diff options
Diffstat (limited to 'src/libserver/logger/logger_console.c')
-rw-r--r-- | src/libserver/logger/logger_console.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/src/libserver/logger/logger_console.c b/src/libserver/logger/logger_console.c new file mode 100644 index 000000000..1bc91007a --- /dev/null +++ b/src/libserver/logger/logger_console.c @@ -0,0 +1,294 @@ +/*- + * 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 CONSOLE_LOG_QUARK g_quark_from_static_string ("console_logger") + +static const gchar lf_chr = '\n'; +struct rspamd_console_logger_priv { + gint fd; + gint crit_fd; + gboolean log_color; + gboolean log_rspamadm; + gboolean log_tty; +}; + +/* Copy & paste :( */ +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); + } +} + +void * +rspamd_log_console_init (rspamd_logger_t *logger, struct rspamd_config *cfg, + uid_t uid, gid_t gid, GError **err) +{ + struct rspamd_console_logger_priv *priv; + + priv = g_malloc0 (sizeof (*priv)); + priv->log_color = (logger->flags & RSPAMD_LOG_FLAG_COLOR); + priv->log_rspamadm = (logger->flags & RSPAMD_LOG_FLAG_RSPAMADM); + + if (priv->log_rspamadm) { + priv->fd = dup (STDOUT_FILENO); + priv->crit_fd = dup (STDERR_FILENO); + } + else { + priv->fd = dup (STDERR_FILENO); + priv->crit_fd = priv->fd; + } + + if (priv->fd == -1) { + g_set_error (err, CONSOLE_LOG_QUARK, errno, + "open_log: cannot dup console fd: %s\n", + strerror (errno)); + rspamd_log_console_dtor (logger, priv); + + return NULL; + } + + if (isatty (priv->fd)) { + priv->log_tty = true; + } + else if (priv->log_color) { + /* Disable colors for not a tty */ + priv->log_color = false; + } + + return priv; +} + +void * +rspamd_log_console_reload (rspamd_logger_t *logger, struct rspamd_config *cfg, + gpointer arg, uid_t uid, gid_t gid, GError **err) +{ + struct rspamd_console_logger_priv *npriv; + + npriv = rspamd_log_console_init (logger, cfg, uid, gid, err); + + if (npriv) { + /* Close old */ + rspamd_log_console_dtor (logger, arg); + } + + return npriv; +} + +void +rspamd_log_console_dtor (rspamd_logger_t *logger, gpointer arg) +{ + struct rspamd_console_logger_priv *priv = (struct rspamd_console_logger_priv *)arg; + + if (priv->fd != -1) { + if (priv->fd != priv->crit_fd) { + /* Two different FD case */ + if (close (priv->crit_fd) == -1) { + rspamd_fprintf (stderr, "cannot close log crit_fd %d: %s\n", + priv->crit_fd, strerror (errno)); + } + } + + if (close (priv->fd) == -1) { + rspamd_fprintf (stderr, "cannot close log fd %d: %s\n", + priv->fd, strerror (errno)); + } + + /* Avoid the next if to be executed as crit_fd is equal to fd */ + priv->crit_fd = -1; + } + + if (priv->crit_fd != -1) { + if (close (priv->crit_fd) == -1) { + rspamd_fprintf (stderr, "cannot close log crit_fd %d: %s\n", + priv->crit_fd, strerror (errno)); + } + } + + g_free (priv); +} + +bool +rspamd_log_console_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_console_logger_priv *priv = (struct rspamd_console_logger_priv *)arg; + static gchar timebuf[64], modulebuf[64]; + gchar tmpbuf[256]; + gchar *m; + struct iovec iov[6]; + gulong r = 0, mr = 0; + size_t mremain; + gint fd, niov = 0; + + if (level_flags & G_LOG_LEVEL_CRITICAL) { + fd = priv->crit_fd; + } + else { + fd = priv->fd; + } + +#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 + + log_time (rspamd_get_calendar_ticks (), + rspamd_log, timebuf, sizeof (timebuf)); + if (priv->log_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 (priv->log_rspamadm) { + if (rspamd_log->log_level == G_LOG_LEVEL_DEBUG) { + log_time (rspamd_get_calendar_ticks (), + rspamd_log, timebuf, sizeof (timebuf)); + iov[niov].iov_base = (void *) timebuf; + iov[niov++].iov_len = strlen (timebuf); + iov[niov].iov_base = (void *) " "; + iov[niov++].iov_len = 1; + } + + iov[niov].iov_base = (void *) message; + iov[niov++].iov_len = mlen; + iov[niov].iov_base = (void *) &lf_chr; + iov[niov++].iov_len = 1; + } + else { + r += rspamd_snprintf (tmpbuf + r, + sizeof (tmpbuf) - r, + "%s #%P(%s) ", + timebuf, + rspamd_log->pid, + rspamd_log->process_type); + + 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; + } + + iov[niov].iov_base = tmpbuf; + iov[niov++].iov_len = r; + iov[niov].iov_base = modulebuf; + iov[niov++].iov_len = m - modulebuf; + iov[niov].iov_base = (void *) message; + iov[niov++].iov_len = mlen; + iov[niov].iov_base = (void *) &lf_chr; + iov[niov++].iov_len = 1; + } + + if (priv->log_color) { + iov[niov].iov_base = "\033[0m"; + iov[niov++].iov_len = sizeof ("\033[0m") - 1; + } + +again: + r = writev (fd, iov, niov); + + if (r == -1) { + if (errno == EAGAIN || errno == EINTR) { + goto again; + } + + if (rspamd_log->mtx) { + rspamd_mempool_unlock_mutex (rspamd_log->mtx); + } + else { + rspamd_file_unlock (fd, FALSE); + } + + return false; + } + + if (rspamd_log->mtx) { + rspamd_mempool_unlock_mutex (rspamd_log->mtx); + } + else { + rspamd_file_unlock (fd, FALSE); + } + + return true; +}
\ No newline at end of file |