Added %err_code and %err_detail logformat codes to record details about
transaction failures. For example, when Squid responds with 500 Internal
Server Error, it is often useful to know what went wrong.

=== modified file 'src/HttpRequest.cc'
--- src/HttpRequest.cc	2009-04-28 23:00:49 +0000
+++ src/HttpRequest.cc	2010-06-29 22:22:34 +0000
@@ -89,6 +89,7 @@
     body_pipe = NULL;
     // hier
     errType = ERR_NONE;
+    errDetail = ERR_DETAIL_NONE;
     peer_login = NULL;		// not allocated/deallocated by this class
     peer_domain = NULL;		// not allocated/deallocated by this class
     vary_headers = NULL;

=== modified file 'src/HttpRequest.h'
--- src/HttpRequest.h	2009-04-28 23:00:49 +0000
+++ src/HttpRequest.h	2010-06-29 19:36:35 +0000
@@ -117,6 +117,7 @@
     HierarchyLogEntry hier;
 
     err_type errType;
+    int errDetail; ///< errType-specific detail about the transaction error
 
     char *peer_login;		/* Configured peer login:password */
 

=== modified file 'src/Server.cc'
--- src/Server.cc	2009-04-28 23:00:49 +0000
+++ src/Server.cc	2010-06-29 22:28:50 +0000
@@ -630,10 +630,14 @@
         debugs(11,9, HERE << "creating ICAP error entry after ICAP failure");
         ErrorState *err =
             errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, request);
-        err->xerrno = errno;
+        err->xerrno = ERR_DETAIL_ICAP_RESPMOD_EARLY;
         fwd->fail(err);
         fwd->dontRetry(true);
     }
+    else if (request) { // update logged info
+        request->errType = ERR_ICAP_FAILURE;
+        request->errDetail = ERR_DETAIL_ICAP_RESPMOD_LATE;
+    }
 
     abortTransaction("ICAP failure");
 }
@@ -660,7 +664,7 @@
         // handle start failure for an essential ICAP service
         ErrorState *err = errorCon(ERR_ICAP_FAILURE,
             HTTP_INTERNAL_SERVER_ERROR, originalRequest());
-        err->xerrno = errno;
+        err->xerrno = ERR_DETAIL_ICAP_RESPMOD_START;
         errorAppendEntry(entry, err);
         abortTransaction("ICAP start failure");
         return;

=== modified file 'src/access_log.cc'
--- src/access_log.cc	2010-05-13 04:20:47 +0000
+++ src/access_log.cc	2010-06-29 21:58:23 +0000
@@ -41,6 +41,7 @@
 #include "Store.h"
 
 #include "ACLChecklist.h"
+#include "errorpage.h"
 
 #include "HttpReply.h"
 #include "HttpRequest.h"
@@ -367,7 +368,8 @@
     /*LFT_HTTP_STATUS, */
 
     LFT_SQUID_STATUS,
-    /*LFT_SQUID_ERROR, */
+    LFT_SQUID_ERROR,
+    LFT_SQUID_ERROR_DETAIL,
     LFT_SQUID_HIERARCHY,
 
     LFT_MIME_TYPE,
@@ -520,7 +522,8 @@
         /*{ "Ht", LFT_HTTP_STATUS }, */
 
         {"Ss", LFT_SQUID_STATUS},
-        /*{ "Se", LFT_SQUID_ERROR }, */
+        {"err_code", LFT_SQUID_ERROR },
+        {"err_detail", LFT_SQUID_ERROR_DETAIL },
         {"Sh", LFT_SQUID_HIERARCHY},
 
         {"mt", LFT_MIME_TYPE},
@@ -991,7 +994,17 @@
 
             break;
 
-            /* case LFT_SQUID_ERROR: */
+        case LFT_SQUID_ERROR:
+            if (al->request && al->request->errType != ERR_NONE)
+                out = errorPageName(al->request->errType);
+            break;
+
+        case LFT_SQUID_ERROR_DETAIL:
+            if (al->request && al->request->errDetail >= 0) {
+                outint = al->request->errDetail;
+                doint = 1;
+            }
+            break;
 
         case LFT_SQUID_HIERARCHY:
             if (al->hier.ping.timedout)

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2010-05-13 04:20:47 +0000
+++ src/cf.data.pre	2010-06-29 23:19:12 +0000
@@ -2042,6 +2042,9 @@
 			starts with the first connect request (or write I/O)
 			sent to the first selected peer. The timer stops
 			with the last I/O with the last peer.
