|
Veritable Lasagna
An Allocator & Data Structure Library for C.
|
Thread-safe, sink-based logging for Veritable Lasagna. More...
Include dependency graph for vl_log.h:
This graph shows which files directly or indirectly include this file:Go to the source code of this file.
Data Structures | |
| struct | vl_log_sink_vtbl |
| Virtual function table for a log sink. More... | |
| struct | vl_log_sink |
| Public descriptor for attaching an output sink to a logger. More... | |
| struct | vl_log_config |
| Configuration used when creating a logger. More... | |
Macros | |
| #define | VL_ENABLE_DEBUG_LOG 1 |
| #define | VL_LOGD_MSG0(msg) vlLogMessageF(VL_ANSI_FG_MAGENTA "[DBG | %s @ line %d] " VL_ANSI_RESET "%s", __FILE__, __LINE__, msg) |
| Debug-only message log routed through the global logger. | |
| #define | VL_LOGD_MSGF(fmt, ...) vlLogMessageF(VL_ANSI_FG_MAGENTA "[DBG | %s @ line %d] " VL_ANSI_RESET fmt, __FILE__, __LINE__, __VA_ARGS__) |
| Debug-only formatted log routed through the global logger. | |
| #define | VL_LOGD_ERR0(msg) vlLogErrorF(VL_ANSI_FG_YELLOW "[DBG | %s @ line %d] " VL_ANSI_RESET "%s", __FILE__, __LINE__, msg) |
| Debug-only error log routed through the global logger. | |
| #define | VL_LOGD_ERRF(fmt, ...) vlLogErrorF(VL_ANSI_FG_YELLOW "[DBG | %s @ line %d] " VL_ANSI_RESET fmt, __FILE__, __LINE__, __VA_ARGS__) |
| Debug-only formatted error log routed through the global logger. | |
| #define | VL_LOG_MSG0(msg) vlLogMessage(msg) |
| Always-enabled message log routed through the global logger. | |
| #define | VL_LOG_MSGF(fmt, ...) vlLogMessageF((fmt), __VA_ARGS__) |
| Always-enabled formatted message log routed through the global logger. | |
| #define | VL_LOG_ERR0(msg) vlLogError(msg) |
| Always-enabled error log routed through the global logger. | |
| #define | VL_LOG_ERRF(fmt, ...) vlLogErrorF((fmt), __VA_ARGS__) |
| Always-enabled formatted error log routed through the global logger. | |
Functions | |
| VL_API vl_logger * | vlLoggerNew (const vl_log_config *config) |
| Create a new logger instance. | |
| VL_API void | vlLoggerDelete (vl_logger *logger) |
| Destroy a logger instance and release all associated resources. | |
| VL_API vl_bool_t | vlLoggerAddSink (vl_logger *logger, vl_log_sink sink) |
| Attach a sink to a logger instance. | |
| VL_API void | vlLoggerMessage (vl_logger *logger, const char *msg) |
| Write a preformatted message through a specific logger. | |
| VL_API void | vlLoggerMessageF (vl_logger *logger, const char *msgFormat,...) |
| Write a formatted message through a specific logger. | |
| VL_API void | vlLoggerFlush (vl_logger *logger) |
| Flush pending messages for a specific logger. | |
| VL_API vl_log_sink | vlLogSinkStdout (void) |
| Create a sink that writes to standard output. | |
| VL_API vl_log_sink | vlLogSinkStream (vl_stream *stream) |
Create a sink that writes to an existing vl_stream. | |
| VL_API void | vlLogInit (const vl_log_config *config) |
| Initialize the global logger. | |
| VL_API void | vlLogFlush (void) |
| Flush the global logger. | |
| VL_API void | vlLogShutdown (void) |
| Shut down and destroy the global logger. | |
| VL_API void | vlLogMessage (const char *msg) |
| Write a preformatted message through the global logger. | |
| VL_API void | vlLogMessageF (const char *msgFormat,...) |
| Write a formatted message through the global logger. | |
| VL_API void | vlLogError (const char *msg) |
| Write an error message through the global logger. | |
| VL_API void | vlLogErrorF (const char *msgFormat,...) |
| Write a formatted error message through the global logger. | |
| VL_API vl_bool_t | vlLogAddSink (vl_log_sink sink) |
| Attach a sink to the global logger. | |
| VL_API vl_bool_t | vlLogAddStdoutSink (void) |
| Convenience helper that attaches a stdout sink to the global logger. | |
| VL_API vl_bool_t | vlLogAddStreamSink (vl_stream *stream) |
Convenience helper that attaches a vl_stream sink to the global logger. | |
Thread-safe, sink-based logging for Veritable Lasagna.
██ ██ ██ █████ ███████ █████ ██████ ███ ██ █████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ███████ ███████ ███████ ██ ███ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ███████ ██ ██ ███████ ██ ██ ██████ ██ ████ ██ ██ ====—: A Data Structure and Algorithms library for C11. :—====
Copyright 2026 Jesse Walker, released under the MIT license. Git Repository: https://github.com/walkerje/veritable_lasagna
This module provides a small logging system built around two ideas:
vl_logger) which own buffering, synchronization, and dispatch behaviorvl_log_sink) which define where bytes are writtenThe API supports both:
vlLoggerNew()vlLog*() familyA logger accepts preformatted messages and forwards them to zero or more attached sinks. Sinks are modular output targets such as:
vl_streamEach logger may operate either:
All logger operations are intended to be safe for concurrent use from multiple threads.
In async mode, producer threads only enqueue work and signal the worker, which helps reduce I/O contention. In sync mode, writes occur before the logging call returns.
Messages are written exactly as provided. This API does not append a newline automatically, so callers should include \n when line-oriented output is desired.
Logger instances own their attached sinks. When a sink is added to a logger, the logger stores a copy of the sink descriptor and assumes ownership of the sink's sink_data. Sink cleanup is performed automatically when the logger is destroyed.
| struct vl_log_sink |
Public descriptor for attaching an output sink to a logger.
A sink is defined by:
vtbl)sink_data)The logger stores a copy of this struct when vlLoggerAddSink() succeeds.
After a successful vlLoggerAddSink(), the logger owns sink_data and will eventually pass it to the sink's destroy callback.
Therefore, callers should treat the sink as "moved" into the logger after successful attachment.
Collaboration diagram for vl_log_sink:| Data Fields | ||
|---|---|---|
| void * | sink_data |
Sink implementation state. Ownership transfers to the logger after successful attachment. |
| const vl_log_sink_vtbl * | vtbl |
Sink callback table. Must not be NULL for a valid sink. |
| struct vl_log_config |
Configuration used when creating a logger.
This structure controls per-logger behavior. The configuration is consumed at logger creation time by vlLoggerNew() or by vlLogInit() for the global logger.
Collaboration diagram for vl_log_config:| Data Fields | ||
|---|---|---|
| vl_bool_t | async |
Enable asynchronous logging. If If Async mode is typically preferred for reducing contention in code paths that log frequently. |
| #define VL_ENABLE_DEBUG_LOG 1 |
| #define VL_LOG_ERR0 | ( | msg | ) | vlLogError(msg) |
Always-enabled error log routed through the global logger.
| #define VL_LOG_ERRF | ( | fmt, | |
| ... | |||
| ) | vlLogErrorF((fmt), __VA_ARGS__) |
Always-enabled formatted error log routed through the global logger.
| #define VL_LOG_MSG0 | ( | msg | ) | vlLogMessage(msg) |
Always-enabled message log routed through the global logger.
| #define VL_LOG_MSGF | ( | fmt, | |
| ... | |||
| ) | vlLogMessageF((fmt), __VA_ARGS__) |
Always-enabled formatted message log routed through the global logger.
| #define VL_LOGD_ERR0 | ( | msg | ) | vlLogErrorF(VL_ANSI_FG_YELLOW "[DBG | %s @ line %d] " VL_ANSI_RESET "%s", __FILE__, __LINE__, msg) |
Debug-only error log routed through the global logger.
| #define VL_LOGD_ERRF | ( | fmt, | |
| ... | |||
| ) | vlLogErrorF(VL_ANSI_FG_YELLOW "[DBG | %s @ line %d] " VL_ANSI_RESET fmt, __FILE__, __LINE__, __VA_ARGS__) |
Debug-only formatted error log routed through the global logger.
| #define VL_LOGD_MSG0 | ( | msg | ) | vlLogMessageF(VL_ANSI_FG_MAGENTA "[DBG | %s @ line %d] " VL_ANSI_RESET "%s", __FILE__, __LINE__, msg) |
Debug-only message log routed through the global logger.
| #define VL_LOGD_MSGF | ( | fmt, | |
| ... | |||
| ) | vlLogMessageF(VL_ANSI_FG_MAGENTA "[DBG | %s @ line %d] " VL_ANSI_RESET fmt, __FILE__, __LINE__, __VA_ARGS__) |
Debug-only formatted log routed through the global logger.
| VL_API vl_bool_t vlLogAddSink | ( | vl_log_sink | sink | ) |
Attach a sink to the global logger.
| sink | Sink descriptor to attach. |
VL_TRUE on success, VL_FALSE on failure.If the global logger is not initialized yet, it may be initialized lazily before the sink is attached.
Here is the call graph for this function:
Here is the caller graph for this function:| VL_API vl_bool_t vlLogAddStdoutSink | ( | void | ) |
Convenience helper that attaches a stdout sink to the global logger.
VL_TRUE on success, VL_FALSE on failure.
Here is the call graph for this function:Convenience helper that attaches a vl_stream sink to the global logger.
| stream | Stream to attach as a sink target. |
VL_TRUE on success, VL_FALSE on failure.
Here is the call graph for this function:| VL_API void vlLogError | ( | const char * | msg | ) |
Write an error message through the global logger.
| msg | NUL-terminated message string. |
This currently behaves like a semantic alias of vlLogMessage(). It exists to make call sites more expressive and to leave room for future severity-aware routing or formatting.
Here is the call graph for this function:| VL_API void vlLogErrorF | ( | const char * | msgFormat, |
| ... | |||
| ) |
Write a formatted error message through the global logger.
| msgFormat | printf-style format string. |
| ... | Format arguments. |
This currently behaves like a semantic alias of vlLogMessageF().
Here is the call graph for this function:| VL_API void vlLogFlush | ( | void | ) |
Flush the global logger.
If the global logger has not been initialized, this function does nothing.
Here is the call graph for this function:| VL_API vl_bool_t vlLoggerAddSink | ( | vl_logger * | logger, |
| vl_log_sink | sink | ||
| ) |
Attach a sink to a logger instance.
| logger | Logger receiving the sink. |
| sink | Sink descriptor to attach. |
VL_TRUE on success, VL_FALSE on failure.On success, the logger stores a copy of sink and assumes ownership of sink.sink_data.
On failure, ownership remains with the caller unless the implementation documents otherwise.
Here is the call graph for this function:
Here is the caller graph for this function:| VL_API void vlLoggerDelete | ( | vl_logger * | logger | ) |
Destroy a logger instance and release all associated resources.
NULL (no-op).| logger | Logger to destroy. NULL is ignored. |
Destruction performs an implicit flush of pending messages before tearing down worker state and attached sinks.
After this call returns, logger must not be used again.
Here is the call graph for this function:
Here is the caller graph for this function:| VL_API void vlLoggerFlush | ( | vl_logger * | logger | ) |
Flush pending messages for a specific logger.
| logger | Logger instance to flush. NULL is ignored. |
Behavior depends on the logger mode:
This function is useful as a synchronization barrier before shutdown, abnormal termination, or assertions in tests.
Here is the call graph for this function:
Here is the caller graph for this function:| VL_API void vlLoggerMessage | ( | vl_logger * | logger, |
| const char * | msg | ||
| ) |
Write a preformatted message through a specific logger.
msg internally. The caller retains ownership of the msg pointer.NULL for msg (treated as empty). logger should not be NULL.NULL for logger.| logger | Logger instance to receive the message. |
| msg | NUL-terminated UTF-8 message string. If NULL, it is treated as an empty string. |
The message is copied internally so the caller retains ownership of msg. No newline is appended automatically.
In async mode, this call typically enqueues the message and returns before sink I/O completes.
Here is the call graph for this function:
Here is the caller graph for this function:| VL_API void vlLoggerMessageF | ( | vl_logger * | logger, |
| const char * | msgFormat, | ||
| ... | |||
| ) |
Write a formatted message through a specific logger.
| logger | Logger instance to receive the message. |
| msgFormat | printf-style format string. |
| ... | Format arguments. |
The formatted message is materialized into logger-owned memory before being enqueued or written.
No newline is appended automatically.
| VL_API vl_logger * vlLoggerNew | ( | const vl_log_config * | config | ) |
Create a new logger instance.
vl_logger handle and is responsible for calling vlLoggerDelete.vlLoggerDelete.NULL if the logger could not be created.NULL if heap allocation fails or if internal synchronization primitives/worker threads cannot be initialized.NULL on failure.| config | Optional logger configuration. If NULL, implementation-defined defaults are used. |
The returned logger initially has no sinks attached. Messages sent to such a logger are accepted but may produce no externally visible output until one or more sinks are added.
Here is the call graph for this function:
Here is the caller graph for this function:| VL_API void vlLogInit | ( | const vl_log_config * | config | ) |
Initialize the global logger.
| config | Optional configuration for the global logger. If NULL, implementation defaults are used. |
This function initializes the process-wide convenience logger used by the vlLog*() functions.
The global logger is intended for applications that want a simple shared logging facility without manually managing a vl_logger*.
Typical usage:
vlLogInit() once during startupvlLogMessage*() during runtimevlLogShutdown() during shutdown
Here is the call graph for this function:
Here is the caller graph for this function:| VL_API void vlLogMessage | ( | const char * | msg | ) |
Write a preformatted message through the global logger.
| msg | NUL-terminated message string. If NULL, treated as an empty string. |
If the global logger has not yet been initialized, it may be initialized lazily using default behavior.
Here is the call graph for this function:
Here is the caller graph for this function:| VL_API void vlLogMessageF | ( | const char * | msgFormat, |
| ... | |||
| ) |
Write a formatted message through the global logger.
| msgFormat | printf-style format string. |
| ... | Format arguments. |
If the global logger has not yet been initialized, it may be initialized lazily using default behavior.
Here is the call graph for this function:| VL_API void vlLogShutdown | ( | void | ) |
Shut down and destroy the global logger.
If the global logger is active, this performs an implicit flush, destroys all attached sinks, stops background worker state if present, and resets the global logger to an uninitialized state.
Reinitialization after shutdown is permitted by calling vlLogInit() again.
Here is the call graph for this function:| VL_API vl_log_sink vlLogSinkStdout | ( | void | ) |
Create a sink that writes to standard output.
vlLoggerAddSink().This sink writes to stdout and flushes it when requested by the logger.
The returned sink is intended to be attached to exactly one logger.
Here is the call graph for this function:
Here is the caller graph for this function:| VL_API vl_log_sink vlLogSinkStream | ( | vl_stream * | stream | ) |
Create a sink that writes to an existing vl_stream.
| stream | Stream to write to. |
vlLoggerAddSink().The sink retains the stream when created and releases it when the sink is destroyed. This allows the stream to remain valid for as long as the logger needs it.
Here is the call graph for this function:
Here is the caller graph for this function: