return 0;
}
+Message types
+-------------
+Messages can also have types, which can be used for further filtering inside streams.
+By default, there is only the default message type. To obtain an identifier of a new
+type (again to be OR'ed to the log level when calling <<msg()>>), use <<log_register_type()>>.
+The number of types is currently limited to 32.
+
+If you want non-default types to be visible, enable the `LSFMT_TYPE` format flag.
+
Processes, threads and signals
------------------------------
When you fork a new process, it automatically inherits all currently configured log
extern struct log_stream log_stream_default;
+extern char **log_type_names;
+
#endif
/* Initialize the stream */
bzero(l, sizeof(*l));
l->levels = ~0U;
+ l->types = ~0U;
l->regnum = LS_SET_STRNUM(index);
clist_init(&l->substreams);
return log_ref_stream(l);
CLIST_FOR_EACH(simp_node *, i, ls->substreams)
log_set_format(i->p, mask, data);
}
+
+/*** Registry of type names ***/
+
+int log_register_type(const char *name)
+{
+ if (!log_type_names)
+ {
+ log_type_names = xmalloc_zero(LS_GET_TYPE(~0U) * sizeof(char *));
+ log_type_names[0] = "default";
+ }
+ uns id;
+ for (id=0; id < LS_GET_TYPE(~0U) && log_type_names[id]; id++)
+ if (!strcmp(log_type_names[id], name))
+ return LS_SET_TYPE(id);
+ ASSERT(id < LS_GET_TYPE(~0U));
+ log_type_names[id] = xstrdup(name);
+ return LS_SET_TYPE(id);
+}
+
+/** Find a message type by name and return its ID encoded by `LS_SET_TYPE`. Returns -1 if no such type found. **/
+int log_find_type(const char *name)
+{
+ if (!strcmp(name, "default"))
+ return 0;
+ if (!log_type_names)
+ return -1;
+
+ for (uns id=0; id < LS_GET_TYPE(~0U) && log_type_names[id]; id++)
+ if (!strcmp(log_type_names[id], name))
+ return LS_SET_TYPE(id);
+ return -1;
+}
.use_count = 1000000,
.handler = default_log_handler,
.levels = ~0U,
+ .types = ~0U,
.msgfmt = LSFMT_DEFAULT,
// an empty clist
.substreams.head.next = (cnode *) &log_stream_default.substreams.head,
return log_streams.ptr[n];
}
+/*** Known message types ***/
+
+char **log_type_names;
+
+char *
+log_type_name(uns flags)
+{
+ uns type = LS_GET_TYPE(flags);
+
+ if (!log_type_names || !log_type_names[type])
+ return "default";
+ else
+ return log_type_names[type];
+}
+
/*** Logging ***/
void
return 1;
}
- /* Filter by level and hook function */
- if (!((1 << LS_GET_LEVEL(m->flags)) & ls->levels))
- return 0;
- if (ls->filter && ls->filter(ls, m))
+ /* 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 */
if (!ls->handler)
return 0;
+ /* Will print a message type? */
+ char *type = NULL;
+ if ((ls->msgfmt & LSFMT_TYPE) && LS_GET_TYPE(m->flags))
+ type = log_type_name(m->flags);
+
/* Upper bound on message length */
int len = strlen(m->raw_msg) + strlen(m->stime) + strlen(m->sutime) + 32;
if (log_title)
len += strlen(log_title);
if (ls->name)
len += strlen(ls->name);
+ if (type)
+ len += strlen(type) + 3;
/* Get a buffer and format the message */
char *free_buf = NULL;
p += sprintf(p, "<?> ");
}
+ /* Message type ( |type| + 3 chars ) */
+ if (ls->msgfmt & LSFMT_TYPE)
+ p += sprintf(p, "{%s} ", type);
+
/* The message itself ( |m| + 1 chars ) */
{
const char *q = m->raw_msg;
int main(void)
{
+ int type = log_find_type("foo");
+ ASSERT(type < 0);
+ type = log_register_type("foo");
+
struct log_stream *ls = log_new_syslog("local3", 0);
#if 0
log_add_substream(ls, ls);
ls->stream_flags |= LSFLAG_ERR_IS_FATAL;
#endif
msg(L_INFO | ls->regnum, "Brum <%300s>", ":-)");
- log_set_format(log_default_stream(), ~0U, LSFMT_USEC);
- msg(L_INFO, "Brum <%300s>", ":-)");
+ log_set_format(log_default_stream(), ~0U, LSFMT_USEC | LSFMT_TYPE);
+ msg(L_INFO | type, "Brum <%300s>", ":-)");
log_close_all();
return 0;
}
char *name; // Optional name, allocated by the user (or constructor)
int regnum; // Stream number, already encoded by LS_SET_STRNUM(); -1 if closed
uns levels; // Bitmask of accepted severity levels (default: all)
+ uns types; // Bitmask of accepted message types (default: all)
uns msgfmt; // Formatting flags (LSFMT_xxx)
uns use_count; // Number of references to the stream
uns stream_flags; // Various other flags (LSFLAG_xxx)
LSFMT_TITLE = 8, // program title (log_title) */
LSFMT_PID = 16, // program PID (log_pid) */
LSFMT_LOGNAME = 32, // name of the log_stream */
+ LSFMT_TYPE = 64, // message type
};
#define LSFMT_DEFAULT (LSFMT_LEVEL | LSFMT_TIME | LSFMT_TITLE | LSFMT_PID) /** Default format **/
* === Message flags
*
* The @flags parameter of msg() is divided to several groups of bits (from the LSB):
- * message severity level (`L_xxx`), destination stream, message type [currently unused]
+ * message severity level (`L_xxx`), destination stream, message type
* and control bits (e.g., `L_SIGHANDLER`).
***/
#define LS_SET_TYPE(type) ((type) << LS_TYPE_POS) /** Convert message type to flags **/
#define LS_SET_CTRL(ctrl) ((ctrl) << LS_CTRL_POS) /** Convert control bits to flags **/
+/** Register a new message type and return the corresponding flag set (encoded by `LS_SET_TYPE`). **/
+int log_register_type(const char *name);
+
+/** Find a message type by name and return the corresponding flag set. Returns -1 if no such type found. **/
+int log_find_type(const char *name);
+
+/** Given a flag set, extract the message type ID and return its name. **/
+char *log_type_name(uns flags);
+
/*** === Operations on streams ***/
/**