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;
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;
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;
%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
| factors
| metric
| composites
+ | logging
;
tempdir :
}
;
+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
switch (signo) {
case SIGHUP:
do_restart = 1;
+ do_reopen_log = 1;
break;
case SIGINT:
case SIGTERM:
do_restart = 0;
child_dead = 0;
child_ready = 0;
+ do_reopen_log = 0;
active_worker = NULL;
bzero (rspamd->cfg, sizeof (struct config_file));
}
}
+ 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);
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
/*
#include <unistd.h>
#include <stdarg.h>
#include <sys/file.h>
+#include <syslog.h>
+#include <glib.h>
#include "config.h"
#ifdef HAVE_LIBUTIL_H
#include "util.h"
#include "cfg_file.h"
+sig_atomic_t do_reopen_log = 0;
+
int
event_make_socket_nonblocking (int fd)
{
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
*/
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
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;