You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Randy Terbush <ra...@zyzzyva.com> on 1997/07/27 20:20:21 UTC

[PATCH] loglevels final?

Below is what I feel makes the most sense toward implementing 
logging verbosity control.

Reasoning:
Much of what gets logged as errors by Apache is information that 
seems to generate more questions by users of a server hosting 
service than enlightenment of problems. It would be nice to have 
features such as these that allows tuning of the level of verbosity.

Features:
These changes enable syslog() logging of errors through another 
parameter to the ErrorLog directive.

ErrorLog syslog   # enables logging to syslog via LOCAL7 facility 
ErrorLog syslog:daemon  # allows setting of any other valid facility

Default logging level can be selected with the directive LogLevel.
LogLevel accepts a single parameter, one of:
   emerg, alert, crit, error, warn, notice, info, debug.

These levels mirror the syslog counterparts. 

After struggling to find a level/mask solution that would work, I 
have reverted back to the single hierarchy that I originally 
submitted. The reasons being that I think this part of the server 
needs to stay relatively simple. It also becomes tricky to convert 
to sane values for priority in syslog. My keeping levels in sync 
with syslog standards, it makes it much easier to integrate Apache 
error logging into existing system monitoring. As pointed out by 
others, if you need to filter the log output, grep works just fine.

Lastly, I have tried to maintain the existing output format for 
errors logged, but I would also like to lobby for a revamping of 
error_log format to something that a) makes it easier to filter 
certain levels of logging priority, and b) makes the errors logged 
more consistent looking.

Perhaps something like:

[time] [level] errormessage

At higher verbosity levels:

[time] [level] errno: strerror(): routine: errormessage

And in request context:

[time] [level] host: request: errormessage


This patch only adds one example use of aplog_error() in 
http_core.c and converts existing logging routines to wrappers for 
aplog_error(). Converting existing use of log_* would be the next 
phase of this change.


Index: http_core.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_core.c,v
retrieving revision 1.100
diff -u -3 -r1.100 http_core.c
--- http_core.c	1997/07/24 04:38:09	1.100
+++ http_core.c	1997/07/27 18:17:30
@@ -107,6 +107,8 @@
     conf->limit_nproc = NULL;
 #endif
 
+    conf->loglevel = DEFAULT_LOGLEVEL;
+    
     conf->sec = make_array (a, 2, sizeof(void *));
 
     return (void *)conf;
@@ -1196,6 +1198,35 @@
     return NULL;
 }
 
+const char *set_loglevel (cmd_parms *cmd, core_dir_config *conf, const char *arg) 
+{
+   char *str;
+    
+   if ((str = getword_conf(cmd->pool, &arg))) {
+       if (!strcasecmp(str, "emerg"))
+	   conf->loglevel = APLOG_EMERG;
+       else if (!strcasecmp(str, "alert"))
+	   conf->loglevel = APLOG_ALERT;
+       else if (!strcasecmp(str, "crit"))
+	   conf->loglevel = APLOG_CRIT;
+       else if (!strcasecmp(str, "error"))
+	   conf->loglevel = APLOG_ERR;
+       else if (!strcasecmp(str, "warn"))
+	   conf->loglevel = APLOG_WARNING;
+       else if (!strcasecmp(str, "notice"))
+	   conf->loglevel = APLOG_NOTICE;
+       else if (!strcasecmp(str, "info"))
+	   conf->loglevel = APLOG_INFO;
+       else if (!strcasecmp(str, "debug"))
+	   conf->loglevel = APLOG_DEBUG;
+   }
+   else
+       return "LogLevel requires level keyword";
+   
+   return NULL;
+}
+    
+
 /* Note --- ErrorDocument will now work from .htaccess files.  
  * The AllowOverride of Fileinfo allows webmasters to turn it off
  */
@@ -1320,6 +1351,7 @@
 { "ThreadsPerChild", set_threads, NULL, RSRC_CONF, TAKE1, "Number of threads a child creates" },
 { "ExcessRequestsPerChild", set_excess_requests, NULL, RSRC_CONF, TAKE1, "Maximum number of requests a particular child serves after it is ready to die." },
 { "ListenBacklog", set_listenbacklog, NULL, RSRC_CONF, TAKE1, "maximum length of the queue of pending connections, as used by listen(2)" },
