]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Rework] Start logger rework
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 10 Feb 2020 14:43:31 +0000 (14:43 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 10 Feb 2020 21:12:13 +0000 (21:12 +0000)
src/libutil/CMakeLists.txt
src/libutil/logger.c
src/libutil/logger.h
src/libutil/logger_file.c [new file with mode: 0644]
src/libutil/logger_private.h [new file with mode: 0644]

index 290841373ce479d142ab20900fd0c5d5f23d7898..6cd5df8a06f67e39e191cd77414b5c5207362b64 100644 (file)
@@ -11,6 +11,7 @@ SET(LIBRSPAMDUTILSRC
                                ${CMAKE_CURRENT_SOURCE_DIR}/http_router.c
                                ${CMAKE_CURRENT_SOURCE_DIR}/http_context.c
                                ${CMAKE_CURRENT_SOURCE_DIR}/logger.c
+                               ${CMAKE_CURRENT_SOURCE_DIR}/logger_file.c
                                ${CMAKE_CURRENT_SOURCE_DIR}/map.c
                                ${CMAKE_CURRENT_SOURCE_DIR}/map_helpers.c
                                ${CMAKE_CURRENT_SOURCE_DIR}/mem_pool.c
index cb1e392092a6aecfed48a5f5b0581d1000bdc42d..1f586b1112767bb7ba911d5ed5354911e65534d1 100644 (file)
 #include "map_helpers.h"
 #include "ottery.h"
 #include "unix-std.h"
+#include "logger_private.h"
 
 #ifdef HAVE_SYSLOG_H
 #include <syslog.h>
 #endif
 
-/* How much message should be repeated before it is count to be repeated one */
-#define REPEATS_MIN 3
-#define REPEATS_MAX 300
-#define LOG_ID 6
-#define LOGBUF_LEN 8192
-
-struct rspamd_log_module {
-       gchar *mname;
-       guint id;
-};
-
-struct rspamd_log_modules {
-       guchar *bitset;
-       guint bitset_len; /* Number of BITS used in bitset */
-       guint bitset_allocated; /* Size of bitset allocated in BYTES */
-       GHashTable *modules;
-};
-
-struct rspamd_logger_error_elt {
-       gint completed;
-       GQuark ptype;
-       pid_t pid;
-       gdouble ts;
-       gchar id[LOG_ID + 1];
-       gchar module[9];
-       gchar message[];
-};
-
-struct rspamd_logger_error_log {
-       struct rspamd_logger_error_elt *elts;
-       rspamd_mempool_t *pool;
-       guint32 max_elts;
-       guint32 elt_len;
-       /* Avoid false cache sharing */
-       guchar __padding[64 - sizeof(gpointer) * 2 - sizeof(guint64)];
-       guint cur_row;
-};
-
-/**
- * Static structure that store logging parameters
- * It is NOT shared between processes and is created by main process
- */
-struct rspamd_logger_s {
-       rspamd_log_func_t log_func;
-       gpointer log_arg;
-       enum rspamd_log_type log_type;
-       gint log_facility;
-       gint log_level;
-       gchar *log_file;
-       gboolean log_buffered;
-       gboolean log_silent_workers;
-       guint32 log_buf_size;
-
-       struct rspamd_logger_error_log *errlog;
-       struct rspamd_cryptobox_pubkey *pk;
-       struct rspamd_cryptobox_keypair *keypair;
-       struct {
-               guint32 size;
-               guint32 used;
-               u_char *buf;
-       } io_buf;
-       gint fd;
-       guint flags;
-       gboolean is_buffered;
-       gboolean enabled;
-       gboolean is_debug;
-       gboolean throttling;
-       gboolean no_lock;
-       gboolean opened;
-       time_t throttling_time;
-       enum rspamd_log_type type;
-       pid_t pid;
-       guint32 repeats;
-       GQuark process_type;
-       struct rspamd_radix_map_helper *debug_ip;
-       guint64 last_line_cksum;
-       gchar *saved_message;
-       gsize saved_mlen;
-       gchar *saved_function;
-       gchar *saved_module;
-       gchar *saved_id;
-       rspamd_mempool_mutex_t *mtx;
-       guint saved_loglevel;
-       guint64 log_cnt[4];
-};
-
-static const gchar lf_chr = '\n';
 
 static rspamd_logger_t *default_logger = NULL;
 static struct rspamd_log_modules *log_modules = NULL;
 
-static void syslog_log_function (const gchar *module,
-                                                                const gchar *id, const gchar *function,
-                                                                gint log_level, const gchar *message, gsize mlen,
-                                                                rspamd_logger_t *logger,
-                                                                gpointer arg);
-
-static void file_log_function (const gchar *module,
-                                                          const gchar *id, const gchar *function,
-                                                          gint log_level, const gchar *message, gsize mlen,
-                                                          rspamd_logger_t *logger,
-                                                          gpointer arg);
-
 guint rspamd_task_log_id = (guint)-1;
 RSPAMD_CONSTRUCTOR(rspamd_task_log_init)
 {
        rspamd_task_log_id = rspamd_logger_add_debug_module("task");
 }
 
-/**
- * Calculate checksum for log line (used for repeating logic)
- */
-static inline guint64
-rspamd_log_calculate_cksum (const gchar *message, size_t mlen)
-{
-       return rspamd_cryptobox_fast_hash (message, mlen, rspamd_hash_seed ());
-}
-
-/*
- * Write a line to log file (unbuffered)
- */
-static void
-direct_write_log_line (rspamd_logger_t *rspamd_log,
-               void *data,
-               gsize count,
-               gboolean is_iov,
-               gint level_flags)
-{
-       gchar errmsg[128];
-       struct iovec *iov;
-       const gchar *line;
-       glong r;
-       gint fd;
-       gboolean locked = FALSE;
-
-       iov = (struct iovec *) data;
-
-       if (rspamd_log->type == RSPAMD_LOG_CONSOLE) {
-
-               if (rspamd_log->flags & RSPAMD_LOG_FLAG_RSPAMADM) {
-                       fd = STDOUT_FILENO;
-
-                       if (level_flags & G_LOG_LEVEL_CRITICAL) {
-                               fd = STDERR_FILENO;
-                       }
-               }
-               else {
-                       fd = rspamd_log->fd;
-               }
-       }
-       else {
-               fd = rspamd_log->fd;
-       }
-
-       if (!rspamd_log->no_lock) {
-               gsize tlen;
-
-               if (is_iov) {
-                       tlen = 0;
-
-                       for (guint i = 0; i < count; i ++) {
-                               tlen += iov[i].iov_len;
-                       }
-               }
-               else {
-                       tlen = count;
-               }
-
-               if (tlen > PIPE_BUF || rspamd_log->flags & RSPAMD_LOG_FLAG_TTY) {
-                       locked = TRUE;
-
-#ifndef DISABLE_PTHREAD_MUTEX
-                       if (rspamd_log->mtx) {
-                               rspamd_mempool_lock_mutex (rspamd_log->mtx);
-                       }
-                       else {
-                               rspamd_file_lock (fd, FALSE);
-                       }
-#else
-                       rspamd_file_lock (fd, FALSE);
-#endif
-               }
-       }
-
-       if (is_iov) {
-               r = writev (fd, iov, count);
-       }
-       else {
-               line = (const gchar *) data;
-               r = write (fd, line, count);
-       }
-
-       if (locked) {
-#ifndef DISABLE_PTHREAD_MUTEX
-               if (rspamd_log->mtx) {
-                       rspamd_mempool_unlock_mutex (rspamd_log->mtx);
-               }
-               else {
-                       rspamd_file_unlock (fd, FALSE);
-               }
-#else
-               rspamd_file_unlock (fd, FALSE);
-#endif
-       }
-
-       if (r == -1) {
-               /* We cannot write message to file, so we need to detect error and make decision */
-               if (errno == EINTR) {
-                       /* Try again */
-                       direct_write_log_line (rspamd_log, data, count, is_iov, level_flags);
-                       return;
-               }
-
-               r = rspamd_snprintf (errmsg,
-                               sizeof (errmsg),
-                               "direct_write_log_line: cannot write log line: %s",
-                               strerror (errno));
-               if (errno == EFAULT || errno == EINVAL || errno == EFBIG ||
-                               errno == ENOSPC) {
-                       /* Rare case */
-                       rspamd_log->throttling = TRUE;
-                       rspamd_log->throttling_time = time (NULL);
-               }
-               else if (errno == EPIPE || errno == EBADF) {
-                       /* We write to some pipe and it disappears, disable logging or we has opened bad file descriptor */
-                       rspamd_log->enabled = FALSE;
-               }
-       }
-       else if (rspamd_log->throttling) {
-               rspamd_log->throttling = FALSE;
-       }
-}
-
-static void
-rspamd_escape_log_string (gchar *str)
-{
-       guchar *p = (guchar *) str;
-
-       while (*p) {
-               if ((*p & 0x80) || !g_ascii_isprint (*p)) {
-                       *p = '?';
-               }
-               else if (*p == '\n' || *p == '\r') {
-                       *p = ' ';
-               }
-               p++;
-       }
-}
-
-gint
-rspamd_try_open_log_fd (rspamd_logger_t *rspamd_log, uid_t uid, gid_t gid)
-{
-       gint fd;
-
-       fd = open (rspamd_log->log_file,
-                       O_CREAT | O_WRONLY | O_APPEND,
-                       S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
-       if (fd == -1) {
-               fprintf (stderr,
-                               "open_log: cannot open desired log file: %s, %s\n",
-                               rspamd_log->log_file, strerror (errno));
-               return -1;
-       }
-
-       if (uid != -1 || gid != -1) {
-               if (fchown (fd, uid, gid) == -1) {
-                       fprintf (stderr,
-                                       "open_log: cannot chown desired log file: %s, %s\n",
-                                       rspamd_log->log_file, strerror (errno));
-                       close (fd);
-
-                       return -1;
-               }
-       }
-
-       return fd;
-}
 
 /* Logging utility functions */
 gint
@@ -378,53 +112,6 @@ rspamd_log_open_priv (rspamd_logger_t *rspamd_log, uid_t uid, gid_t gid)
        return 0;
 }
 
-static void
-rspamd_log_reset_repeated (rspamd_logger_t *rspamd_log)
-{
-       gchar tmpbuf[256];
-       gssize r;
-
-       if (rspamd_log->opened) {
-               if (rspamd_log->type == RSPAMD_LOG_FILE) {
-                       if (rspamd_log->repeats > REPEATS_MIN) {
-                               r = rspamd_snprintf (tmpbuf,
-                                               sizeof (tmpbuf),
-                                               "Last message repeated %ud times",
-                                               rspamd_log->repeats);
-                               rspamd_log->repeats = 0;
-
-                               if (rspamd_log->saved_message) {
-                                       file_log_function (rspamd_log->saved_module,
-                                                       rspamd_log->saved_id,
-                                                       rspamd_log->saved_function,
-                                                       rspamd_log->saved_loglevel | RSPAMD_LOG_FORCED,
-                                                       rspamd_log->saved_message,
-                                                       rspamd_log->saved_mlen,
-                                                       rspamd_log,
-                                                       rspamd_log->log_arg);
-
-                                       g_free (rspamd_log->saved_message);
-                                       g_free (rspamd_log->saved_function);
-                                       g_free (rspamd_log->saved_module);
-                                       g_free (rspamd_log->saved_id);
-                                       rspamd_log->saved_message = NULL;
-                                       rspamd_log->saved_function = NULL;
-                                       rspamd_log->saved_module = NULL;
-                                       rspamd_log->saved_id = NULL;
-                               }
-
-                               /* It is safe to use temporary buffer here as it is not static */
-                               file_log_function (NULL, NULL,
-                                               G_STRFUNC,
-                                               rspamd_log->saved_loglevel | RSPAMD_LOG_FORCED,
-                                               tmpbuf,
-                                               r,
-                                               rspamd_log,
-                                               rspamd_log->log_arg);
-                       }
-               }
-       }
-}
 
 void
 rspamd_log_close_priv (rspamd_logger_t *rspamd_log, gboolean termination, uid_t uid, gid_t gid)
@@ -611,17 +298,7 @@ rspamd_set_logger (struct rspamd_config *cfg,
 
        logger->flags = cfg->log_flags;
 
-       /* Set up buffer */
-       if (cfg->log_buffered) {
-               if (cfg->log_buf_size != 0) {
-                       logger->io_buf.size = cfg->log_buf_size;
-               }
-               else {
-                       logger->io_buf.size = LOGBUF_LEN;
-               }
-               logger->is_buffered = TRUE;
-               logger->io_buf.buf = g_malloc (logger->io_buf.size);
-       }
+
        /* Set up conditional logging */
        if (cfg->debug_ip_map != NULL) {
                /* Try to add it as map first of all */
@@ -932,62 +609,6 @@ rspamd_default_log_function (gint level_flags,
 }
 
 
-/**
- * Fill buffer with message (limits must be checked BEFORE this call)
- */
-static void
-fill_buffer (rspamd_logger_t *rspamd_log, const struct iovec *iov, gint iovcnt)
-{
-       gint i;
-
-       for (i = 0; i < iovcnt; i++) {
-               memcpy (rspamd_log->io_buf.buf + rspamd_log->io_buf.used,
-                               iov[i].iov_base,
-                               iov[i].iov_len);
-               rspamd_log->io_buf.used += iov[i].iov_len;
-       }
-
-}
-
-/*
- * Write message to buffer or to file (using direct_write_log_line function)
- */
-static void
-file_log_helper (rspamd_logger_t *rspamd_log,
-               const struct iovec *iov,
-               guint iovcnt,
-               gint level_flags)
-{
-       size_t len = 0;
-       guint i;
-
-       if (!rspamd_log->is_buffered) {
-               /* Write string directly */
-               direct_write_log_line (rspamd_log, (void *) iov, iovcnt, TRUE, level_flags);
-       }
-       else {
-               /* Calculate total length */
-               for (i = 0; i < iovcnt; i++) {
-                       len += iov[i].iov_len;
-               }
-               /* Fill buffer */
-               if (rspamd_log->io_buf.size < len) {
-                       /* Buffer is too small to hold this string, so write it directly */
-                       rspamd_log_flush (rspamd_log);
-                       direct_write_log_line (rspamd_log, (void *) iov, iovcnt, TRUE, level_flags);
-               }
-               else if (rspamd_log->io_buf.used + len >= rspamd_log->io_buf.size) {
-                       /* Buffer is full, try to write it directly */
-                       rspamd_log_flush (rspamd_log);
-                       fill_buffer (rspamd_log, iov, iovcnt);
-               }
-               else {
-                       /* Copy incoming string to buffer */
-                       fill_buffer (rspamd_log, iov, iovcnt);
-               }
-       }
-}
-
 /**
  * Syslog interface for logging
  */
@@ -1034,343 +655,9 @@ syslog_log_function (const gchar *module, const gchar *id,
 #endif
 }
 
-
-static inline void
-log_time (gdouble now, rspamd_logger_t *rspamd_log, gchar *timebuf,
-               size_t len)
-{
-       time_t sec = (time_t)now;
-       gsize r;
-       struct tm tms;
-
-       rspamd_localtime (sec, &tms);
-       r = strftime (timebuf, len, "%F %H:%M:%S", &tms);
-
-       if (rspamd_log->flags & RSPAMD_LOG_FLAG_USEC) {
-               gchar usec_buf[16];
-
-               rspamd_snprintf (usec_buf, sizeof (usec_buf), "%.5f",
-                               now - (gdouble)sec);
-               rspamd_snprintf (timebuf + r, len - r,
-                               "%s", usec_buf + 1);
-       }
-}
-
 /**
  * Main file interface for logging
  */
-static void
-file_log_function (const gchar *module, const gchar *id,
-               const gchar *function,
-               gint level_flags,
-               const gchar *message,
-               gsize mlen,
-               rspamd_logger_t *rspamd_log,
-               gpointer arg)
-{
-       static gchar timebuf[64], modulebuf[64];
-       gchar tmpbuf[256];
-       gchar *m;
-       gdouble now;
-
-       struct iovec iov[6];
-       gulong r = 0, mr = 0;
-       guint64 cksum;
-       size_t mremain;
-       const gchar *cptype = NULL;
-       gboolean got_time = FALSE;
-
-       if (!(level_flags & RSPAMD_LOG_FORCED) && !rspamd_log->enabled) {
-               return;
-       }
-
-       /* Check throttling due to write errors */
-       if (!(level_flags & RSPAMD_LOG_FORCED) && rspamd_log->throttling) {
-               now = rspamd_get_calendar_ticks ();
-               if (rspamd_log->throttling_time != now) {
-                       rspamd_log->throttling_time = now;
-                       got_time = TRUE;
-               }
-               else {
-                       /* Do not try to write to file too often while throttling */
-                       return;
-               }
-       }
-
-       if (!(rspamd_log->flags & RSPAMD_LOG_FLAG_RSPAMADM)) {
-               /* Check repeats */
-               cksum = rspamd_log_calculate_cksum (message, mlen);
-
-               if (cksum == rspamd_log->last_line_cksum) {
-                       rspamd_log->repeats++;
-                       if (rspamd_log->repeats > REPEATS_MIN && rspamd_log->repeats <
-                                       REPEATS_MAX) {
-                               /* Do not log anything */
-                               if (rspamd_log->saved_message == NULL) {
-                                       rspamd_log->saved_function = g_strdup (function);
-                                       rspamd_log->saved_mlen = mlen;
-                                       rspamd_log->saved_message = g_malloc (mlen);
-                                       memcpy (rspamd_log->saved_message, message, mlen);
-
-                                       if (module) {
-                                               rspamd_log->saved_module = g_strdup (module);
-                                       }
-
-                                       if (id) {
-                                               rspamd_log->saved_id = g_strdup (id);
-                                       }
-
-                                       rspamd_log->saved_loglevel = level_flags;
-                               }
-
-                               return;
-                       }
-                       else if (rspamd_log->repeats > REPEATS_MAX) {
-                               gssize r = rspamd_snprintf (tmpbuf,
-                                               sizeof (tmpbuf),
-                                               "Last message repeated %ud times",
-                                               rspamd_log->repeats);
-                               rspamd_log->repeats = 0;
-                               /* It is safe to use temporary buffer here as it is not static */
-                               if (rspamd_log->saved_message) {
-                                       file_log_function (rspamd_log->saved_module,
-                                                       rspamd_log->saved_id,
-                                                       rspamd_log->saved_function,
-                                                       rspamd_log->saved_loglevel,
-                                                       rspamd_log->saved_message,
-                                                       rspamd_log->saved_mlen,
-                                                       rspamd_log,
-                                                       arg);
-
-                                       g_free (rspamd_log->saved_message);
-                                       g_free (rspamd_log->saved_function);
-                                       g_free (rspamd_log->saved_module);
-                                       g_free (rspamd_log->saved_id);
-                                       rspamd_log->saved_message = NULL;
-                                       rspamd_log->saved_function = NULL;
-                                       rspamd_log->saved_module = NULL;
-                                       rspamd_log->saved_id = NULL;
-                               }
-
-                               /* Two messages */
-                               file_log_function ("logger", NULL,
-                                               G_STRFUNC,
-                                               rspamd_log->saved_loglevel,
-                                               tmpbuf,
-                                               r,
-                                               rspamd_log,
-                                               arg);
-
-                               file_log_function (module, id,
-                                               function,
-                                               level_flags,
-                                               message,
-                                               mlen,
-                                               rspamd_log,
-                                               arg);
-
-                               rspamd_log->repeats = REPEATS_MIN + 1;
-
-                               return;
-                       }
-               }
-               else {
-                       /* Reset counter if new message differs from saved message */
-                       rspamd_log->last_line_cksum = cksum;
-                       if (rspamd_log->repeats > REPEATS_MIN) {
-                               gssize r = rspamd_snprintf (tmpbuf,
-                                               sizeof (tmpbuf),
-                                               "Last message repeated %ud times",
-                                               rspamd_log->repeats);
-                               rspamd_log->repeats = 0;
-
-                               if (rspamd_log->saved_message) {
-                                       file_log_function (rspamd_log->saved_module,
-                                                       rspamd_log->saved_id,
-                                                       rspamd_log->saved_function,
-                                                       rspamd_log->saved_loglevel,
-                                                       rspamd_log->saved_message,
-                                                       rspamd_log->saved_mlen,
-                                                       rspamd_log,
-                                                       arg);
-
-                                       g_free (rspamd_log->saved_message);
-                                       g_free (rspamd_log->saved_function);
-                                       g_free (rspamd_log->saved_module);
-                                       g_free (rspamd_log->saved_id);
-                                       rspamd_log->saved_message = NULL;
-                                       rspamd_log->saved_function = NULL;
-                                       rspamd_log->saved_module = NULL;
-                                       rspamd_log->saved_id = NULL;
-                               }
-
-                               file_log_function ("logger", NULL,
-                                               G_STRFUNC,
-                                               level_flags,
-                                               tmpbuf,
-                                               r,
-                                               rspamd_log,
-                                               arg);
-                               /* It is safe to use temporary buffer here as it is not static */
-                               file_log_function (module, id,
-                                               function,
-                                               level_flags,
-                                               message,
-                                               mlen,
-                                               rspamd_log,
-                                               arg);
-                               return;
-                       }
-                       else {
-                               rspamd_log->repeats = 0;
-                       }
-               }
-               if (!got_time) {
-                       now = rspamd_get_calendar_ticks ();
-               }
-
-               /* Format time */
-               if (!(rspamd_log->flags & RSPAMD_LOG_FLAG_SYSTEMD)) {
-                       log_time (now, rspamd_log, timebuf, sizeof (timebuf));
-               }
-
-               cptype = g_quark_to_string (rspamd_log->process_type);
-
-               if (rspamd_log->flags & RSPAMD_LOG_FLAG_COLOR) {
-                       if (level_flags & (G_LOG_LEVEL_INFO|G_LOG_LEVEL_MESSAGE)) {
-                               /* White */
-                               r = rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "\033[0;37m");
-                       }
-                       else if (level_flags & G_LOG_LEVEL_WARNING) {
-                               /* Magenta */
-                               r = rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "\033[0;32m");
-                       }
-                       else if (level_flags & G_LOG_LEVEL_CRITICAL) {
-                               /* Red */
-                               r = rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "\033[1;31m");
-                       }
-               }
-               else {
-                       r = 0;
-               }
-
-               if (!(rspamd_log->flags & RSPAMD_LOG_FLAG_SYSTEMD)) {
-                       r += rspamd_snprintf (tmpbuf + r,
-                                       sizeof (tmpbuf) - r,
-                                       "%s #%P(%s) ",
-                                       timebuf,
-                                       rspamd_log->pid,
-                                       cptype);
-               }
-               else {
-                       r += rspamd_snprintf (tmpbuf + r,
-                                       sizeof (tmpbuf) - r,
-                                       "(%s) ",
-                                       cptype);
-               }
-
-               modulebuf[0] = '\0';
-               mremain = sizeof (modulebuf);
-               m = modulebuf;
-
-               if (id != NULL) {
-                       guint slen = strlen (id);
-                       slen = MIN (LOG_ID, slen);
-                       mr = rspamd_snprintf (m, mremain, "<%*.s>; ", slen,
-                                       id);
-                       m += mr;
-                       mremain -= mr;
-               }
-               if (module != NULL) {
-                       mr = rspamd_snprintf (m, mremain, "%s; ", module);
-                       m += mr;
-                       mremain -= mr;
-               }
-               if (function != NULL) {
-                       mr = rspamd_snprintf (m, mremain, "%s: ", function);
-                       m += mr;
-                       mremain -= mr;
-               }
-               else {
-                       mr = rspamd_snprintf (m, mremain, ": ");
-                       m += mr;
-                       mremain -= mr;
-               }
-
-               /* Construct IOV for log line */
-               iov[0].iov_base = tmpbuf;
-               iov[0].iov_len = r;
-               iov[1].iov_base = modulebuf;
-               iov[1].iov_len = m - modulebuf;
-               iov[2].iov_base = (void *) message;
-               iov[2].iov_len = mlen;
-               iov[3].iov_base = (void *) &lf_chr;
-               iov[3].iov_len = 1;
-
-               if (rspamd_log->flags & RSPAMD_LOG_FLAG_COLOR) {
-                       iov[4].iov_base = "\033[0m";
-                       iov[4].iov_len = sizeof ("\033[0m") - 1;
-                       /* Call helper (for buffering) */
-                       file_log_helper (rspamd_log, iov, 5, level_flags);
-               }
-               else {
-                       /* Call helper (for buffering) */
-                       file_log_helper (rspamd_log, iov, 4, level_flags);
-               }
-       }
-       else {
-               /* Rspamadm logging version */
-
-               if (rspamd_log->flags & RSPAMD_LOG_FLAG_COLOR) {
-                       if (level_flags & (G_LOG_LEVEL_INFO|G_LOG_LEVEL_MESSAGE)) {
-                               /* White */
-                               r = rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "\033[0;37m");
-                       }
-                       else if (level_flags & G_LOG_LEVEL_WARNING) {
-                               /* Magenta */
-                               r = rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "\033[0;32m");
-                       }
-                       else if (level_flags & G_LOG_LEVEL_CRITICAL) {
-                               /* Red */
-                               r = rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "\033[1;31m");
-                       }
-
-                       iov[0].iov_base = (void *) tmpbuf;
-                       iov[0].iov_len = r;
-                       r = 1;
-               }
-               else {
-                       r = 0;
-               }
-
-
-               if (rspamd_log->log_level == G_LOG_LEVEL_DEBUG) {
-                       log_time (rspamd_get_calendar_ticks (),
-                                       rspamd_log, timebuf, sizeof (timebuf));
-                       iov[r].iov_base = (void *) timebuf;
-                       iov[r++].iov_len = strlen (timebuf);
-                       iov[r].iov_base = (void *) " ";
-                       iov[r++].iov_len = 1;
-               }
-
-               iov[r].iov_base = (void *) message;
-               iov[r++].iov_len = mlen;
-               iov[r].iov_base = (void *) &lf_chr;
-               iov[r++].iov_len = 1;
-
-               if (rspamd_log->flags & RSPAMD_LOG_FLAG_COLOR) {
-                       iov[r].iov_base = "\033[0m";
-                       iov[r++].iov_len = sizeof ("\033[0m") - 1;
-                       /* Call helper (for buffering) */
-                       file_log_helper (rspamd_log, iov, r, level_flags);
-               }
-               else {
-                       /* Call helper (for buffering) */
-                       file_log_helper (rspamd_log, iov, r, level_flags);
-               }
-       }
-}
-
 /**
  * Write log line depending on ip
  */
