-/* Logging */
-
-#define L_DEBUG 'D' /* Debugging messages */
-#define L_INFO 'I' /* Informational msgs, warnings and errors */
-#define L_WARN 'W'
-#define L_ERROR 'E'
-#define L_INFO_R 'i' /* Errors caused by external events */
-#define L_WARN_R 'w'
-#define L_ERROR_R 'e'
-#define L_FATAL '!' /* die() */
-
-#define L_SIGHANDLER 0x10000 /* Avoid operations that are unsafe in signal handlers */
-
-extern char *log_title; /* NULL - print no title, default is program name given to log_init() */
-extern char *log_filename; /* Expanded name of the current log file */
-extern int log_pid; /* 0 if shouldn't be logged */
-extern int log_precise_timings; /* Include microsecond timestamps in log messages */
-extern void (*log_die_hook)(void);
-struct tm;
-extern void (*log_switch_hook)(struct tm *tm);
-
-void msg(uns cat, const char *fmt, ...) FORMAT_CHECK(printf,2,3);
-void vmsg(uns cat, const char *fmt, va_list args);
-void die(const char *, ...) NONRET FORMAT_CHECK(printf,1,2);
-void log_init(const char *argv0);
-void log_file(const char *name);
-void log_fork(void); /* Call after fork() to update log_pid */
-
-/* If the log name contains metacharacters for date and time, we switch the logs
- * automatically whenever the name changes. You can disable it and switch explicitly. */
-int log_switch(void);
-void log_switch_disable(void);
-void log_switch_enable(void);
+/***
+ * [[logging]]
+ *
+ * === Basic logging functions (see <<log:,Logging>> and <ucw/log.h> for more)
+ ***/
+
+enum log_levels { /** The available log levels to pass to msg() and friends. **/
+ L_DEBUG=0, // 'D' - Debugging
+ L_INFO, // 'I' - Informational
+ L_WARN, // 'W' - Warning
+ L_ERROR, // 'E' - Error, but non-critical
+ L_INFO_R, // 'i' - An alternative set of levels for messages caused by remote events
+ L_WARN_R, // 'w' (e.g., a packet received via network)
+ L_ERROR_R, // 'e'
+ L_FATAL, // '!' - Fatal error
+ L_MAX
+};
+
+#define LOG_LEVEL_NAMES P(DEBUG) P(INFO) P(WARN) P(ERROR) P(INFO_R) P(WARN_R) P(ERROR_R) P(FATAL)
+
+// Return the letter associated with a given severity level
+#define LS_LEVEL_LETTER(level) ("DIWEiwe!###"[( level )])
+
+#define L_SIGHANDLER 0x80000000 /** Avoid operations that are unsafe in signal handlers **/
+#define L_LOGGER_ERR 0x40000000 /** Used internally to avoid infinite reporting of logging errors **/
+
+/**
+ * This is the basic printf-like function for logging a message.
+ * The @flags contain the log level and possibly other flag bits (like `L_SIGHANDLER`).
+ **/
+void msg(uint flags, const char *fmt, ...) FORMAT_CHECK(printf,2,3);
+void vmsg(uint flags, const char *fmt, va_list args); /** A vararg version of msg(). **/
+void die(const char *, ...) NONRET FORMAT_CHECK(printf,1,2); /** Log a fatal error message and exit the program. **/
+void vdie(const char *fmt, va_list args) NONRET; /** va_list version of die() **/
+
+extern char *log_title; /** An optional log message title. Set to program name by log_init(). **/
+extern int log_pid; /** An optional PID printed in each log message. Set to 0 if it shouldn't be logged. **/
+extern void (*log_die_hook)(void); /** An optional function called just before die() exists. **/ // API: log_die_hook
+
+void log_init(const char *argv0); /** Set @log_title to the program name extracted from @argv[0]. **/
+void log_fork(void); /** Call after fork() to update @log_pid. **/
+void log_file(const char *name); /** Establish logging to the named file. Also redirect stderr there. **/