#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*
}
/* 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)
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();
/* 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;
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 ***/
#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
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)
};
/**
**/
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
*