-#define LS_SET_LEVEL(level) (( level ) << LS_LEVEL_POS )
-#define LS_SET_STRNUM(strnum) (( strnum ) << LS_STRNUM_POS )
-#define LS_SET_FLAGS(flags) (( flags ) << LS_FLAGS_POS )
-#define LS_SET_INTERNAL(intern) (( intern ) << LS_INTERNAL_POS )
-
-// Internal flags of the logsystem
-// Avoid operations that are unsafe in signal handlers
-#define LSFLAG_SIGHANDLER LS_SET_INTERNAL(0x001)
-
-// The module is initialized when a first stream is created.
-// Before that only the default stream exists.
-
-// Initial number of streams to allocate (must be >=2)
-#define LS_INIT_STREAMS 8
-
-/* Return pointer a new (xmalloc()-ated) stream with no handler and an empty substream list. */
-struct log_stream *ls_new(void);
-
-/* Close and xfree() given log_stream */
-/* Does not affect substreams */
-void ls_close(struct log_stream *ls);
-
-/* close all open streams, un-initialize the module, free all memory,
- * use only ls_default_log */
-void ls_close_all(void);
-
-/* add a new substream, xmalloc()-ate a new simp_node */
-void ls_add_substream(struct log_stream *where, struct log_stream *what);
-
-/* remove all occurences of a substream, free() the simp_node */
-/* return number of deleted entries */
-int ls_rm_substream(struct log_stream *where, struct log_stream *what);
-
-/* get a stream by its number (regnum) */
-/* returns NULL for free numbers */
-/* defaults to ls_default_stream for 0 when stream number 0 not set */
-struct log_stream *log_stream_by_flags(uns flags);
-
-/* The proposed alternative to original vmsg() */
-void ls_vmsg(unsigned int cat, const char *fmt, va_list args);
-
-/* The proposed alternative to original msg() */
-void ls_msg(unsigned int cat, const char *fmt, ...);
-
-/* The proposed alternative to original die() */
-void ls_die(const char *fmt, ...);
-
-/* process a message (string) (INTERNAL) */
-/* depth prevents undetected looping */
-/* returns 1 in case of loop detection or other fatal error
- * 0 otherwise */
-int ls_passmsg(int depth, struct log_stream *ls, const char *stime, const char *sutime,
- const char *msg, uns cat);
-
-/* Maximal depth of ls_passmsg recursion */
-#define LS_MAX_DEPTH 64
-
-/* Define an array (growing buffer) for pointers to log_streams. */
-#define GBUF_TYPE struct log_stream*
-#define GBUF_PREFIX(x) lsbuf_##x
-#include "ucw/gbuf.h"
-
-extern struct lsbuf_t log_streams;
-extern int log_streams_after;
-
-/********* Individual handler types (constructors, handlers, destructors) */
-
-/**** standard (filedes) files */
-
-// NOTE:
-// under unix, for ordinary files open in append mode, the writes
-// are atomic (unless you meet the quota or other bad things happen),
-// so using a single log_stream is thread-safe and the file can be shared
-// among multiple processes
-
-/* assign log to a file descriptor */
-/* initialize with the default formatting, does NOT close the descriptor */
-struct log_stream *ls_fdfile_new(int fd);
-
-/* open() a file (append mode) */
-/* initialize with the default formatting */
-struct log_stream *ls_file_new(const char *path);
+#define LS_SET_LEVEL(level) ((level) << LS_LEVEL_POS) /** Convert severity level to flags **/
+#define LS_SET_STRNUM(strnum) ((strnum) << LS_STRNUM_POS) /** Convert stream number to flags **/
+#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 **/
+
+#define LS_NUM_TYPES (1 << LS_TYPE_BITS)
+
+/** 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(uint flags);
+
+/*** === Operations on streams ***/
+
+/**
+ * Allocate a new log stream with no handler and an empty substream list.
+ * Since struct log_stream is followed by private data, @size bytes of memory are allocated
+ * for the whole structure. See below for functions creating specific stream types.
+ **/
+struct log_stream *log_new_stream(size_t size);
+
+/**
+ * Decrement the use count of a stream. If it becomes zero, close the stream,
+ * free its memory, and unlink all its substreams.
+ **/
+int log_close_stream(struct log_stream *ls);
+
+/**
+ * Get a new reference on an existing stream. For convenience, the return value is
+ * equal to the argument @ls.
+ **/
+static inline struct log_stream *log_ref_stream(struct log_stream *ls)
+{
+ ls->use_count++;
+ return ls;
+}
+
+/**
+ * Link a substream to a stream. The substream gains a reference, preventing
+ * it from being freed until it is unlinked.
+ **/
+void log_add_substream(struct log_stream *where, struct log_stream *what);
+
+/**
+ * Unlink all occurrences of a substream @what from stream @where. Each
+ * occurrence loses a reference. If @what is NULL, all substreams are unlinked.
+ * Returns the number of unlinked substreams.
+ **/
+int log_rm_substream(struct log_stream *where, struct log_stream *what);
+
+/**
+ * Set formatting flags of a given stream and all its substreams. The flags are
+ * AND'ed with @mask and OR'ed with @data.
+ **/
+void log_set_format(struct log_stream *ls, uint mask, uint data);
+
+/**
+ * Find a stream by its registration number (in the format of logging flags).
+ * Returns NULL if there is no such stream.
+ **/
+struct log_stream *log_stream_by_flags(uint flags);
+
+/** Return a pointer to the default stream (stream #0). **/
+static inline struct log_stream *log_default_stream(void)
+{
+ return log_stream_by_flags(0);
+}