]> mj.ucw.cz Git - libucw.git/commitdiff
Logging: Stream filters are permitted to modify log messages
authorMartin Mares <mj@ucw.cz>
Tue, 4 Feb 2014 12:55:23 +0000 (13:55 +0100)
committerMartin Mares <mj@ucw.cz>
Tue, 4 Feb 2014 12:55:23 +0000 (13:55 +0100)
maint/libucw.abi
ucw/log-conf.c
ucw/log-internal.h
ucw/log.c
ucw/log.h

index cd462cc205386d9e00dd5582f616e176e0aba85e..c11f24042e91de09e5a353aeb6bdf1820bb74675 100644 (file)
@@ -292,6 +292,7 @@ log_set_format
 log_stream_by_flags
 log_set_default_stream
 log_close_all
+log_pass_filtered
 log_new_file
 log_new_fd
 log_switch_disable
index 824d95fcb01df289025f44a19634584531df6214..ff71feaa6bd7495afd3d5b20b5e72ba2c4c5f2a6 100644 (file)
@@ -243,7 +243,7 @@ log_limiter(struct log_stream *ls, struct log_msg *m)
          struct log_msg mm = *m;
          mm.flags |= L_LOGGER_ERR;
          mm.raw_msg = "(maximum logging rate exceeded, some messages will be suppressed)";
-         log_pass_msg(0, ls, &mm);
+         log_pass_msg(ls, &mm);
        }
       return 1;
     }
index c2eef05bad331dd25c348705ce4e43a1c88b41ea..dc1d1526007683cf39e441ce3b55dec725f6d599 100644 (file)
 #define log_type_names ucw_log_type_names
 #endif
 
-/*
- * Pass a message to a stream.
- * @depth prevents loops.
- * Returns 1 in case of loop detection or other fatal error,
- *         0 otherwise
- */
-int log_pass_msg(int depth, struct log_stream *ls, struct log_msg *m);
+/* Pass a message to a stream. */
+void log_pass_msg(struct log_stream *ls, struct log_msg *m);
 
 /* Define an array (growing buffer) for pointers to log_streams. */
 #define GBUF_TYPE struct log_stream*
index df6eae0531ecdef5f5e3352acd49157ec418aa14..aea97e3bd61457d2f0d371021cfe7cfcb0a306f0 100644 (file)
--- a/ucw/log.c
+++ b/ucw/log.c
@@ -161,10 +161,11 @@ vmsg(uns cat, const char *fmt, va_list args)
     }
 
   /* Pass the message to the log_stream */
-  if (log_pass_msg(0, ls, &m))
+  log_pass_msg(ls, &m);
+  if (m.error)
     {
       /* Error (such as infinite loop) occurred */
-      log_pass_msg(0, &log_stream_default, &m);
+      log_pass_msg(&log_stream_default, &m);
     }
 
   if (m.raw_msg != msgbuf)
@@ -194,7 +195,7 @@ log_report_err(struct log_stream *ls, struct log_msg *m, int err)
       errno = err;
       snprintf(errbuf, sizeof(errbuf), "Error logging to %s: %m", name);
     }
-  log_pass_msg(0, &log_stream_default, &errm);
+  log_pass_msg(&log_stream_default, &errm);
 
   if (ls->stream_flags & LSFLAG_ERR_IS_FATAL)
     do_die();
@@ -203,32 +204,20 @@ log_report_err(struct log_stream *ls, struct log_msg *m, int err)
 /* Maximal depth of log_pass_msg recursion */
 #define LS_MAX_DEPTH 64
 
-int
-log_pass_msg(int depth, struct log_stream *ls, struct log_msg *m)
+void
+log_pass_filtered(struct log_stream *ls, struct log_msg *m)
 {
-  ASSERT(ls);
-
-  /* Check recursion depth */
-  if (depth > LS_MAX_DEPTH)
-    {
-      log_report_err(ls, m, EDEADLK);
-      return 1;
-    }
-
-  /* Filter by level, type and hook function */
-  if (!((1 << LS_GET_LEVEL(m->flags)) & ls->levels) ||
-      !((1 << LS_GET_TYPE(m->flags)) & ls->types) ||
-      ls->filter && ls->filter(ls, m))
-    return 0;
-
   /* Pass the message to substreams */
   CLIST_FOR_EACH(simp_node *, s, ls->substreams)
-    if (log_pass_msg(depth+1, s->p, m))
-      return 1;
+    {
+      log_pass_msg(s->p, m);
+      if (m->error)
+       return;
+    }
 
   /* Will pass to the handler of this stream... is there any? */
   if (!ls->handler)
-    return 0;
+    return;
 
   /* Will print a message type? */
   char *type = NULL;
@@ -316,7 +305,36 @@ log_pass_msg(int depth, struct log_stream *ls, struct log_msg *m)
 
   if (free_buf)
     xfree(free_buf);
-  return 0;
+}
+
+void
+log_pass_msg(struct log_stream *ls, struct log_msg *m)
+{
+  ASSERT(ls);
+
+  /* Check recursion depth */
+  if (m->depth > LS_MAX_DEPTH)
+    {
+      log_report_err(ls, m, EDEADLK);
+      m->error = 1;
+      return;
+    }
+
+  /* Filter by level and type */
+  if (!((1 << LS_GET_LEVEL(m->flags)) & ls->levels) ||
+      !((1 << LS_GET_TYPE(m->flags)) & ls->types))
+    return;
+
+  m->depth++;
+
+  if (ls->filter && ls->filter(ls, m))
+    {
+      // The filter might have called log_pass_filtered()
+    }
+  else
+    log_pass_filtered(ls, m);
+
+  m->depth--;
 }
 
 /*** Utility functions ***/
index d4cc525df083a097c7a4a003031dace4327db60d..bee7a8a204e9918b1be209a40c426baaef61f2c8 100644 (file)
--- a/ucw/log.h
+++ b/ucw/log.h
@@ -25,6 +25,7 @@
 #define log_new_file ucw_log_new_file
 #define log_new_stream ucw_log_new_stream
 #define log_new_syslog ucw_log_new_syslog
+#define log_pass_filtered ucw_log_pass_filtered
 #define log_register_type ucw_log_register_type
 #define log_rm_substream ucw_log_rm_substream
 #define log_set_default_stream ucw_log_set_default_stream
@@ -51,6 +52,8 @@ struct log_msg {
   char *raw_msg;                       // Unformatted parts
   char *stime;
   char *sutime;
+  uns depth;                           // Recursion depth
+  bool error;                          // An error has occurred (e.g., an infinite loop in sub-streams)
 };
 
 /**
@@ -220,6 +223,15 @@ void log_set_default_stream(struct log_stream *ls);
  **/
 void log_close_all(void);
 
+/**
+ * The filter function of a stream might want to modify the message
+ * before passing it to the handler and/or substreams. In this case,
+ * the filter should make a local copy of `struct log_msg`, call
+ * @log_pass_filtered() on it and return true, so that the original
+ * message will not be processed any further.
+ **/
+void log_pass_filtered(struct log_stream *ls, struct log_msg *m);
+
 /***
  * === Logging to files
  *