@@ -1707,11 +994,9 @@ rspamd_logger_get_singleton (void)
        return default_logger;
 }
 
-rspamd_log_func_t
+struct rspamd_logger_funcs*
 rspamd_logger_set_log_function (rspamd_logger_t *logger,
-                                                               rspamd_log_func_t nfunc,
-                                                               gpointer narg,
-                                                               gpointer *old_arg)
+                                                               struct rspamd_logger_funcs *nfuncs);
 {
        if (logger == NULL) {
                logger = default_logger;
@@ -1719,10 +1004,6 @@ rspamd_logger_set_log_function (rspamd_logger_t *logger,
 
        g_assert (logger != NULL);
 
-       if (old_arg) {
-               *old_arg = logger->log_arg;
-       }
-
        rspamd_log_func_t old_func = logger->log_func;
 
        logger->log_func = nfunc;
index d2c690392af90f416fc9592f42b775a12697d4bb..3cec58249680ecbbd4da163b9eb5497f38445de7 100644 (file)
@@ -29,6 +29,25 @@ typedef void (*rspamd_log_func_t) (const gchar *module, const gchar *id,
                                                                   gsize mlen,
                                                                   rspamd_logger_t *logger,
                                                                   gpointer arg);
+typedef void * (*rspamd_log_init_func) (rspamd_logger_t *logger,
+                                                                               struct rspamd_config *cfg,
+                                                                               uid_t uid, gid_t gid,
+                                                                               GError **err);
+typedef void* (*rspamd_log_reload_func) (rspamd_logger_t *logger,
+                                                                               struct rspamd_config *cfg,
+                                                                               gpointer arg,
+                                                                               uid_t uid, gid_t gid,
+                                                                               GError **err);
+typedef void (*rspamd_log_dtor_func) (rspamd_logger_t *logger,
+                                                                               gpointer arg);
+
+struct rspamd_logger_funcs {
+       rspamd_log_init_func init;
+       rspamd_log_reload_func reload;
+       rspamd_log_dtor_func dtor;
+       rspamd_log_func_t log;
+       gpointer specific;
+};
 
 #define RSPAMD_LOGBUF_SIZE 8192
 
@@ -200,17 +219,13 @@ ucl_object_t *rspamd_log_errorbuf_export (const rspamd_logger_t *logger);
 rspamd_logger_t *rspamd_logger_get_singleton (void);
 
 /**
- * Sets new logging function
+ * Sets new logger functions and initialise logging if needed
  * @param logger
- * @param nfunc
- * @param narg
- * @param old_arg
- * @return old log function and old log function arg in (*old_arg)
+ * @param nfuncs
+ * @return static pointer to the old functions (so this function is not reentrant)
  */
-rspamd_log_func_t rspamd_logger_set_log_function (rspamd_logger_t *logger,
-                                                                                                  rspamd_log_func_t nfunc,
-                                                                                                  gpointer narg,
-                                                                                                  gpointer *old_arg);
+struct rspamd_logger_funcs* rspamd_logger_set_log_function (rspamd_logger_t *logger,
+                                                                                                                       struct rspamd_logger_funcs *nfuncs);
 
 /* Typical functions */
 
diff --git a/src/libutil/logger_file.c b/src/libutil/logger_file.c
new file mode 100644 (file)
index 0000000..b2e01cf
--- /dev/null
@@ -0,0 +1,588 @@
+/*-
+ * Copyright 2020 Vsevolod Stakhov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "logger.h"
+#include "libserver/cfg_file.h"
+#include "libcryptobox/cryptobox.h"
+#include "unix-std.h"
+
+#include "logger_private.h"
+
+#define FILE_LOG_QUARK g_quark_from_static_string ("file_logger")
+
+static const gchar lf_chr = '\n';
+
+struct rspamd_file_logger_priv {
+       gint fd;
+       struct {
+               guint32 size;
+               guint32 used;
+               u_char *buf;
+       } io_buf;
+       gboolean throttling;
+       gchar *log_file;
+       gboolean is_buffered;
+       time_t throttling_time;
+       guint32 repeats;
+       guint64 last_line_cksum;
+       gchar *saved_message;
+       gsize saved_mlen;
+       gchar *saved_function;
+       gchar *saved_module;
+       gchar *saved_id;
+       guint saved_loglevel;
+       guint64 log_cnt[4];
+};
+
+/**
+ * Calculate checksum for log line (used for repeating logic)
+ */
+static inline guint64
+rspamd_log_calculate_cksum (const gchar *message, size_t mlen)
+{
+       return rspamd_cryptobox_fast_hash (message, mlen, rspamd_hash_seed ());
+}
+
+static inline void
+log_time (gdouble now, rspamd_logger_t *rspamd_log, gchar *timebuf,
+                 size_t len)
+{
+       time_t sec = (time_t)now;
+       gsize r;
+       struct tm tms;
+
+       rspamd_localtime (sec, &tms);
+       r = strftime (timebuf, len, "%F %H:%M:%S", &tms);
+
+       if (rspamd_log->flags & RSPAMD_LOG_FLAG_USEC) {
+               gchar usec_buf[16];
+
+               rspamd_snprintf (usec_buf, sizeof (usec_buf), "%.5f",
+                               now - (gdouble)sec);
+               rspamd_snprintf (timebuf + r, len - r,
+                               "%s", usec_buf + 1);
+       }
+}
+
+
+/*
+ * Write a line to log file (unbuffered)
+ */
+static void
+direct_write_log_line (rspamd_logger_t *rspamd_log,
+                                          struct rspamd_file_logger_priv *priv,
+                                          void *data,
+                                          gsize count,
+                                          gboolean is_iov,
+                                          gint level_flags)
+{
+       gchar errmsg[128];
+       struct iovec *iov;
+       const gchar *line;
+       glong r;
+       gint fd;
+       gboolean locked = FALSE;
+
+       iov = (struct iovec *) data;
+       fd = priv->fd;
+
+       if (!rspamd_log->no_lock) {
+               gsize tlen;
+
+               if (is_iov) {
+                       tlen = 0;
+
+                       for (guint i = 0; i < count; i ++) {
+                               tlen += iov[i].iov_len;
+                       }
+               }
+               else {
+                       tlen = count;
+               }
+
+               if (tlen > PIPE_BUF || rspamd_log->flags & RSPAMD_LOG_FLAG_TTY) {
+                       locked = TRUE;
+
+#ifndef DISABLE_PTHREAD_MUTEX
+                       if (rspamd_log->mtx) {
+                               rspamd_mempool_lock_mutex (rspamd_log->mtx);
+                       }
+                       else {
+                               rspamd_file_lock (fd, FALSE);
+                       }
+#else
+                       rspamd_file_lock (fd, FALSE);
+#endif
+               }
+       }
+
+       if (is_iov) {
+               r = writev (fd, iov, count);
+       }
+       else {
+               line = (const gchar *) data;
+               r = write (fd, line, count);
+       }
+
+       if (locked) {
+#ifndef DISABLE_PTHREAD_MUTEX
+               if (rspamd_log->mtx) {
+                       rspamd_mempool_unlock_mutex (rspamd_log->mtx);
+               }
+               else {
+                       rspamd_file_unlock (fd, FALSE);
+               }
+#else
+               rspamd_file_unlock (fd, FALSE);
+#endif
+       }
+
+       if (r == -1) {
+               /* We cannot write message to file, so we need to detect error and make decision */
+               if (errno == EINTR) {
+                       /* Try again */
+                       direct_write_log_line (rspamd_log, priv, data, count, is_iov, level_flags);
+                       return;
+               }
+
+               r = rspamd_snprintf (errmsg,
+                               sizeof (errmsg),
+                               "direct_write_log_line: cannot write log line: %s",
+                               strerror (errno));
+               if (errno == EFAULT || errno == EINVAL || errno == EFBIG ||
+                       errno == ENOSPC) {
+                       /* Rare case */
+                       priv->throttling = TRUE;
+                       priv->throttling_time = time (NULL);
+               }
+               else if (errno == EPIPE || errno == EBADF) {
+                       /* We write to some pipe and it disappears, disable logging or we has opened bad file descriptor */
+                       rspamd_log->enabled = FALSE;
+               }
+       }
+       else if (priv->throttling) {
+               priv->throttling = FALSE;
+       }
+}
+
+/**
+ * Fill buffer with message (limits must be checked BEFORE this call)
+ */
+static void
+fill_buffer (rspamd_logger_t *rspamd_log,
+                        struct rspamd_file_logger_priv *priv,
+                        const struct iovec *iov, gint iovcnt)
+{
+       gint i;
+
+       for (i = 0; i < iovcnt; i++) {
+               memcpy (priv->io_buf.buf + priv->io_buf.used,
+                               iov[i].iov_base,
+                               iov[i].iov_len);
+               priv->io_buf.used += iov[i].iov_len;
+       }
+
+}
+
+/*
+ * Write message to buffer or to file (using direct_write_log_line function)
+ */
+static void
+file_log_helper (rspamd_logger_t *rspamd_log,
+                                struct rspamd_file_logger_priv *priv,
+                                const struct iovec *iov,
+                                guint iovcnt,
+                                gint level_flags)
+{
+       size_t len = 0;
+       guint i;
+
+       if (!priv->is_buffered) {
+               /* Write string directly */
+               direct_write_log_line (rspamd_log, priv, (void *) iov, iovcnt,
+                               TRUE, level_flags);
+       }
+       else {
+               /* Calculate total length */
+               for (i = 0; i < iovcnt; i++) {
+                       len += iov[i].iov_len;
+               }
+               /* Fill buffer */
+               if (priv->io_buf.size < len) {
+                       /* Buffer is too small to hold this string, so write it directly */
+                       rspamd_log_flush (rspamd_log);
+                       direct_write_log_line (rspamd_log, priv, (void *) iov, iovcnt,
+                                       TRUE, level_flags);
+               }
+               else if (priv->io_buf.used + len >= priv->io_buf.size) {
+                       /* Buffer is full, try to write it directly */
+                       rspamd_log_flush (rspamd_log);
+                       fill_buffer (rspamd_log, priv, iov, iovcnt);
+               }
+               else {
+                       /* Copy incoming string to buffer */
+                       fill_buffer (rspamd_log, priv, iov, iovcnt);
+               }
+       }
+}
+
+static void
+rspamd_log_reset_repeated (rspamd_logger_t *rspamd_log,
+                                                  struct rspamd_file_logger_priv *priv)
+{
+       gchar tmpbuf[256];
+       gssize r;
+
+       if (rspamd_log->opened) {
+               if (priv->repeats > REPEATS_MIN) {
+                       r = rspamd_snprintf (tmpbuf,
+                                       sizeof (tmpbuf),
+                                       "Last message repeated %ud times",
+                                       priv->repeats - REPEATS_MIN);
+                       priv->repeats = 0;
+
+                       if (priv->saved_message) {
+                               rspamd_log_file_log (priv->saved_module,
+                                               priv->saved_id,
+                                               priv->saved_function,
+                                               priv->saved_loglevel | RSPAMD_LOG_FORCED,
+                                               priv->saved_message,
+                                               priv->saved_mlen,
+                                               rspamd_log,
+                                               priv);
+
+                               g_free (priv->saved_message);
+                               g_free (priv->saved_function);
+                               g_free (priv->saved_module);
+                               g_free (priv->saved_id);
+                               priv->saved_message = NULL;
+                               priv->saved_function = NULL;
+                               priv->saved_module = NULL;
+                               priv->saved_id = NULL;
+                       }
+
+                       /* It is safe to use temporary buffer here as it is not static */
+                       rspamd_log_file_log (NULL, NULL,
+                                       G_STRFUNC,
+                                       priv->saved_loglevel | RSPAMD_LOG_FORCED,
+                                       tmpbuf,
+                                       r,
+                                       rspamd_log,
+                                       priv);
+               }
+       }
+}
+
+static gint
+rspamd_try_open_log_fd (rspamd_logger_t *rspamd_log,
+                                               struct rspamd_file_logger_priv *priv,
+                                               uid_t uid, gid_t gid,
+                                               GError **err)
+{
+       gint fd;
+
+       fd = open (priv->log_file,
+                       O_CREAT | O_WRONLY | O_APPEND,
+                       S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
+       if (fd == -1) {
+               g_set_error (err, FILE_LOG_QUARK, errno,
+                               "open_log: cannot open desired log file: %s, %s\n",
+                               priv->log_file, strerror (errno));
+               return -1;
+       }
+
+       if (uid != -1 || gid != -1) {
+               if (fchown (fd, uid, gid) == -1) {
+                       g_set_error (err, FILE_LOG_QUARK, errno,
+                                       "open_log: cannot chown desired log file: %s, %s\n",
+                                       priv->log_file, strerror (errno));
+                       close (fd);
+
+                       return -1;
+               }
+       }
+
+       return fd;
+}
+
+void *
+rspamd_log_file_init (rspamd_logger_t *logger, struct rspamd_config *cfg,
+                                         uid_t uid, gid_t gid, GError **err)
+{
+       struct rspamd_file_logger_priv *priv;
+
+       if (!cfg->cfg_name) {
+               g_set_error (err, FILE_LOG_QUARK, EINVAL,
+                               "no log file specified");
+               return NULL;
+       }
+
+       priv = g_malloc0 (sizeof (*priv));
+
+       if (cfg->log_buffered) {
+               if (cfg->log_buf_size != 0) {
+                       priv->io_buf.size = cfg->log_buf_size;
+               }
+               else {
+                       priv->io_buf.size = LOGBUF_LEN;
+               }
+               priv->is_buffered = TRUE;
+               priv->io_buf.buf = g_malloc (priv->io_buf.size);
+       }
+
+       if (cfg->log_file) {
+               priv->log_file = g_strdup (cfg->log_file);
+       }
+
+       priv->fd = rspamd_try_open_log_fd (logger, priv, uid, gid, err);
+
+       if (priv->fd == -1) {
+               rspamd_log_file_dtor (logger, priv);
+
+               return NULL;
+       }
+
+       return priv;
+}
+
+void
+rspamd_log_file_dtor (rspamd_logger_t *logger, gpointer arg)
+{
+       struct rspamd_file_logger_priv *priv = (struct rspamd_file_logger_priv *)arg;
+
+       rspamd_log_reset_repeated (logger, priv);
+
+       if (priv->fd != -1) {
+               if (close (priv->fd) == -1) {
+                       rspamd_fprintf (stderr, "cannot close log fd %d: %s; log file = %s\n",
+                                       priv->fd, strerror (errno), priv->log_file);
+               }
+       }
+
+       g_free (priv->log_file);
+       g_free (priv);
+}
+
+void
+rspamd_log_file_log (const gchar *module, const gchar *id,
+                                  const gchar *function,
+                                  gint level_flags,
+                                  const gchar *message,
+                                  gsize mlen,
+                                  rspamd_logger_t *rspamd_log,
+                                  gpointer arg)
+{
+       struct rspamd_file_logger_priv *priv = (struct rspamd_file_logger_priv *)arg;
+       static gchar timebuf[64], modulebuf[64];
+       gchar tmpbuf[256];
+       gchar *m;
+       gdouble now;
+       struct iovec iov[6];
+       gulong r = 0, mr = 0;
+       guint64 cksum;
+       size_t mremain;
+       const gchar *cptype = NULL;
+       gboolean got_time = FALSE;
+
+
+       if (!(level_flags & RSPAMD_LOG_FORCED) && !rspamd_log->enabled) {
+               return;
+       }
+
+       /* Check throttling due to write errors */
+       if (!(level_flags & RSPAMD_LOG_FORCED) && priv->throttling) {
+               now = rspamd_get_calendar_ticks ();
+               if (priv->throttling_time != now) {
+                       priv->throttling_time = now;
+                       got_time = TRUE;
+               }
+               else {
+                       /* Do not try to write to file too often while throttling */
+                       return;
+               }
+       }
+
+       /* Check repeats */
+       cksum = rspamd_log_calculate_cksum (message, mlen);
+
+       if (cksum == priv->last_line_cksum) {
+               priv->repeats++;
+
+               if (priv->repeats > REPEATS_MIN && priv->repeats <
+                                                                                                REPEATS_MAX) {
+                       /* Do not log anything but save message for future */
+                       if (priv->saved_message == NULL) {
+                               priv->saved_function = g_strdup (function);
+                               priv->saved_mlen = mlen;
+                               priv->saved_message = g_malloc (mlen);
+                               memcpy (priv->saved_message, message, mlen);
+
+                               if (module) {
+                                       priv->saved_module = g_strdup (module);
+                               }
+
+                               if (id) {
+                                       priv->saved_id = g_strdup (id);
+                               }
+
+                               priv->saved_loglevel = level_flags;
+                       }
+
+                       return;
+               }
+               else if (priv->repeats > REPEATS_MAX) {
+                       rspamd_log_reset_repeated (rspamd_log, priv);
+
+                       rspamd_log_file_log (module, id,
+                                       function,
+                                       level_flags,
+                                       message,
+                                       mlen,
+                                       rspamd_log,
+                                       priv);
+
+                       /* Probably we have more repeats in future */
+                       priv->repeats = REPEATS_MIN + 1;
+
+                       return;
+               }
+       }
+       else {
+               /* Reset counter if new message differs from saved message */
+               priv->last_line_cksum = cksum;
+
+               if (priv->repeats > REPEATS_MIN) {
+                       rspamd_log_reset_repeated (rspamd_log, priv);
+                       rspamd_log_file_log (module, id,
+                                       function,
+                                       level_flags,
+                                       message,
+                                       mlen,
+                                       rspamd_log,
+                                       arg);
+                       return;
+               }
+               else {
+                       priv->repeats = 0;
+               }
+       }
+       if (!got_time) {
+               now = rspamd_get_calendar_ticks ();
+       }
+
+       /* Format time */
+       if (!(rspamd_log->flags & RSPAMD_LOG_FLAG_SYSTEMD)) {
+               log_time (now, rspamd_log, timebuf, sizeof (timebuf));
+       }
+
+       cptype = g_quark_to_string (rspamd_log->process_type);
+
+       if (rspamd_log->flags & RSPAMD_LOG_FLAG_COLOR) {
+               if (level_flags & (G_LOG_LEVEL_INFO|G_LOG_LEVEL_MESSAGE)) {
+                       /* White */
+                       r = rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "\033[0;37m");
+               }
+               else if (level_flags & G_LOG_LEVEL_WARNING) {
+                       /* Magenta */
+                       r = rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "\033[0;32m");
+               }
+               else if (level_flags & G_LOG_LEVEL_CRITICAL) {
+                       /* Red */
+                       r = rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "\033[1;31m");
+               }
+       }
+       else {
+               r = 0;
+       }
+
+       if (!(rspamd_log->flags & RSPAMD_LOG_FLAG_SYSTEMD)) {
+               r += rspamd_snprintf (tmpbuf + r,
+                               sizeof (tmpbuf) - r,
+                               "%s #%P(%s) ",
+                               timebuf,
+                               rspamd_log->pid,
+                               cptype);
+       }
+       else {
+               r += rspamd_snprintf (tmpbuf + r,
+                               sizeof (tmpbuf) - r,
+                               "(%s) ",
+                               cptype);
+       }
+
+       modulebuf[0] = '\0';
+       mremain = sizeof (modulebuf);
+       m = modulebuf;
+
+       if (id != NULL) {
+               guint slen = strlen (id);
+               slen = MIN (LOG_ID, slen);
+               mr = rspamd_snprintf (m, mremain, "<%*.s>; ", slen,
+                               id);
+               m += mr;
+               mremain -= mr;
+       }
+       if (module != NULL) {
+               mr = rspamd_snprintf (m, mremain, "%s; ", module);
+               m += mr;
+               mremain -= mr;
+       }
+       if (function != NULL) {
+               mr = rspamd_snprintf (m, mremain, "%s: ", function);
+               m += mr;
+               mremain -= mr;
+       }
+       else {
+               mr = rspamd_snprintf (m, mremain, ": ");
+               m += mr;
+               mremain -= mr;
+       }
+
+       /* Construct IOV for log line */
+       iov[0].iov_base = tmpbuf;
+       iov[0].iov_len = r;
+       iov[1].iov_base = modulebuf;
+       iov[1].iov_len = m - modulebuf;
+       iov[2].iov_base = (void *) message;
+       iov[2].iov_len = mlen;
+       iov[3].iov_base = (void *) &lf_chr;
+       iov[3].iov_len = 1;
+
+       file_log_helper (rspamd_log, priv, iov, 4, level_flags);
+}
+
+void *
+rspamd_log_file_reload (rspamd_logger_t *logger, struct rspamd_config *cfg,
+                                               gpointer arg, uid_t uid, gid_t gid, GError **err)
+{
+       struct rspamd_file_logger_priv *npriv;
+
+       if (!cfg->cfg_name) {
+               g_set_error (err, FILE_LOG_QUARK, EINVAL,
+                               "no log file specified");
+               return NULL;
+       }
+
+       npriv = rspamd_log_file_init (logger, cfg, uid, gid, err);
+
+       if (npriv) {
+               /* Close old */
+               rspamd_log_file_dtor (logger, arg);
+       }
+
+       return npriv;
+}
diff --git a/src/libutil/logger_private.h b/src/libutil/logger_private.h
new file mode 100644 (file)
index 0000000..4644e4e
--- /dev/null
@@ -0,0 +1,109 @@
+/*-
+ * Copyright 2020 Vsevolod Stakhov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RSPAMD_LOGGER_PRIVATE_H
+#define RSPAMD_LOGGER_PRIVATE_H
+
+/* How much message should be repeated before it is count to be repeated one */
+#define REPEATS_MIN 3
+#define REPEATS_MAX 300
+#define LOG_ID 6
+#define LOGBUF_LEN 8192
+
+struct rspamd_log_module {
+       gchar *mname;
+       guint id;
+};
+
+struct rspamd_log_modules {
+       guchar *bitset;
+       guint bitset_len; /* Number of BITS used in bitset */
+       guint bitset_allocated; /* Size of bitset allocated in BYTES */
+       GHashTable *modules;
+};
+
+struct rspamd_logger_error_elt {
+       gint completed;
+       GQuark ptype;
+       pid_t pid;
+       gdouble ts;
+       gchar id[LOG_ID + 1];
+       gchar module[9];
+       gchar message[];
+};
+
+struct rspamd_logger_error_log {
+       struct rspamd_logger_error_elt *elts;
+       rspamd_mempool_t *pool;
+       guint32 max_elts;
+       guint32 elt_len;
+       /* Avoid false cache sharing */
+       guchar __padding[64 - sizeof(gpointer) * 2 - sizeof(guint64)];
+       guint cur_row;
+};
+
+/**
+ * Static structure that store logging parameters
+ * It is NOT shared between processes and is created by main process
+ */
+struct rspamd_logger_s {
+       struct rspamd_logger_funcs ops;
+       gint log_facility;
+       gint log_level;
+
+       struct rspamd_logger_error_log *errlog;
+       struct rspamd_cryptobox_pubkey *pk;
+       struct rspamd_cryptobox_keypair *keypair;
+
+       guint flags;
+       gboolean enabled;
+       gboolean is_debug;
+       gboolean no_lock;
+       gboolean opened;
+
+       pid_t pid;
+       GQuark process_type;
+       struct rspamd_radix_map_helper *debug_ip;
+       rspamd_mempool_mutex_t *mtx;
+};
+
+/*
+ * Common logging prototypes
+ */
+
+/*
+ * File logging
+ */
+void * rspamd_log_file_init (rspamd_logger_t *logger, struct rspamd_config *cfg,
+                                                        uid_t uid, gid_t gid, GError **err);
+void * rspamd_log_file_reload (rspamd_logger_t *logger, struct rspamd_config *cfg,
+                                                          gpointer arg, uid_t uid, gid_t gid, GError **err);
+void rspamd_log_file_dtor (rspamd_logger_t *logger, gpointer arg);
+void rspamd_log_file_log (const gchar *module, const gchar *id,
+                                                 const gchar *function,
+                                                 gint level_flags,
+                                                 const gchar *message,
+                                                 gsize mlen,
+                                                 rspamd_logger_t *rspamd_log,
+                                                 gpointer arg);
+
+const static struct rspamd_logger_funcs file_log_funcs = {
+               .init = rspamd_log_file_init,
+               .dtor = rspamd_log_file_dtor,
+               .reload = rspamd_log_file_reload,
+               .log = rspamd_log_file_log,
+};
+
+#endif