summaryrefslogtreecommitdiffstats
path: root/src/libserver/logger/logger_console.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libserver/logger/logger_console.c')
-rw-r--r--src/libserver/logger/logger_console.c294
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