]> source.dussan.org Git - rspamd.git/commitdiff
* Add main logging functions (log to file, syslog and console)
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Sun, 26 Oct 2008 03:53:05 +0000 (06:53 +0300)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Sun, 26 Oct 2008 03:53:05 +0000 (06:53 +0300)
* Handle log reopening

cfg_file.h
cfg_file.l
cfg_file.y
main.c
main.h
util.c
util.h
worker.c

index d664a15f0d4fb48f7e6e34f209e292ae2daf44f3..1eb71476de0f55708eaed25bcf59b4848c451603 100644 (file)
@@ -60,6 +60,12 @@ enum rspamd_regexp_type {
        REGEXP_URL,
 };
 
+enum rspamd_log_type {
+       RSPAMD_LOG_CONSOLE,
+       RSPAMD_LOG_SYSLOG,
+       RSPAMD_LOG_FILE,
+};
+
 struct rspamd_regexp {
        enum rspamd_regexp_type type;
        char *regexp_text;
@@ -107,6 +113,12 @@ struct config_file {
        int no_fork;
        unsigned int workers_number;
 
+       enum rspamd_log_type log_type;
+       int log_facility;
+       int log_level;
+       char *log_file;
+       int log_fd;
+
        struct memcached_server memcached_servers[MAX_MEMCACHED_SERVERS];
        size_t memcached_servers_num;
        memc_proto_t memcached_protocol;        
index e52f2585b6d221fcec043ff3513137c1e2dd08ef..fefd112374d731ec7e220c279eb1d6801583804e 100644 (file)
@@ -49,6 +49,20 @@ required_score                                       return REQUIRED_SCORE;
 function                                               return FUNCTION;
 control                                                        return CONTROL;
 password                                               return PASSWORD;
+logging                                                        return LOGGING;
+
+log_type                                               return LOG_TYPE;
+console                                                        return LOG_TYPE_CONSOLE;
+syslog                                                 return LOG_TYPE_SYSLOG;
+file                                                   return LOG_TYPE_FILE;
+
+log_level                                              return LOG_LEVEL;
+DEBUG                                                  return LOG_LEVEL_DEBUG;
+INFO                                                   return LOG_LEVEL_INFO;
+WARNING                                                        return LOG_LEVEL_WARNING;
+ERROR                                                  return LOG_LEVEL_ERROR;
+log_facility                                   return LOG_FACILITY;
+log_file                                               return LOG_FILENAME;
 
 \{                                                             return OBRACE;
 \}                                                             return EBRACE;
index 1ccb928b75cc08b8515aa1ee4f421e0789fd8425..1838c0f6ea38cccfd92df3a2a1ef3da38b6b2d2d 100644 (file)
@@ -50,6 +50,8 @@ struct metric *cur_metric = NULL;
 %token  MODULE_OPT PARAM VARIABLE
 %token  HEADER_FILTERS MIME_FILTERS MESSAGE_FILTERS URL_FILTERS FACTORS METRIC NAME
 %token  REQUIRED_SCORE FUNCTION FRACT COMPOSITES CONTROL PASSWORD
+%token  LOGGING LOG_TYPE LOG_TYPE_CONSOLE LOG_TYPE_SYSLOG LOG_TYPE_FILE
+%token  LOG_LEVEL LOG_LEVEL_DEBUG LOG_LEVEL_INFO LOG_LEVEL_WARNING LOG_LEVEL_ERROR LOG_FACILITY LOG_FILENAME
 
 %type  <string>        STRING
 %type  <string>        VARIABLE
@@ -88,6 +90,7 @@ command       :
        | factors
        | metric
        | composites
+       | logging
        ;
 
 tempdir :
@@ -435,6 +438,110 @@ variable:
        }
        ;
 
+logging:
+       LOGGING OBRACE loggingbody EBRACE
+       ;
+
+loggingbody:
+       loggingcmd SEMICOLON
+       | loggingbody loggingcmd SEMICOLON
+       ;
+
+loggingcmd:
+       loggingtype
+       | logginglevel
+       | loggingfacility
+       | loggingfile
+       ;
+
+loggingtype:
+       LOG_TYPE EQSIGN LOG_TYPE_CONSOLE {
+               cfg->log_type = RSPAMD_LOG_CONSOLE;
+       }
+       LOG_TYPE EQSIGN LOG_TYPE_SYSLOG {
+               cfg->log_type = RSPAMD_LOG_SYSLOG;
+       }
+       LOG_TYPE EQSIGN LOG_TYPE_FILE {
+               cfg->log_type = RSPAMD_LOG_FILE;
+       }
+       ;
+
+logginglevel:
+       LOG_LEVEL EQSIGN LOG_LEVEL_DEBUG {
+               cfg->log_level = G_LOG_LEVEL_DEBUG;
+       }
+       LOG_LEVEL EQSIGN LOG_LEVEL_INFO {
+               cfg->log_level = G_LOG_LEVEL_INFO | G_LOG_LEVEL_MESSAGE;
+       }
+       LOG_LEVEL EQSIGN LOG_LEVEL_WARNING {
+               cfg->log_level = G_LOG_LEVEL_WARNING;
+       }
+       LOG_LEVEL EQSIGN LOG_LEVEL_ERROR {
+               cfg->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
+       }
+       ;
+
+loggingfacility:
+       LOG_FACILITY EQSIGN QUOTEDSTRING {
+               if (strncasecmp ($3, "LOG_AUTH", sizeof ("LOG_AUTH") - 1) == 0) {
+                       cfg->log_facility = LOG_AUTH;
+               }
+               else if (strncasecmp ($3, "LOG_CONSOLE", sizeof ("LOG_CONSOLE") - 1) == 0) {
+                       cfg->log_facility = LOG_CONSOLE;
+               }
+               else if (strncasecmp ($3, "LOG_CRON", sizeof ("LOG_CRON") - 1) == 0) {
+                       cfg->log_facility = LOG_CRON;
+               }
+               else if (strncasecmp ($3, "LOG_DAEMON", sizeof ("LOG_DAEMON") - 1) == 0) {
+                       cfg->log_facility = LOG_DAEMON;
+               }
+               else if (strncasecmp ($3, "LOG_MAIL", sizeof ("LOG_MAIL") - 1) == 0) {
+                       cfg->log_facility = LOG_MAIL;
+               }
+               else if (strncasecmp ($3, "LOG_USER", sizeof ("LOG_USER") - 1) == 0) {
+                       cfg->log_facility = LOG_USER;
+               }
+               else if (strncasecmp ($3, "LOG_LOCAL0", sizeof ("LOG_LOCAL0") - 1) == 0) {
+                       cfg->log_facility = LOG_LOCAL0;
+               }
+               else if (strncasecmp ($3, "LOG_LOCAL1", sizeof ("LOG_LOCAL1") - 1) == 0) {
+                       cfg->log_facility = LOG_LOCAL1;
+               }
+               else if (strncasecmp ($3, "LOG_LOCAL2", sizeof ("LOG_LOCAL2") - 1) == 0) {
+                       cfg->log_facility = LOG_LOCAL2;
+               }
+               else if (strncasecmp ($3, "LOG_LOCAL3", sizeof ("LOG_LOCAL3") - 1) == 0) {
+                       cfg->log_facility = LOG_LOCAL3;
+               }
+               else if (strncasecmp ($3, "LOG_LOCAL4", sizeof ("LOG_LOCAL4") - 1) == 0) {
+                       cfg->log_facility = LOG_LOCAL4;
+               }
+               else if (strncasecmp ($3, "LOG_LOCAL5", sizeof ("LOG_LOCAL5") - 1) == 0) {
+                       cfg->log_facility = LOG_LOCAL5;
+               }
+               else if (strncasecmp ($3, "LOG_LOCAL6", sizeof ("LOG_LOCAL6") - 1) == 0) {
+                       cfg->log_facility = LOG_LOCAL6;
+               }
+               else if (strncasecmp ($3, "LOG_LOCAL7", sizeof ("LOG_LOCAL7") - 1) == 0) {
+                       cfg->log_facility = LOG_LOCAL7;
+               }
+               else {
+                       yyerror ("yyparse: invalid logging facility: %s", $3);
+                       YYERROR;
+               }
+
+               free ($3);
+       }
+       ;
+
+loggingfile:
+       LOG_FILENAME EQSIGN QUOTEDSTRING {
+               cfg->log_file = memory_pool_strdup (cfg->cfg_pool, $3);
+
+               free ($3);
+       }
+       ;
+
 %%
 /* 
  * vi:ts=4 
diff --git a/main.c b/main.c
index a886620852c3b49e9b7573cc5e16863aeab5d9e3..81effd61dd22045d4ab30745907d53f6815d18ee 100644 (file)
--- a/main.c
+++ b/main.c
@@ -48,6 +48,7 @@ void sig_handler (int signo)
        switch (signo) {
                case SIGHUP:
                        do_restart = 1;
+                       do_reopen_log = 1;
                        break;
                case SIGINT:
                case SIGTERM:
@@ -182,6 +183,7 @@ main (int argc, char **argv)
        do_restart = 0;
        child_dead = 0;
        child_ready = 0;
+       do_reopen_log = 0;
        active_worker = NULL;
 
        bzero (rspamd->cfg, sizeof (struct config_file));
@@ -225,6 +227,33 @@ main (int argc, char **argv)
                }
     }
 
+       switch (cfg->log_type) {
+               case RSPAMD_LOG_CONSOLE:
+                       if (!rspamd->cfg->no_fork) {
+                               fprintf (stderr, "Cannot log to console while daemonized, disable logging");
+                               cfg->log_fd = -1;
+                       }
+                       else {
+                               cfg->log_fd = 2;
+                       }
+                       g_log_set_default_handler (file_log_function, cfg);
+                       break;
+               case RSPAMD_LOG_FILE:
+                       if (cfg->log_file == NULL || open_log (cfg) == -1) {
+                               fprintf (stderr, "Fatal error, cannot open logfile, exiting");
+                               exit (EXIT_FAILURE);
+                       }
+                       g_log_set_default_handler (file_log_function, cfg);
+                       break;
+               case RSPAMD_LOG_SYSLOG:
+                       if (open_log (cfg) == -1) {
+                               fprintf (stderr, "Fatal error, cannot open syslog facility, exiting");
+                               exit (EXIT_FAILURE);
+                       }
+                       g_log_set_default_handler (syslog_log_function, cfg);
+                       break;
+       }
+
        if (!rspamd->cfg->no_fork && daemon (1, 1) == -1) {
                fprintf (stderr, "Cannot daemonize\n");
                exit (-errno);
diff --git a/main.h b/main.h
index 3c519463f964d279dcc06c53411d74b6a4bcaeb9..3a4671bfb1669c0ecf5add048e9e7a9e0361740f 100644 (file)
--- a/main.h
+++ b/main.h
@@ -179,6 +179,8 @@ struct c_module {
 void start_worker (struct rspamd_worker *worker, int listen_sock);
 void start_controller (struct rspamd_worker *worker);
 
+extern sig_atomic_t do_reopen_log;
+
 #endif
 
 /* 
diff --git a/util.c b/util.c
index b0d40daf0a4201ac40c2ebf9539c80dd9ff89a1e..90a536359d1a96459c858ee09f037b8f78e30b06 100644 (file)
--- a/util.c
+++ b/util.c
@@ -9,6 +9,8 @@
 #include <unistd.h>
 #include <stdarg.h>
 #include <sys/file.h>
+#include <syslog.h>
+#include <glib.h>
 
 #include "config.h"
 #ifdef HAVE_LIBUTIL_H
@@ -17,6 +19,8 @@
 #include "util.h"
 #include "cfg_file.h"
 
+sig_atomic_t do_reopen_log = 0;
+
 int
 event_make_socket_nonblocking (int fd)
 {
@@ -734,6 +738,97 @@ parse_expression (memory_pool_t *pool, char *line)
        return expr;
 }
 
+/* Logging utility functions */
+int
+open_log (struct config_file *cfg)
+{
+       switch (cfg->log_type) {
+               case RSPAMD_LOG_CONSOLE:
+                       /* Do nothing with console */
+                       return 0;
+               case RSPAMD_LOG_SYSLOG:
+                       openlog ("rspamd", LOG_NDELAY | LOG_PID, cfg->log_facility);
+                       return 0;
+               case RSPAMD_LOG_FILE:
+                       cfg->log_fd = open (cfg->log_file, O_CREAT | O_WRONLY | O_APPEND);
+                       if (cfg->log_fd == -1) {
+                               msg_err ("open_log: cannot open desired log file: %s, %m", cfg->log_file);
+                               return -1;
+                       }
+                       return 0;
+       }
+}
+
+int
+reopen_log (struct config_file *cfg)
+{
+       do_reopen_log = 0;
+       switch (cfg->log_type) {
+               case RSPAMD_LOG_CONSOLE:
+                       /* Do nothing with console */
+                       return 0;
+               case RSPAMD_LOG_SYSLOG:
+                       closelog ();
+                       break;
+               case RSPAMD_LOG_FILE:
+                       close (cfg->log_fd);
+                       break;
+       }
+       return open_log (cfg);
+}
+
+void
+syslog_log_function (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer arg)
+{
+       struct config_file *cfg = (struct config_file *)arg;
+       if (do_reopen_log) {
+               reopen_log (cfg);
+       }
+
+       if (log_level <= cfg->log_level) {
+               if (log_level >= G_LOG_LEVEL_DEBUG) {
+                       syslog (LOG_DEBUG, message);
+               }
+               else if (log_level >= G_LOG_LEVEL_INFO) {
+                       syslog (LOG_INFO, message);
+               }
+               else if (log_level >= G_LOG_LEVEL_WARNING) {
+                       syslog (LOG_WARNING, message);
+               }
+               else if (log_level >= G_LOG_LEVEL_CRITICAL) {
+                       syslog (LOG_ERR, message);
+               }
+       }
+}
+
+void
+file_log_function (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer arg)
+{
+       struct config_file *cfg = (struct config_file *)arg;
+       char tmpbuf[128];
+       int r;
+       struct iovec out[3];
+       
+       if (cfg->log_fd == -1) {
+               return;
+       }
+
+       if (do_reopen_log) {
+               reopen_log (cfg);
+       }
+
+       if (log_level <= cfg->log_level) {
+               r = snprintf (tmpbuf, sizeof (tmpbuf), "#%d: %d rspamd ", (int)getpid (), (int)time (NULL));
+               out[0].iov_base = tmpbuf;
+               out[0].iov_len = r;
+               out[1].iov_base = (char *)message;
+               out[1].iov_len = strlen (message);
+               out[2].iov_base = "\r\n";
+               out[2].iov_len = 2;
+
+               writev (cfg->log_fd, out, sizeof (out) / sizeof (out[0]));
+       }
+}
 /*
  * vi:ts=4
  */
diff --git a/util.h b/util.h
index e88521281e2b9416bf3b333c27b5145ab5c3f37d..1791f463542abb02b58e5958b5a75e2751e017b2 100644 (file)
--- a/util.h
+++ b/util.h
@@ -52,4 +52,9 @@ int pidfile_close(struct pidfh *pfh);
 int pidfile_remove(struct pidfh *pfh);
 #endif
 
+int open_log (struct config_file *cfg);
+int reopen_log (struct config_file *cfg);
+void syslog_log_function (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer arg);
+void file_log_function (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer arg);
+
 #endif
index efa95c10542a8d472878c33c58319b9ec3540d8a..741a351a1f444eb69a9cc21d5831d2d067e5f4a7 100644 (file)
--- a/worker.c
+++ b/worker.c
@@ -59,6 +59,7 @@ sigusr_handler (int fd, short what, void *arg)
        tv.tv_usec = 0;
        event_del (&worker->sig_ev);
        event_del (&worker->bind_ev);
+       do_reopen_log = 1;
        msg_info ("worker's shutdown is pending in %d sec", SOFT_SHUTDOWN_TIME);
        event_loopexit (&tv);
        return;