|
Csilk 0.2.1
A lightweight, high-performance C HTTP web framework
|
Thread-safe structured logger with JSON and human-readable output, file rotation, and ANSI color support. More...
#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <time.h>#include <unistd.h>#include <uv.h>#include "csilk/csilk.h"#include "csilk/reflection/reflect.h"
Data Structures | |
| struct | csilk_log_entry_t |
| Structured log entry type used for JSON-formatted log output. More... | |
| struct | csilk_logger_t |
| Internal logger singleton — holds configuration, file pointer, mutex, and current file size. More... | |
Macros | |
| #define | LOG_ENTRY_MAP(X) |
Functions | |
| static void | rotate_log_files (void) |
| Rotate the current log file by renaming it with a ".1" suffix. | |
| static int | log_text (csilk_log_level_t lv, const char *file, int line, const char *func, const char *msg, int msg_len) |
| Format and write a human-readable plain-text log line. | |
| static cJSON * | build_json_entry (csilk_log_level_t lv, const char *file, int line, const char *func, const char *msg, int msg_len) |
| Build a cJSON object from log entry fields using the reflection engine. | |
| static int | log_json (csilk_log_level_t lv, const char *file, int line, const char *func, cJSON *extra, const char *msg, int msg_len) |
| Format and write a structured JSON log line with optional extra fields. | |
| int | csilk_log_init (csilk_log_config_t config) |
| Initialize (or reinitialize) the global logger with the given configuration. | |
| void | _csilk_log_internal (csilk_log_level_t lv, const char *file, int line, const char *func, const char *fmt,...) |
| Internal: format and emit a log message to the global logger. | |
| void | _csilk_log_structured (csilk_log_level_t lv, const char *file, int line, const char *func, cJSON *extra, const char *fmt,...) |
| Internal: emit a structured JSON log entry with extra key-value fields. | |
| int | csilk_log_is_json (void) |
| Check whether the global logger is configured for structured JSON output. | |
| void | csilk_log_set_request_id (const char *request_id) |
| Set the Request ID for the current thread. | |
| cJSON * | csilk_log_make_kv (const char *key,...) |
| Build a key-value cJSON object for structured logging. | |
| void | csilk_log_close (void) |
| Close the global logger and release resources. | |
Variables | |
| static csilk_logger_t | g_logger = {{0}, NULL, 0, {0}, 0} |
| static _Thread_local char | tl_request_id [37] = {0} |
| static const char * | level_names [] = {"TRACE", "DEBUG", "INFO ", "WARN ", "ERROR", "FATAL"} |
| static const char * | level_colors [] |
Thread-safe structured logger with JSON and human-readable output, file rotation, and ANSI color support.
=== Design ===
The logger is a global singleton (g_logger) protected by a mutex for thread-safe access. Two output modes are available:
Text mode (default): [2024-01-15 10:30:00] INFO [file.c:42] function(): <request_id> message ANSI color codes are added for each level when use_colors is enabled.
JSON mode: {"time_epoch":1705312200,"level":"INFO","request_id":"...", "file":"file.c","line":42,"func":"function","msg":"..."} Uses the csilk reflection engine (CSILK_REGISTER_REFLECT) for automatic struct-to-JSON serialization, avoiding manual JSON string building.
=== Thread Safety ===
All public log macros (CSILK_LOG_I, CSILK_LOG_E, etc.) acquire g_logger.mutex before writing. The thread-local request ID (tl_request_id) allows each thread to track its own request context without contention.
=== File Rotation ===
When max_file_size is set and the current file exceeds it, the logger renames <path> to <path>.1 (single-backup rotation) and opens a new file. Rotation happens inline during log write, protected by the mutex.
=== Log Levels ===
TRACE (0) - Most verbose, for debugging internals DEBUG (1) - Detailed information for developers INFO (2) - Normal operational messages (default) WARN (3) - Unexpected but handled situations ERROR (4) - Errors that don't stop the server FATAL (5) - Critical errors causing shutdown
The level filter is checked inside each log macro call before any formatting or I/O occurs, so disabled levels have near-zero overhead.
| struct csilk_log_entry_t |
Structured log entry type used for JSON-formatted log output.
All fields are fixed-size character arrays to avoid dynamic allocation. The type is registered with the reflection engine for automatic JSON serialization via csilk_json_marshal().
| struct csilk_logger_t |
Internal logger singleton — holds configuration, file pointer, mutex, and current file size.