+		err_code    The ID of an error response served by Squid or
+		            a similar internal error identifier.
+		err_detail  Additional err_code-dependent error information.
 		%	a literal % character
 
 	If ICAP is enabled, the following two codes become available (as

=== modified file 'src/client_side_request.cc'
--- src/client_side_request.cc	2009-04-28 23:00:49 +0000
+++ src/client_side_request.cc	2010-06-29 22:28:50 +0000
@@ -1258,6 +1258,9 @@
         (c != NULL && c->auth_user_request ?
             c->auth_user_request : request->auth_user_request));
 
+    if (request->errDetail < 0)
+        request->errDetail = ERR_DETAIL_ICAP_REQMOD;
+
     node = (clientStreamNode *)client_stream.tail->data;
     clientStreamRead(node, this, node->readBuffer);
 }

=== modified file 'src/enums.h'
--- src/enums.h	2009-04-28 23:00:49 +0000
+++ src/enums.h	2010-06-29 22:32:39 +0000
@@ -100,6 +100,16 @@
     ERR_MAX
 } err_type;
 
+typedef enum {
+    ERR_DETAIL_NONE = -1,
+    ERR_DETAIL_START = 100000, // to avoid clashes with most OS error numbers
+    ERR_DETAIL_ICAP_REQMOD, // ICAP REQMOD failure
+    ERR_DETAIL_ICAP_RESPMOD_START, // ICAP RESPMOD failed to start
+    ERR_DETAIL_ICAP_RESPMOD_EARLY, // ICAP RESPMOD failed w/o store entry
+    ERR_DETAIL_ICAP_RESPMOD_LATE,  // ICAP RESPMOD failed with a store entry
+    ERR_DETAIL_MAX
+} err_detail_type;
+
 enum fd_type {
     FD_NONE,
     FD_LOG,

=== modified file 'src/errorpage.cc'
--- src/errorpage.cc	2008-07-12 12:24:42 +0000
+++ src/errorpage.cc	2010-06-29 21:04:24 +0000
@@ -303,7 +303,7 @@
     return (err_type)id;
 }
 
-static const char *
+const char *
 errorPageName(int pageId)
 {
     if (pageId >= ERR_NONE && pageId < ERR_MAX)		/* common case */
@@ -331,6 +331,7 @@
     if (request != NULL) {
         err->request = HTTPMSGLOCK(request);
         err->src_addr = request->client_addr;
+        request->errType = type;
     }
 
     return err;

=== modified file 'src/errorpage.h'
--- src/errorpage.h	2007-05-09 13:45:58 +0000
+++ src/errorpage.h	2010-06-29 21:05:17 +0000
@@ -92,6 +92,7 @@
 SQUIDCEXTERN void errorStateFree(ErrorState * err);
 SQUIDCEXTERN err_type errorReservePageId(const char *page_name);
 SQUIDCEXTERN ErrorState *errorCon(err_type type, http_status, HttpRequest * request);
+SQUIDCEXTERN const char *errorPageName(int pageId); ///< error ID to string
 
 
 #endif /* SQUID_ERRORPAGE_H */

=== modified file 'src/forward.cc'
--- src/forward.cc	2010-05-13 04:24:52 +0000
+++ src/forward.cc	2010-06-29 19:45:29 +0000
@@ -296,6 +296,10 @@
 
     if (!errorState->request)
         errorState->request = HTTPMSGLOCK(request);
+
+    request->errType = errorState->type;
+    if (request->errDetail < 0)
+        request->errDetail = errorState->xerrno;
 }
 
 /*

=== modified file 'src/ftp.cc'
--- src/ftp.cc	2009-02-08 09:47:46 +0000
+++ src/ftp.cc	2010-06-29 22:01:28 +0000
@@ -3135,6 +3135,9 @@
         http_code = HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    if (ftpState->request)
+        ftpState->request->errDetail = code;
+
     err = errorCon(err_code, http_code, ftpState->request);
 
     if (ftpState->old_request)


