Mastering log.c: A Lightweight C99 Logging Library for Embedded Systems
This guide introduces the log.c library, a compact C99‑based logger suitable for embedded platforms, covering its features, usage examples, level control, file output, callbacks, thread safety, and colorized output with code snippets and configuration details.
Overview
log.c is a lightweight, header‑only logging library written in C99 and released under the MIT license. The source code is hosted at https://github.com/rxi/log.c and can be compiled on any platform that supports the C99 standard, including embedded systems.
Key Features
C99 implementation, suitable for resource‑constrained environments.
Silent mode to suppress all output.
Configurable log levels (TRACE, DEBUG, INFO, WARN, ERROR, FATAL).
Optional ANSI color codes for terminal output.
Thread‑safe design with user‑provided lock callbacks.
Basic Usage
Include log.c and log.h in your project. The library provides six macros for logging at different severity levels:
#include "log.h"
int main(void) {
log_trace("Trace message: %d", 42);
log_debug("Debug message: %s", "debug");
log_info("Info message: %s", "info");
log_warn("Warn message: %s", "warning");
log_error("Error message: %s", "error");
log_fatal("Fatal message: %s", "fatal");
return 0;
}Each macro accepts a printf -style format string and writes the formatted text to stderr.
Setting the Log Level
Filter messages by calling log_set_level(). Logs with a lower priority than the specified level are ignored.
log_set_level(LOG_ERROR); // only ERROR and FATAL are printedRedirecting Output to a File
Use log_add_fp() to attach a FILE* pointer. The second argument selects the minimum level that will be written to the file.
#include "log.h"
int main(void) {
FILE *file = fopen("log.txt", "w");
if (file) {
log_add_fp(file, LOG_INFO); // write INFO and higher to file
}
// logging calls …
return 0;
}Custom Formatting via Callback
Register a callback with log_add_callback() to control the exact output format, for example to prepend timestamps.
static const char *level_str[] = {"TRACE","DEBUG","INFO","WARN","ERROR","FATAL"};
static void my_log_callback(log_Event *ev) {
char buf[64];
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time);
fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_str[ev->level], ev->file, ev->line);
vfprintf(ev->udata, ev->fmt, ev->ap);
fprintf(ev->udata, "
");
fflush(ev->udata);
}
int main(void) {
log_add_callback(my_log_callback, stderr, LOG_FATAL);
// logging calls …
return 0;
}Thread‑Safety
Provide a lock function to log_set_lock(). The function receives a boolean indicating lock (true) or unlock (false) and a user data pointer.
void lock_fn(bool lock, void *udata) {
if (lock) {
// acquire lock
} else {
// release lock
}
}
log_set_lock(lock_fn, NULL);Enabling Colored Output
Define LOG_USE_COLOR at compile time to activate ANSI color codes.
gcc log.c test.c -DLOG_USE_COLORThe combination of level filtering, file redirection, custom callbacks, optional thread safety, and colored console output makes log.c well suited for minimal‑overhead logging in embedded C projects.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
