summaryrefslogtreecommitdiffstats
path: root/liblog.h
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2025-02-09 15:04:27 +0100
committerMattias Andrée <m@maandree.se>2025-02-09 15:04:27 +0100
commited004cba0e8d1d383def76f795b1e63ba0aaa89a (patch)
treeb12e5f23329f631b66c19b932551e4dff5aa477f /liblog.h
downloadliblog-ed004cba0e8d1d383def76f795b1e63ba0aaa89a.tar.gz
liblog-ed004cba0e8d1d383def76f795b1e63ba0aaa89a.tar.bz2
liblog-ed004cba0e8d1d383def76f795b1e63ba0aaa89a.tar.xz
First commit (everything was written 2024)
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
-rw-r--r--liblog.h1583
1 files changed, 1583 insertions, 0 deletions
diff --git a/liblog.h b/liblog.h
new file mode 100644
index 0000000..5e2fad1
--- /dev/null
+++ b/liblog.h
@@ -0,0 +1,1583 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBLOG_H
+#define LIBLOG_H
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+
+
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wformat-nonliteral"
+# pragma clang diagnostic ignored "-Wpadded"
+#elif defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
+
+
+/**
+ * Mark the message as incomplete an deferred
+ * printing until LIBLOG_XLOG_UNCORK is used.
+ */
+#define LIBLOG_XLOG_CORK 0x0001
+
+/**
+ * Output message printed since the first
+ * LIBLOG_XLOG_CORK (after the last
+ * LIBLOG_XLOG_UNCORK if any) as one complete
+ * message.
+ */
+#define LIBLOG_XLOG_UNCORK 0x0002
+
+/**
+ * Output a backtrace even if the it is not
+ * configured that backtraces should be printed
+ * for the selected log level.
+ */
+#define LIBLOG_XLOG_BACKTRACE 0x0004
+
+/**
+ * Do not output a backtrace even if the it is
+ * configured that backtraces should be printed
+ * for the selected log level.
+ */
+#define LIBLOG_XLOG_NO_BACKTRACE 0x0008
+
+/**
+ * Do not output any new text (apport from potential
+ * backtrace); allowing `fmt` to be `NULL`.
+ */
+#define LIBLOG_XLOG_NO_TEXT 0x0010
+
+
+/**
+ * Opaque data type for the internal state
+ * of a `struct liblog_context`
+ */
+struct liblog_context_internal_state;
+
+/**
+ * Log levels
+ */
+enum liblog_level {
+ /**
+ * System is unusable
+ */
+ LIBLOG_EMERGENCY = 0,
+
+ /**
+ * Action must be taken immediately
+ */
+ LIBLOG_ALERT = 100,
+
+ /**
+ * Critical condition
+ */
+ LIBLOG_CRITICAL = 200,
+
+ /**
+ * Error condition
+ */
+ LIBLOG_ERROR = 300,
+
+ /**
+ * Warning condition
+ */
+ LIBLOG_WARNING = 400,
+
+ /**
+ * Normal, but significant, condition
+ */
+ LIBLOG_NOTICE = 500,
+
+ /**
+ * Informational message
+ */
+ LIBLOG_INFO = 600,
+
+ /**
+ * Less verbose debug-level message: what is happening on a high level
+ */
+ LIBLOG_TRACE = 700,
+
+ /**
+ * More verbose debug-level message: detailed information about what is going on
+ */
+ LIBLOG_DEBUG = 800
+};
+
+/**
+ * Log channel types
+ */
+enum liblog_sink {
+ /**
+ * Output to syslog
+ */
+ LIBLOG_SYSLOG,
+
+ /**
+ * Output to a file descriptor
+ */
+ LIBLOG_FILE,
+
+ /**
+ * Output to a `FILE`
+ */
+ LIBLOG_STREAM
+};
+
+/**
+ * Log output configurations; mapping of log levels to log channels
+ *
+ * Destroy with `liblog_destroy_output` if destroying manually
+ */
+struct liblog_output {
+ /**
+ * User defined data
+ *
+ * This could for example be a path name to the output
+ * file so that the application knows which file that
+ * should be subject to rotation when online log rotation
+ * is performed
+ */
+ void *userdata;
+
+ /**
+ * The prefix for each log line
+ *
+ * A string where the following special symbols will be replaced
+ * - %{ltime: %} span that marks formatting of the current local time with strftime(3)
+ * - %{utime: %} span that marks formatting of the current UTC time with strftime(3)
+ * - %[nano] the nanoseconds of the current time, printed with 9 digits
+ * - %[micro] the microseconds of the current time, printed with 6 digits
+ * - %[milli] the milliseconds of the current time, printed with 3 digits
+ * - %[centi] the centiseconds of the current time, printed with 2 digits
+ * - %[deci] the deciseconds of the current time, printed with 1 digit
+ * - %[function] function where the log message is being printed from
+ * - %[file] file where the log message is being printed from
+ * - %[line] line in file where the log message is being printed from
+ * - %[level] log level for the message rounded down to a predefined value
+ * (printed as string)
+ * - %[xlevel] the exact log level for the message, printed as the name of
+ * of the log level rounded down to a predfined value, followed
+ * by an adjustment
+ * - %[tid] the process's thread ID
+ * - %[pid] the process's thread group ID (process ID)
+ * - %[ppid] the process's parent process ID
+ * - %[pgid] the process's process group ID
+ * - %[sid] the process's session ID
+ * - %[uid] the real user ID of the process
+ * - %[euid] the effective user ID of the process
+ * - %[gid] the real group ID of the process
+ * - %[egid] the effective group ID of the process
+ * - %[name] the name of process
+ * - %[argv0] the value of the global `const char *argv0`
+ * - %% a literal %
+ *
+ * If `NULL`, this with be replace with a default format
+ */
+ const char *prefixfmt;
+
+ /**
+ * If set `.lowest_verbosity` is treated as set to
+ * the lowest possible value
+ */
+ unsigned lowest_verbosity_unlimited : 1;
+
+ /**
+ * If set `.higest_verbosity` is treated as set to
+ * the highest possible value
+ */
+ unsigned highest_verbosity_unlimited : 1;
+
+ /**
+ * If set, each log message will be prefixed with
+ * a backtrace
+ */
+ unsigned use_backtrace : 1;
+
+ unsigned : 0;
+
+ /**
+ * The lowest log level, in regards to verbosity
+ * but higest in regard to criticality, for which
+ * this log output channel shall be used
+ *
+ * Must not be greater than `.highest_verbosity`
+ */
+ enum liblog_level lowest_verbosity;
+
+ /**
+ * The higest log level, in regards to verbosity
+ * but lowest in regard to criticality, for which
+ * this log output channel shall be used
+ *
+ * Must not be less than `.lowest_verbosity`
+ */
+ enum liblog_level highest_verbosity;
+
+ /**
+ * The output channel type
+ */
+ enum liblog_sink sink_type;
+
+ /**
+ * The output channel
+ */
+ union {
+ /**
+ * Used when `.sink_type` is `LIBLOG_SYSLOG`
+ *
+ * The application is responsible for opening and closing syslog
+ */
+ struct {
+ /**
+ * The syslog log level to use
+ */
+ int level;
+ } syslog;
+
+ /**
+ * Used when `.sink_type` is `LIBLOG_FILE`
+ */
+ struct {
+ /**
+ * The file descriptor to write to
+ */
+ int fd;
+
+ /**
+ * Whether the library shall close the file descriptor
+ * when destroying the `struct liblog_output` object
+ */
+ unsigned owns_fd : 1;
+ } file;
+
+ /**
+ * Used when `.sink_type` is `LIBLOG_STREAM`
+ */
+ struct {
+ /**
+ * The stream to write to
+ */
+ FILE *stream;
+
+ /**
+ * Whether the library shall close the stream
+ * when destroying the `struct liblog_output` object
+ */
+ unsigned owns_stream : 1;
+ } stream;
+ } sink;
+};
+
+/**
+ * Logging configurations and state
+ *
+ * Initialise with `liblog_init_context`, and then
+ * configure output using any of the follow functions:
+ * - liblog_use_fd
+ * - liblog_use_fd_for_range
+ * - liblog_use_file
+ * - liblog_use_file_for_range
+ * - liblog_use_stderr
+ * - liblog_use_stderr_for_range
+ * - liblog_use_stream
+ * - liblog_use_stream_for_range
+ * - liblog_use_syslog
+ * - liblog_use_syslog_for_range
+ * - liblog_use_output
+ *
+ * Destroy with `liblog_destroy_context`
+ */
+struct liblog_context {
+ /**
+ * Opaque state
+ */
+ struct liblog_context_internal_state *internal_state;
+
+ /**
+ * Log output configurations; mapping of log levels to log channels
+ */
+ struct liblog_output *outputs;
+
+ /**
+ * Number of elements in noutputs
+ */
+ size_t noutputs;
+
+ /**
+ * Mask of log level groups to exclude when logging
+ */
+ unsigned logmask;
+};
+/* TODO add multithreading support */
+
+
+
+/* for internal use { */
+#define LIBLOG_VA__(FUNC, ...)\
+ int ret;\
+ va_list args;\
+ va_start(args, fmt);\
+ ret = FUNC(__VA_ARGS__, args);\
+ va_end(args);\
+ return ret
+
+#define LIBLOG_OUTPUT_UNRANGED__(...)\
+ (&(struct liblog_output){\
+ .userdata = NULL,\
+ .prefixfmt = prefixfmt,\
+ .lowest_verbosity_unlimited = 1U,\
+ .highest_verbosity_unlimited = 1U,\
+ .use_backtrace = (use_backtrace ? 1U : 0U),\
+ __VA_ARGS__\
+ })
+
+#define LIBLOG_OUTPUT_RANGED__(...)\
+ (&(struct liblog_output){\
+ .userdata = NULL,\
+ .prefixfmt = prefixfmt,\
+ .lowest_verbosity_unlimited = 0U,\
+ .highest_verbosity_unlimited = 0U,\
+ .use_backtrace = (use_backtrace ? 1U : 0U),\
+ .lowest_verbosity = least_verbose,\
+ .highest_verbosity = most_verbose,\
+ __VA_ARGS__\
+ })
+
+#if defined(__clang__)
+# define LIBLOG_PRINTF__(FMTIDX) __attribute__((__format__(__printf__, (FMTIDX), (FMTIDX) + 1)))
+# define LIBLOG_VPRINTF__(FMTIDX) __attribute__((__format__(__printf__, (FMTIDX), 0)))
+#elif defined(__GNUC__)
+# define LIBLOG_PRINTF__(FMTIDX) __attribute__((__format__(__gnu_printf__, (FMTIDX), (FMTIDX) + 1)))
+# define LIBLOG_VPRINTF__(FMTIDX) __attribute__((__format__(__gnu_printf__, (FMTIDX), 0)))
+#else
+# define LIBLOG_PRINTF__(FMTIDX)
+# define LIBLOG_VPRINTF__(FMTIDX)
+#endif
+
+#if defined(__GNUC__)
+# define LIBLOG_CONST__ __attribute__((__const__))
+#else
+# define LIBLOG_CONST__
+#endif
+
+LIBLOG_CONST__ unsigned liblog_logmask__(enum liblog_level least_verbose, enum liblog_level most_verbose);
+/* } */
+
+
+
+/**
+ * Initialise a `struct liblog_context`
+ *
+ * @param ctx That object to initialise
+ * @return 0 on success, -1 on failure
+ */
+int liblog_init_context(struct liblog_context *ctx);
+
+/**
+ * Destroy a `struct liblog_context`
+ *
+ * @param ctx That object to destroy
+ * @return 0 on success, -1 on failure (object will
+ * still be completely destroyed)
+ */
+int liblog_destroy_context(struct liblog_context *ctx);
+
+/**
+ * Destroy a `struct liblog_output`
+ *
+ * @param output That object to destroy
+ * @return 0 on success, -1 on failure (object will
+ * still be completely destroyed)
+ */
+int liblog_destroy_output(struct liblog_output *output);
+
+
+/**
+ * Remove log level mask, causing all log messages, that
+ * have an output configured, to be printed
+ *
+ * @param ctx Logging configurations and state
+ */
+inline void
+liblog_clear_mask(struct liblog_context *ctx)
+{ if (ctx) ctx->logmask = 0U; }
+
+/**
+ * Apply log level mask that is configured in the
+ * process's environment variable "LIBLOG_LOGMASK"
+ *
+ * This is done automatically by `liblog_init_context`
+ *
+ * If the LIBLOG_LOGMASK environment variable is
+ * unset or empty, anything more verbose than a
+ * some specific level (currently `LIBLOG_WARNING`)
+ * will be filtered.
+ *
+ * @param ctx Logging configurations and state
+ */
+void liblog_apply_env_mask(struct liblog_context *ctx);
+
+/**
+ * Stop log messages within a certain range of
+ * log levels from being printed
+ *
+ * @param ctx Logging configurations and state
+ * @param least_verbose The lowest (least verbose, most critical) log level
+ * to filter out; will be rounded up or down (unspecified
+ * which) to the closest predefined log level value
+ * @param most_verbose The highest (most verbose, least critical) log level
+ * to filter out; will be rounded up or down (unspecified
+ * which) to the closest predefined log level value
+ *
+ * This function has no effect if, after rounding, `least_verbose > most_verbose`
+ */
+inline void
+liblog_mask_range(struct liblog_context *ctx, enum liblog_level least_verbose, enum liblog_level most_verbose)
+{ if (ctx) ctx->logmask |= liblog_logmask__(least_verbose, most_verbose); }
+
+/**
+ * Stop log messages with a certain log level or
+ * higher (more verbose, less critical) from being printed
+ *
+ * @param ctx Logging configurations and state
+ * @param least The lowest (least verbose, most critical) log level to
+ * filter out; will be rounded up or down (unspecified
+ * which) to the closest predefined log level value
+ */
+inline void
+liblog_mask_verbose(struct liblog_context *ctx, enum liblog_level least)
+{ liblog_mask_range(ctx, least, LIBLOG_DEBUG); }
+
+/**
+ * Stop log messages with a certain log level group
+ * (all levels up to but excluding the next predefined
+ * log level) from being printed
+ *
+ * @param ctx Logging configurations and state
+ * @param group The log level to filter out; will be rounded
+ * up or down (unspecified which) to the closest
+ * predefined log level value
+ */
+inline void
+liblog_mask_level(struct liblog_context *ctx, enum liblog_level group)
+{ liblog_mask_range(ctx, group, group); }
+
+/**
+ * Stop filtering out log messages within a certain
+ * range of log levels from being printed
+ *
+ * @param ctx Logging configurations and state
+ * @param least_verbose The lowest (least verbose, most critical) log level to
+ * stop filtering out; will be rounded up or down (unspecified
+ * which) to the closest predefined log level value
+ * @param most_verbose The highest (most verbose, least critical) log level to
+ * filtering out; will be rounded up or down (unspecified
+ * which) to the closest predefined log level value
+ *
+ * This function has no effect if, after rounding, `least_verbose > most_verbose`
+ */
+inline void
+liblog_unmask_range(struct liblog_context *ctx, enum liblog_level least_verbose, enum liblog_level most_verbose)
+{ if (ctx) ctx->logmask &= ~liblog_logmask__(least_verbose, most_verbose); }
+
+/**
+ * Stop filtering out log messages with a certain log level or
+ * higher (more verbose, less critical) from being printed
+ *
+ * @param ctx Logging configurations and state
+ * @param least The lowest (least verbose, most critical) log level to
+ * stop filtering out; will be rounded up or down (unspecified
+ * which) to the closest predefined log level value
+ */
+inline void
+liblog_unmask_verbose(struct liblog_context *ctx, enum liblog_level least)
+{ liblog_unmask_range(ctx, least, LIBLOG_DEBUG); }
+
+/**
+ * Stop filtering out log messages with a certain log level
+ * group (all levels up to but excluding the next predefined
+ * log level) from being printed
+ *
+ * @param ctx Logging configurations and state
+ * @param group The log level to stop filtering out; will be
+ * rounded up or down (unspecified which) to the
+ * closest predefined log level value
+ */
+inline void
+liblog_unmask_level(struct liblog_context *ctx, enum liblog_level group)
+{ liblog_unmask_range(ctx, group, group); }
+
+
+/**
+ * Add a log output
+ *
+ * @param ctx Logging configurations and state
+ * @param output The configurations for the additional output
+ * @return The new output configuration (this is an object
+ * owned by `ctx` and should not be deallocated,
+ * it is returned so that changes can be made)
+ * on success, `NULL` on failure
+ */
+struct liblog_output *liblog_use_output(struct liblog_context *ctx, const struct liblog_output *output);
+
+/**
+ * Set up logging with syslog(3)
+ *
+ * @param ctx Logging configurations and state
+ * @param prefixfmt See `.prefixfmt` in `struct liblog_output`
+ * @param use_backtrace Whether each log message should be prefix with a log backtrace
+ * @return 0 on success, -1 on failure
+ *
+ * This function adds multi new output configurations to `ctx`
+ */
+int liblog_use_syslog(struct liblog_context *ctx, const char *prefixfmt, int use_backtrace);
+
+/**
+ * Set up logging with syslog(3)
+ *
+ * @param ctx Logging configurations and state
+ * @param syslog_level The syslog(3) log level that shall be used
+ * @param prefixfmt See `.prefixfmt` in `struct liblog_output`
+ * @param use_backtrace Whether each log message should be prefix with a log backtrace
+ * @param least_verbose Lower (in regard to verbosity, upper in regards to criticality),
+ * inclusive bound for the range liblog log level for which log
+ * messages should be output to the new output
+ * @param most_verbose Upper (in regard to verbosity, lower in regards to criticality),
+ * inclusive bound for the range liblog log level for which log
+ * messages should be output to the new output
+ * @return The new output configuration (this is an object
+ * owned by `ctx` and should not be deallocated,
+ * it is returned so that changes can be made)
+ * on success, `NULL` on failure
+ */
+inline struct liblog_output *
+liblog_use_syslog_for_range(struct liblog_context *ctx, int syslog_level, const char *prefixfmt, int use_backtrace,
+ enum liblog_level least_verbose, enum liblog_level most_verbose)
+{ return liblog_use_output(ctx, LIBLOG_OUTPUT_RANGED__(.sink_type = LIBLOG_SYSLOG, .sink.syslog = {syslog_level})); }
+
+/**
+ * Set up logging to a file descriptor
+ *
+ * @param ctx Logging configurations and state
+ * @param fd The file descriptor to log to
+ * @param prefixfmt See `.prefixfmt` in `struct liblog_output`
+ * @param use_backtrace Whether each log message should be prefix with a log backtrace
+ * @return The new output configuration (this is an object
+ * owned by `ctx` and should not be deallocated,
+ * it is returned so that changes can be made)
+ * on success, `NULL` on failure
+ */
+inline struct liblog_output *
+liblog_use_fd(struct liblog_context *ctx, int fd, const char *prefixfmt, int use_backtrace)
+{ return liblog_use_output(ctx, LIBLOG_OUTPUT_UNRANGED__(.sink_type = LIBLOG_FILE, .sink.file = {fd, 0})); }
+
+/**
+ * Set up logging to a file descriptor
+ *
+ * @param ctx Logging configurations and state
+ * @param fd The file descriptor to log to
+ * @param prefixfmt See `.prefixfmt` in `struct liblog_output`
+ * @param use_backtrace Whether each log message should be prefix with a log backtrace
+ * @param least_verbose Lower (in regard to verbosity, upper in regards to criticality),
+ * inclusive bound for the range liblog log level for which log
+ * messages should be output to the new output
+ * @param most_verbose Upper (in regard to verbosity, lower in regards to criticality),
+ * inclusive bound for the range liblog log level for which log
+ * messages should be output to the new output
+ * @return The new output configuration (this is an object
+ * owned by `ctx` and should not be deallocated,
+ * it is returned so that changes can be made)
+ * on success, `NULL` on failure
+ */
+inline struct liblog_output *
+liblog_use_fd_for_range(struct liblog_context *ctx, int fd, const char *prefixfmt, int use_backtrace,
+ enum liblog_level least_verbose, enum liblog_level most_verbose)
+{ return liblog_use_output(ctx, LIBLOG_OUTPUT_RANGED__(.sink_type = LIBLOG_FILE, .sink.file = {fd, 0})); }
+
+/**
+ * Set up logging to an output stream
+ *
+ * @param ctx Logging configurations and state
+ * @param stream The stream to log to
+ * @param prefixfmt See `.prefixfmt` in `struct liblog_output`
+ * @param use_backtrace Whether each log message should be prefix with a log backtrace
+ * @return The new output configuration (this is an object
+ * owned by `ctx` and should not be deallocated,
+ * it is returned so that changes can be made)
+ * on success, `NULL` on failure
+ */
+inline struct liblog_output *
+liblog_use_stream(struct liblog_context *ctx, FILE *stream, const char *prefixfmt, int use_backtrace)
+{ return liblog_use_output(ctx, LIBLOG_OUTPUT_UNRANGED__(.sink_type = LIBLOG_STREAM, .sink.stream = {stream, 0})); }
+
+/**
+ * Set up logging to an output stream
+ *
+ * @param ctx Logging configurations and state
+ * @param stream The stream to log to
+ * @param prefixfmt See `.prefixfmt` in `struct liblog_output`
+ * @param use_backtrace Whether each log message should be prefix with a log backtrace
+ * @param least_verbose Lower (in regard to verbosity, upper in regards to criticality),
+ * inclusive bound for the range liblog log level for which log
+ * messages should be output to the new output
+ * @param most_verbose Upper (in regard to verbosity, lower in regards to criticality),
+ * inclusive bound for the range liblog log level for which log
+ * messages should be output to the new output
+ * @return The new output configuration (this is an object
+ * owned by `ctx` and should not be deallocated,
+ * it is returned so that changes can be made)
+ * on success, `NULL` on failure
+ */
+inline struct liblog_output *
+liblog_use_stream_for_range(struct liblog_context *ctx, FILE *stream, const char *prefixfmt, int use_backtrace,
+ enum liblog_level least_verbose, enum liblog_level most_verbose)
+{ return liblog_use_output(ctx, LIBLOG_OUTPUT_RANGED__(.sink_type = LIBLOG_STREAM, .sink.stream = {stream, 0})); }
+
+/**
+ * Set up logging to a file
+ *
+ * @param ctx Logging configurations and state
+ * @param dirfd File descriptor to the directory `path` is relative to if
+ * it is a relative path, or -1 to for the path to be absolute,
+ * failing with EINVAL if it is relative); AT_FDCWD for the
+ * current working directory
+ * @param path The path of the file to write to, if `NULL` or `""`
+ * dirfd will be used as the file descriptor to write to;
+ * if the file exists, it is opened in append mode, otherwise
+ * it is created to readable by every user but only writable
+ * by the current user
+ * @param prefixfmt See `.prefixfmt` in `struct liblog_output`
+ * @param use_backtrace Whether each log message should be prefix with a log backtrace
+ * @return The new output configuration (this is an object
+ * owned by `ctx` and should not be deallocated,
+ * it is returned so that changes can be made)
+ * on success, `NULL` on failure
+ */
+struct liblog_output *liblog_use_file(struct liblog_context *ctx, int dirfd, const char *path,
+ const char *prefixfmt, int use_backtrace);
+
+/**
+ * Set up logging to a file
+ *
+ * @param ctx Logging configurations and state
+ * @param dirfd File descriptor to the directory `path` is relative to if
+ * it is a relative path, or -1 to for the path to be absolute,
+ * failing with EINVAL if it is relative); AT_FDCWD for the
+ * current working directory
+ * @param path The path of the file to write to, if `NULL` or `""`
+ * dirfd will be used as the file descriptor to write to;
+ * if the file exists, it is opened in append mode, otherwise
+ * it is created to readable by every user but only writable
+ * by the current user
+ * @param prefixfmt See `.prefixfmt` in `struct liblog_output`
+ * @param use_backtrace Whether each log message should be prefix with a log backtrace
+ * @param least_verbose Lower (in regard to verbosity, upper in regards to criticality),
+ * inclusive bound for the range liblog log level for which log
+ * messages should be output to the new output
+ * @param most_verbose Upper (in regard to verbosity, lower in regards to criticality),
+ * inclusive bound for the range liblog log level for which log
+ * messages should be output to the new output
+ * @return The new output configuration (this is an object
+ * owned by `ctx` and should not be deallocated,
+ * it is returned so that changes can be made)
+ * on success, `NULL` on failure
+ */
+struct liblog_output *liblog_use_file_for_range(struct liblog_context *ctx, int dirfd, const char *path,
+ const char *prefixfmt, int use_backtrace,
+ enum liblog_level least_verbose, enum liblog_level most_verbose);
+
+/**
+ * Set up logging to the standard output
+ *
+ * @param ctx Logging configurations and state
+ * @param prefixfmt See `.prefixfmt` in `struct liblog_output`
+ * @param use_backtrace Whether each log message should be prefix with a log backtrace
+ * @return The new output configuration (this is an object
+ * owned by `ctx` and should not be deallocated,
+ * it is returned so that changes can be made)
+ * on success, `NULL` on failure
+ */
+inline struct liblog_output *
+liblog_use_stderr(struct liblog_context *ctx, const char *prefixfmt, int use_backtrace)
+{ return liblog_use_fd(ctx, 2, prefixfmt, use_backtrace); }
+
+/**
+ * Set up logging to the standard output
+ *
+ * @param ctx Logging configurations and state
+ * @param prefixfmt See `.prefixfmt` in `struct liblog_output`
+ * @param use_backtrace Whether each log message should be prefix with a log backtrace
+ * @param least_verbose Lower (in regard to verbosity, upper in regards to criticality),
+ * inclusive bound for the range liblog log level for which log
+ * messages should be output to the new output
+ * @param most_verbose Upper (in regard to verbosity, lower in regards to criticality),
+ * inclusive bound for the range liblog log level for which log
+ * messages should be output to the new output
+ * @return The new output configuration (this is an object
+ * owned by `ctx` and should not be deallocated,
+ * it is returned so that changes can be made)
+ * on success, `NULL` on failure
+ */
+inline struct liblog_output *
+liblog_use_stderr_for_range(struct liblog_context *ctx, const char *prefixfmt, int use_backtrace,
+ enum liblog_level least_verbose, enum liblog_level most_verbose)
+{ return liblog_use_fd_for_range(ctx, 2, prefixfmt, use_backtrace, least_verbose, most_verbose); }
+
+
+/**
+ * Write a log message with a custom log level
+ *
+ * This function's behaviour is customisable
+ * using its `flags` parameter
+ *
+ * @param ctx Logging configurations and state
+ * @param level The log level for the message; does not have to
+ * be predefined in `enum liblog_level`
+ * @param flags Modifications the the function's behaviour;
+ * may be 0 or the OR of any of the following values:
+ * - LIBLOG_XLOG_CORK:
+ * Mark the message as incomplete an deferred
+ * printing until LIBLOG_XLOG_UNCORK is used.
+ * - LIBLOG_XLOG_UNCORK:
+ * Output message printed since the first
+ * LIBLOG_XLOG_CORK (after the last
+ * LIBLOG_XLOG_UNCORK if any) as one complete
+ * message.
+ * - LIBLOG_XLOG_BACKTRACE:
+ * Output a backtrace even if the it is not
+ * configured that backtraces should be printed
+ * for the selected log level.
+ * - LIBLOG_XLOG_NO_BACKTRACE:
+ * Do not output a backtrace even if the it is
+ * configured that backtraces should be printed
+ * for the selected log level.
+ * - LIBLOG_XLOG_NO_TEXT:
+ * Do not output any new text (apport from potential
+ * backtrace); allowing `fmt` to be `NULL`.
+ * However, LIBLOG_XLOG_CORK and LIBLOG_XLOG_UNCORK
+ * cannot be combined, nor can LIBLOG_XLOG_BACKTRACE
+ * and LIBLOG_XLOG_NO_BACKTRACE be combined
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(4) int
+liblog_vxlog(struct liblog_context *ctx, enum liblog_level level, unsigned flags, const char *fmt, va_list args);
+
+/**
+ * Write a log message with a custom log level
+ *
+ * This function's behaviour is customisable
+ * using its `flags` parameter
+ *
+ * @param ctx Logging configurations and state
+ * @param level The log level for the message; does not have to
+ * be predefined in `enum liblog_level`
+ * @param flags Modifications the the function's behaviour;
+ * may be 0 or the OR of any of the following values:
+ * - LIBLOG_XLOG_CORK:
+ * Mark the message as incomplete an deferred
+ * printing until LIBLOG_XLOG_UNCORK is used
+ * - LIBLOG_XLOG_UNCORK:
+ * Output message printed since the first
+ * LIBLOG_XLOG_CORK (after the last
+ * LIBLOG_XLOG_UNCORK if any) as one complete
+ * message
+ * - LIBLOG_XLOG_BACKTRACE:
+ * Output a backtrace even if the it is not
+ * configured that backtraces should be printed
+ * for the selected log level
+ * - LIBLOG_XLOG_NO_BACKTRACE:
+ * Do not output a backtrace even if the it is
+ * configured that backtraces should be printed
+ * for the selected log level
+ * - LIBLOG_XLOG_NO_TEXT:
+ * Do not output any new text (apport from potential
+ * backtrace); allowing `fmt` to be `NULL`.
+ * However, LIBLOG_XLOG_CORK and LIBLOG_XLOG_UNCORK
+ * cannot be combined, nor can LIBLOG_XLOG_BACKTRACE
+ * and LIBLOG_XLOG_NO_BACKTRACE be combined
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(4) inline int
+liblog_xlog(struct liblog_context *ctx, enum liblog_level level, unsigned flags, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vxlog, ctx, level, flags, fmt); }
+
+
+/**
+ * If there is an incomplete log message being constructed,
+ * terminate it and print it
+ *
+ * @param ctx Logging configurations and state
+ * @return 0 on success, -1 on failure
+ *
+ * @seealso liblog_xlog
+ * @seealso liblog_dump_backtrace_cork
+ * @seealso liblog_log_cork
+ * @seealso liblog_log_no_backtrace_cork
+ * @seealso liblog_emergency_cork
+ * @seealso liblog_alert_cork
+ * @seealso liblog_critical_cork
+ * @seealso liblog_error_cork
+ * @seealso liblog_warning_cork
+ * @seealso liblog_notice_cork
+ * @seealso liblog_info_cork
+ * @seealso liblog_trace_cork
+ * @seealso liblog_debug_cork
+ */
+inline int
+liblog_uncork(struct liblog_context *ctx)
+{ return liblog_xlog(ctx, 0, LIBLOG_XLOG_NO_BACKTRACE | LIBLOG_XLOG_NO_TEXT | LIBLOG_XLOG_UNCORK, NULL); }
+
+
+/**
+ * Write the backtrace as a log message with a custom log level
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param level The log level for the message; does not have to
+ * be predefined in `enum liblog_level`
+ * @return 0 on success, -1 on failure
+ */
+inline int
+liblog_dump_backtrace(struct liblog_context *ctx, enum liblog_level level)
+{ return liblog_xlog(ctx, level, LIBLOG_XLOG_BACKTRACE | LIBLOG_XLOG_NO_TEXT, NULL); }
+
+/**
+ * Write the backtrace as a log message with a custom log level
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * The backtrace will be terminated by a new line
+ *
+ * @param ctx Logging configurations and state
+ * @param level The log level for the message; does not have to
+ * be predefined in `enum liblog_level`
+ * @return 0 on success, -1 on failure
+ */
+inline int
+liblog_dump_backtrace_cork(struct liblog_context *ctx, enum liblog_level level)
+{ return liblog_xlog(ctx, level, LIBLOG_XLOG_BACKTRACE | LIBLOG_XLOG_NO_TEXT | LIBLOG_XLOG_CORK, NULL); }
+
+
+/**
+ * Write a log message with a custom log level
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param level The log level for the message; does not have to
+ * be predefined in `enum liblog_level`
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(3) inline int
+liblog_vlog(struct liblog_context *ctx, enum liblog_level level, const char *fmt, va_list args)
+{ return liblog_xlog(ctx, level, 0, fmt, args); }
+
+/**
+ * Write a log message with a custom log level
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param level The log level for the message; does not have to
+ * be predefined in `enum liblog_level`
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(3) inline int
+liblog_log(struct liblog_context *ctx, enum liblog_level level, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vlog, ctx, level, fmt); }
+
+/**
+ * Write a log message with a custom log level
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param level The log level for the message; does not have to
+ * be predefined in `enum liblog_level`
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(3) inline int
+liblog_vlog_cork(struct liblog_context *ctx, enum liblog_level level, const char *fmt, va_list args)
+{ return liblog_xlog(ctx, level, LIBLOG_XLOG_CORK, fmt, args); }
+
+/**
+ * Write a log message with a custom log level
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param level The log level for the message; does not have to
+ * be predefined in `enum liblog_level`
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(3) inline int
+liblog_log_cork(struct liblog_context *ctx, enum liblog_level level, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vlog_cork, ctx, level, fmt); }
+
+
+/**
+ * Write a log message with a custom log level
+ *
+ * Even if configured that backtraces should be printed for the
+ * the specificed log level, no backtrace will be printed
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param level The log level for the message; does not have to
+ * be predefined in `enum liblog_level`
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(3) inline int
+liblog_vlog_no_backtrace(struct liblog_context *ctx, enum liblog_level level, const char *fmt, va_list args)
+{ return liblog_xlog(ctx, level, LIBLOG_XLOG_NO_BACKTRACE, fmt, args); }
+
+/**
+ * Write a log message with a custom log level
+ *
+ * Even if configured that backtraces should be printed for the
+ * the specificed log level, no backtrace will be printed
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param level The log level for the message; does not have to
+ * be predefined in `enum liblog_level`
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(3) inline int
+liblog_log_no_backtrace(struct liblog_context *ctx, enum liblog_level level, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vlog_no_backtrace, ctx, level, fmt); }
+
+/**
+ * Write a log message with a custom log level
+ *
+ * Even if configured that backtraces should be printed for the
+ * the specificed log level, no backtrace will be printed
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param level The log level for the message; does not have to
+ * be predefined in `enum liblog_level`
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(3) inline int
+liblog_vlog_no_backtrace_cork(struct liblog_context *ctx, enum liblog_level level, const char *fmt, va_list args)
+{ return liblog_xlog(ctx, level, LIBLOG_XLOG_NO_BACKTRACE | LIBLOG_XLOG_CORK, fmt, args); }
+
+/**
+ * Write a log message with a custom log level
+ *
+ * Even if configured that backtraces should be printed for the
+ * the specificed log level, no backtrace will be printed
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param level The log level for the message; does not have to
+ * be predefined in `enum liblog_level`
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(3) inline int
+liblog_log_no_backtrace_cork(struct liblog_context *ctx, enum liblog_level level, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vlog_no_backtrace_cork, ctx, level, fmt); }
+
+
+/* Everything from this point onwards is just for convenience */
+
+
+/**
+ * Write a log message with log level `LIBLOG_EMERGENCY`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vemergency(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog(ctx, LIBLOG_EMERGENCY, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_EMERGENCY`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_emergency(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vemergency, ctx, fmt); }
+
+/**
+ * Write a log message with log level `LIBLOG_EMERGENCY`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vemergency_cork(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog_cork(ctx, LIBLOG_EMERGENCY, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_EMERGENCY`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_emergency_cork(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vemergency_cork, ctx, fmt); }
+
+
+/**
+ * Write a log message with log level `LIBLOG_ALERT`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_valert(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog(ctx, LIBLOG_ALERT, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_ALERT`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_alert(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_valert, ctx, fmt); }
+
+/**
+ * Write a log message with log level `LIBLOG_ALERT`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_valert_cork(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog_cork(ctx, LIBLOG_ALERT, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_ALERT`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_alert_cork(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_valert_cork, ctx, fmt); }
+
+
+/**
+ * Write a log message with log level `LIBLOG_CRITICAL`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vcritical(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog(ctx, LIBLOG_CRITICAL, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_CRITICAL`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_critical(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vcritical, ctx, fmt); }
+
+/**
+ * Write a log message with log level `LIBLOG_CRITICAL`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vcritical_cork(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog_cork(ctx, LIBLOG_CRITICAL, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_CRITICAL`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_critical_cork(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vcritical_cork, ctx, fmt); }
+
+
+/**
+ * Write a log message with log level `LIBLOG_ERROR`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_verror(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog(ctx, LIBLOG_ERROR, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_ERROR`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_error(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_verror, ctx, fmt); }
+
+/**
+ * Write a log message with log level `LIBLOG_ERROR`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_verror_cork(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog_cork(ctx, LIBLOG_ERROR, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_ERROR`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_error_cork(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_verror_cork, ctx, fmt); }
+
+
+/**
+ * Write a log message with log level `LIBLOG_WARNING`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vwarning(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog(ctx, LIBLOG_WARNING, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_WARNING`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_warning(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vwarning, ctx, fmt); }
+
+/**
+ * Write a log message with log level `LIBLOG_WARNING`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vwarning_cork(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog_cork(ctx, LIBLOG_WARNING, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_WARNING`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_warning_cork(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vwarning_cork, ctx, fmt); }
+
+
+/**
+ * Write a log message with log level `LIBLOG_NOTICE`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vnotice(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog(ctx, LIBLOG_NOTICE, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_NOTICE`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_notice(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vnotice, ctx, fmt); }
+
+/**
+ * Write a log message with log level `LIBLOG_NOTICE`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vnotice_cork(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog_cork(ctx, LIBLOG_NOTICE, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_NOTICE`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_notice_cork(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vnotice_cork, ctx, fmt); }
+
+
+/**
+ * Write a log message with log level `LIBLOG_INFO`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vinfo(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog(ctx, LIBLOG_INFO, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_INFO`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_info(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vinfo, ctx, fmt); }
+
+/**
+ * Write a log message with log level `LIBLOG_INFO`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vinfo_cork(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog_cork(ctx, LIBLOG_INFO, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_INFO`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_info_cork(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vinfo_cork, ctx, fmt); }
+
+
+/**
+ * Write a log message with log level `LIBLOG_TRACE`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vtrace(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog(ctx, LIBLOG_TRACE, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_TRACE`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_trace(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vtrace, ctx, fmt); }
+
+/**
+ * Write a log message with log level `LIBLOG_TRACE`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vtrace_cork(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog_cork(ctx, LIBLOG_TRACE, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_TRACE`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_trace_cork(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vtrace_cork, ctx, fmt); }
+
+
+/**
+ * Write a log message with log level `LIBLOG_DEBUG`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vdebug(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog(ctx, LIBLOG_DEBUG, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_DEBUG`
+ *
+ * The log message is printed immediately as one complete log message
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_debug(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vdebug, ctx, fmt); }
+
+/**
+ * Write a log message with log level `LIBLOG_DEBUG`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_VPRINTF__(2) inline int
+liblog_vdebug_cork(struct liblog_context *ctx, const char *fmt, va_list args)
+{ return liblog_vlog_cork(ctx, LIBLOG_DEBUG, fmt, args); }
+
+/**
+ * Write a log message with log level `LIBLOG_DEBUG`
+ *
+ * The log message is treated as incomplete, and can be extended using
+ * any log message writing function using the same `ctx`, and will be
+ * printed once `liblog_uncork` is called using the same `ctx`
+ *
+ * @param ctx Logging configurations and state
+ * @param fmt printf(3) format string for the log message
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ */
+LIBLOG_PRINTF__(2) inline int
+liblog_debug_cork(struct liblog_context *ctx, const char *fmt, ...)
+{ LIBLOG_VA__(liblog_vdebug_cork, ctx, fmt); }
+
+
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#elif defined(__GNUC__)
+# pragma GCC diagnostic pop
+#endif
+
+#endif