+{ "LogLevel", set_loglevel, (void*)XtOffsetOf(core_dir_config, loglevel), OR_ALL, TAKE1, "set level of verbosity in error logging" },
 { NULL },
 };
 
@@ -1386,9 +1418,9 @@
     if (r->method_number == M_PUT) return METHOD_NOT_ALLOWED;
 
     if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) {
-	log_reason("File does not exist",
-	    r->path_info ? pstrcat(r->pool, r->filename, r->path_info, NULL)
-		: r->filename, r);
+	aplog_error(APLOG_INFO, r, NULL,
+		    r->path_info ? pstrcat(r->pool, r->filename, r->path_info, NULL)
+		    : r->filename, "File does not exist");
 	return NOT_FOUND;
     }
     if (r->method_number != M_GET) return METHOD_NOT_ALLOWED;
Index: http_core.h
===================================================================
RCS file: /export/home/cvs/apache/src/http_core.h,v
retrieving revision 1.24
diff -u -3 -r1.24 http_core.h
--- http_core.h	1997/07/16 00:41:21	1.24
+++ http_core.h	1997/07/27 18:17:32
@@ -179,6 +179,9 @@
     struct rlimit *limit_nproc;
 #endif
 
+    /* logging options */
+    int loglevel;
+    
     /* Access control */
     array_header *sec;
     regex_t *r;
Index: http_log.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_log.c,v
retrieving revision 1.21
diff -u -3 -r1.21 http_log.c
--- http_log.c	1997/07/21 05:53:43	1.21
+++ http_log.c	1997/07/27 18:17:34
@@ -58,12 +58,15 @@
  */
 
 
+
+#define CORE_PRIVATE
 #include "httpd.h"
 #include "http_config.h"
 #include "http_core.h"
 #include "http_log.h"
 
 #include <stdarg.h>
+#include <syslog.h>
 
 static int
 error_log_child (void *cmd)
@@ -92,29 +95,47 @@
     return(child_pid);
 }
 
-void open_error_log(server_rec *s, pool *p)
+void open_error_log (server_rec *s, pool *p)
 {
     char *fname;
-  
-    fname = server_root_relative (p, s->error_fname);
+    register CODE *c;
+    
 
     if (*s->error_fname == '|') {
-      FILE *dummy;
+	FILE *dummy;
 
-      if (!spawn_child (p, error_log_child, (void *)(s->error_fname+1),
-                    kill_after_timeout, &dummy, NULL)) {
-	perror ("spawn_child");
-	fprintf (stderr, "Couldn't fork child for ErrorLog process\n");
-	exit (1);
-      }
+	if (!spawn_child (p, error_log_child, (void *)(s->error_fname+1),
+			  kill_after_timeout, &dummy, NULL)) {
+	    perror ("spawn_child");
+	    fprintf (stderr, "Couldn't fork child for ErrorLog process\n");
+	    exit (1);
+	}
 
-      s->error_log = dummy;
-    } else {
+	s->error_log = dummy;
+    }
+    else if (!strncasecmp(s->error_fname, "syslog", 6)) {
+	if ((fname = strchr(s->error_fname, ':'))) {
+	    fname++;
+	    for (c = facilitynames; c->c_name; c++) {
+		if (!strcasecmp(fname, c->c_name)) {
+		    openlog("httpd", LOG_NDELAY|LOG_CONS|LOG_PID, c->c_val);
+		    s->error_log = NULL;
+		    return;
+		}
+	    }
+	}
+	else
+	    openlog("httpd", LOG_NDELAY|LOG_CONS|LOG_PID, LOG_LOCAL7);
+
+	s->error_log = NULL;
+    }
+    else {
+	fname = server_root_relative (p, s->error_fname);
         if(!(s->error_log = pfopen(p, fname, "a"))) {
             perror("fopen");
             fprintf(stderr,"httpd: could not open error log file %s.\n", fname);
             exit(1);
-      }
+	}
     }
 }
 
@@ -139,12 +160,90 @@
     }
 }
 