| Data Fields | ||
|---|---|---|
| csilk_log_config_t | config |
Logger configuration. |
| size_t | current_size |
Current log file size. |
| FILE * | fp |
Output file pointer. |
| int | initialized |
Whether logger is initialized. |
| uv_mutex_t | mutex |
Mutex for thread-safe logging. |
| #define LOG_ENTRY_MAP | ( | X | ) |
| void _csilk_log_internal | ( | csilk_log_level_t | lv, |
| const char * | file, | ||
| int | line, | ||
| const char * | func, | ||
| const char * | fmt, | ||
| ... | |||
| ) |
Internal: format and emit a log message to the global logger.
Internal log function (use macros instead).
Formats the variadic message via vsnprintf, acquires the logger mutex, checks file rotation (if file logging and max_file_size exceeded), and writes the entry as either JSON or plain text depending on configuration.
| lv | Log severity level (filtered against g_logger.config.level). |
| file | Source file name (provided by CSILK_LOG_* macro). |
| line | Source line number (provided by CSILK_LOG_* macro). |
| func | Function name (provided by CSILK_LOG_* macro). |
| fmt | printf-style format string. |
| ... | Variadic arguments for the format string. |
| void _csilk_log_structured | ( | csilk_log_level_t | lv, |
| const char * | file, | ||
| int | line, | ||
| const char * | func, | ||
| cJSON * | extra, | ||
| const char * | fmt, | ||
| ... | |||
| ) |
Internal: emit a structured JSON log entry with extra key-value fields.
Log a structured JSON message with extra key-value fields.
Like _csilk_log_internal() but accepts an additional cJSON object of extra fields. In JSON mode, the extra fields are merged into the output. In text mode, the extra fields are discarded (cJSON_Delete is called).
| lv | Log severity level. |
| file | Source file name. |
| line | Source line number. |
| func | Function name. |
| extra | cJSON object of extra fields to include (ownership taken). |
| fmt | printf-style format string. |
| ... | Variadic arguments. |
|
static |
Build a cJSON object from log entry fields using the reflection engine.
Populates a csilk_log_entry_t struct with the provided metadata, then serializes it to JSON via csilk_json_marshal() and parses the result back into a cJSON object. This round-trip is used to produce consistent JSON output that matches the registered reflection schema.
| lv | Log level. |
| file | Source file name. |
| line | Source line number. |
| func | Function name. |
| msg | Log message content. |
| msg_len | Message length (may truncate to fit the entry struct). |
| void csilk_log_close | ( | void | ) |
Close the global logger and release resources.
Close the global logger.
Closes file handles and destroys mutexes. Safe to call multiple times.
| int csilk_log_init | ( | csilk_log_config_t | config | ) |
Initialize (or reinitialize) the global logger with the given configuration.
Initialize the global logger with config.
Configures the output destination (stdout if no file_path, or a file if set), the minimum log level, coloring (auto-detected for terminals when use_colors is -1), and whether to use structured JSON format. If the logger was previously initialized, csilk_log_close() is called first. A mutex is initialized for thread-safe operation.
| config | Logger configuration struct with desired settings. |
| int csilk_log_is_json | ( | void | ) |
Check whether the global logger is configured for structured JSON output.
Check whether the logger is in JSON format mode.
| cJSON * csilk_log_make_kv | ( | const char * | key, |
| ... | |||
| ) |
Build a key-value cJSON object for structured logging.
Create a simple key-value cJSON object for structured logging.
Helper to create a flat JSON object from a NULL-terminated list of strings. Used primarily with CSILK_LOG_KV.
| void csilk_log_set_request_id | ( | const char * | request_id | ) |
Set the Request ID for the current thread.
Set the Request ID for the current thread (for log correlation).
Stores the request ID in thread-local storage, allowing subsequent log calls on the same thread to automatically include it without passing the context explicitly.
|
static |
Format and write a structured JSON log line with optional extra fields.
Builds the base log entry via build_json_entry(), merges any extra cJSON fields (the extra object's children are duplicated into the root), serializes to a compact JSON string, and writes it to the output.
| lv | Log level. |
| file | Source file name. |
| line | Source line number. |
| func | Function name. |
| extra | Extra cJSON object with additional key-value pairs to merge into the log entry. Ownership is taken (cJSON_Delete is called). May be NULL. |
| msg | Log message content. |
| msg_len | Message length. |
|
static |
Format and write a human-readable plain-text log line.
Produces output like: "2024-01-15 10:30:00 INFO [file.c:42] function(): <request_id> message" ANSI color codes are added when use_colors is enabled. Thread-local request ID is appended if set via csilk_log_set_request_id().
| lv | Log level enum (controls coloring/level label). |
| file | Source file name (only basename is used). |
| line | Source line number. |
| func | Function name. |
| msg | Log message content (not null-terminated). |
| msg_len | Length of the message content. |
|
static |
Rotate the current log file by renaming it with a ".1" suffix.
Closes the current file, renames "<path>" to "<path>.1", opens a new file at the original path in append mode, and resets the current_size counter. This is a simple single-backup rotation (not multi-generational).
|
static |
|
static |
|
static |
|
static |