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.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Mastering log.c: A Lightweight C99 Logging Library for Embedded Systems

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 printed

Redirecting 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_COLOR

The 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.

loggingThread SafetyembeddedC99log.c
Liangxu Linux
Written by

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.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.