-API_EXPORT(void) error_log2stderr(server_rec *s) {
+API_EXPORT(void) error_log2stderr (server_rec *s) {
     if(fileno(s->error_log) != STDERR_FILENO)
         dup2(fileno(s->error_log),STDERR_FILENO);
 }
 
-void log_pid(pool *p, char *pid_fname) {
+API_EXPORT(void) aplog_error (int level, const request_rec *r, const char *routine,
+			      const char *file, const char *fmt, ...)
+{
+    core_dir_config *conf;
+    va_list args;
+    const char *timestamp = NULL;
+    char errstr[MAX_STRING_LEN];
+    
+
+    if (r != NULL) { /* backward compatibilty for historic loging functions */
+	conf = get_module_config(r->per_dir_config, &core_module);
+
+	if (level > conf->loglevel)
+	    return;
+    }
+
+    /* NULL if we are logging to syslog */
+    if (r->server->error_log) timestamp = get_time();
+
+    switch (level) {
+    case APLOG_EMERG:
+    case APLOG_DEBUG:
+    case APLOG_CRIT:
+    case APLOG_ALERT:
+	/* these levels provide the same logging format as log_unixerr() did */
+	if (file != NULL)
+	    if (timestamp)
+		ap_snprintf(errstr, sizeof(errstr), "[%s] %s: %s: %s",
+			    timestamp, routine, file, strerror(errno));
+	    else
+		ap_snprintf(errstr, sizeof(errstr), "%s: %s: %s",
+			    routine, file, strerror(errno));
+		
+	else
+	    if (timestamp)
+		ap_snprintf(errstr, sizeof(errstr), "[%s] %s: %s",
+			    timestamp, routine, strerror(errno));
+	    else
+		ap_snprintf(errstr, sizeof(errstr), "%s: %s",
+			    routine, strerror(errno));
+	break;
+    case APLOG_INFO:
+	/* this level provides same logging format as log_reason() did */
+	if (timestamp)
+	    ap_snprintf(errstr, sizeof(errstr),
+			"[%s] access to %s failed for %s, reason: ", timestamp, file,
+			get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME));
+	else
+	    ap_snprintf(errstr, sizeof(errstr),
+			"access to %s failed for %s, reason: ", file,
+			get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME));
+	break;
+    case APLOG_ERR:
+    case APLOG_WARNING:
+    case APLOG_NOTICE:
+	/* these levels provide same logging format as log_error() did */
+	if (timestamp)
+	    ap_snprintf(errstr, sizeof(errstr), "[%s]", timestamp);
+	break;
+    }
+    
+    va_start(args, fmt);
+
+    if (timestamp) { /* timestamp means we are logging to file */
+	fprintf(r->server->error_log, "%s", errstr);
+	vfprintf(r->server->error_log, fmt, args);
+	fflush(r->server->error_log);
+    }
+    else {
+	if (errstr)
+	    syslog(level, "%s", errstr);
+
+	vsyslog(level, fmt, args);
+    }
+    
+    va_end(args);
+}
+
+void log_pid (pool *p, char *pid_fname) {
     FILE *pid_file;
 
     if (!pid_fname) return;
@@ -158,50 +257,29 @@
     fclose(pid_file);
 }
 
