A C logging library with monoid logging and three output formats.
Set globally before any logging calls. Defaults to JSONL.
clog_set_fmt(CLOG_FMT_JSONL); // default
clog_set_fmt(CLOG_FMT_TEXT);
clog_set_fmt(CLOG_FMT_TEXT_COLOR); // ANSI colors- JSONL: one JSON object per line, suitable for log aggregators and
jq:
{"ts":"Mon May 18 14:23:01 2026","level":"ERR","file":"server.c","line":42,"func":"handle","msg":"connection refused"}
- TEXT: human-readable, easy to
grep:
server.c:42:handle Mon May 18 14:23:01 2026 ERR connection refused
- TEXT_COLOR: same as TEXT with ANSI level colors (cyan/white/yellow/bold red for INF/DBG/WRN/ERR).
Levels: CLOG_INF, CLOG_DBG, CLOG_WRN, CLOG_ERR.
Each call immediately prints to stdout. Source location is captured automatically.
#include "clog.h"
clog(CLOG_INF, "server started");
clog(CLOG_ERR, "connection refused");Log entries accumulate in a CLog (a dynamic array of ClogEntry). Nothing is printed until the caller decides to flush. Safe to pass through a call chain; the caller that holds the CLog controls when output happens.
#include "clog.h"
void work(CLog *log) {
clogm(CLOG_INF, *log, "doing work");
clogm(CLOG_WRN, *log, "something looks odd");
}
int main(void) {
CLog log = clog_log_init();
work(&log);
clog_log_print(log); // flush everything at once
clog_log_free(log);
return 0;
}CLog is a typed dynamic array (ClogEntry *) backed by dynarr. Entries are value types stored contiguously — plain indexing (log[i]) works.
just # static (.build/libclog.a) + dynamic (.build/libclog.so)
just test # compile and run tests with ASan + UBSan
just clean # remove .build/Copy include/clog.h, include/dynarr.h, include/prelude.h, and either libclog.a or libclog.so into your project, then compile with -I<include_dir> -L<lib_dir> -lclog.