-API_EXPORT(void) log_error(const char *err, server_rec *s) {
-    fprintf(s->error_log, "[%s] %s\n",get_time(),err);
-    fflush(s->error_log);
+API_EXPORT(void) log_error (const char *err, server_rec *s)
+{
+    aplog_error(APLOG_ERR, NULL, NULL, NULL, "%s\n", err);
 }
 
-API_EXPORT(void) log_unixerr(const char *routine, const char *file,
-			     const char *msg, server_rec *s)
+API_EXPORT(void) log_unixerr (const char *routine, const char *file,
+			      const char *msg, server_rec *s)
 {
-    const char *p, *q;
-    FILE *err=s ? s->error_log : stderr;
-
-    p = strerror(errno);
-    q = get_time();
-
-    if (file != NULL)
-	fprintf(err, "[%s] %s: %s: %s\n", q, routine, file, p);
-    else
-	fprintf(err, "[%s] %s: %s\n", q, routine, p);
-    if (msg != NULL) fprintf(s->error_log, "[%s] - %s\n", q, msg);
-
-    fflush(err);
+    aplog_error(APLOG_CRIT, NULL, routine, file, msg);
 }
 
-API_EXPORT(void) log_printf(const server_rec *s, const char *fmt, ...)
+API_EXPORT(void) log_printf (const server_rec *s, const char *fmt, ...)
 {
     va_list args;
     
-    fprintf(s->error_log, "[%s] ", get_time());
     va_start (args, fmt);
-    vfprintf (s->error_log, fmt, args);
+    aplog_error(APLOG_ERR, NULL, NULL, NULL, fmt, args);
     va_end (args);
-
-    fputc('\n', s->error_log);
-    fflush(s->error_log);
 }
 
-API_EXPORT(void) log_reason(const char *reason, const char *file, request_rec *r) 
+API_EXPORT(void) log_reason (const char *reason, const char *file, request_rec *r) 
 {
-    fprintf (r->server->error_log,
-	     "[%s] access to %s failed for %s, reason: %s\n",
-	     get_time(), file,
-	     get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME),
-	     reason);
-    fflush (r->server->error_log);
+    aplog_error(APLOG_INFO, r, NULL, file, reason);
 }
 
 API_EXPORT(void) log_assert(const char *szExp, const char *szFile, int nLine)
Index: http_log.h
===================================================================
RCS file: /export/home/cvs/apache/src/http_log.h,v
retrieving revision 1.10
diff -u -3 -r1.10 http_log.h
--- http_log.h	1997/07/21 05:53:43	1.10
+++ http_log.h	1997/07/27 18:17:34
@@ -50,7 +50,21 @@
  *
  */
 
+#define SYSLOG_NAMES
+#define	APLOG_EMERG	0	/* system is unusable */
+#define	APLOG_ALERT	1	/* action must be taken immediately */
+#define	APLOG_CRIT	2	/* critical conditions */
+#define	APLOG_ERR	3	/* error conditions */
+#define	APLOG_WARNING	4	/* warning conditions */
+#define	APLOG_NOTICE	5	/* normal but significant condition */
+#define	APLOG_INFO	6	/* informational */
+#define	APLOG_DEBUG	7	/* debug-level messages */
+#define DEFAULT_LOGLEVEL	APLOG_ERR
+
+
 void open_logs (server_rec *, pool *p);
+API_EXPORT(void) aplog_error(int level, const request_rec *r, const char *routine,
+			     const char *file, const char *fmt, ...);
 API_EXPORT(void) error_log2stderr (server_rec *);     
 
 void log_pid (pool *p, char *fname);
@@ -60,4 +74,5 @@
 API_EXPORT(void) log_printf(const server_rec *s, const char *fmt, ...);
 API_EXPORT(void) log_reason(const char *reason, const char *fname,
 			    request_rec *r);
+
 



Re: [PATCH] loglevels final?

Posted by Dean Gaudet <dg...@arctic.org>.
While I'm much happier with this approach (I too want it to be simple, and
syslog-style levels are just fine with me) you didn't address one of my
earlier complaints. 

On Sun, 27 Jul 1997, Randy Terbush wrote:

> -void log_pid(pool *p, char *pid_fname) {
> +API_EXPORT(void) aplog_error (int level, const request_rec *r, const char *routine,
> +			      const char *file, const char *fmt, ...)
> +{

I think that the prototype should be: 

API_EXPORT(void) aplog_error (int level, const request_rec *r,
    const char *fmt, ...);

one of the reasons is this code: 

> +    if (timestamp) { /* timestamp means we are logging to file */
> +	fprintf(r->server->error_log, "%s", errstr);
> +	vfprintf(r->server->error_log, fmt, args);
> +	fflush(r->server->error_log);
> +    }
> +    else {
> +	if (errstr)
> +	    syslog(level, "%s", errstr);
> +
> +	vsyslog(level, fmt, args);
> +    }

Is not atomic for the syslog. 

I also feel that "routine" and "file" are very vague, and don't apply to
all situations.

BTW you should probably also implement:

API_EXPORT(void) aplog_verror (int level, const request_rec *r,
    va_list args); 

Dean