Find file
Fetching contributors…
Cannot retrieve contributors at this time
267 lines (168 sloc) 7.46 KB


Yolog - Free Contextual Logging For All!


Yolog is a customizable but easy to use logging library. It allows many options for both file and screen logging.

Yolog is built from the ground up to be entirely embeddable in your project, meaning that it does not have to be built as a DSO dependency and will not conflict with other libraries or projects using Yolog (though it can also live as a DSO).

Yolog can provide contextual source-based information about logging messages (via format strings), can invoke callbacks for each message, and can be configured during compile time to make some logging operations as no-ops (helping performance).



This is a user-defined facility or subsystem. Your application could (and most probably should) have different subsystem. A subsystem represents a logical component within your application which emits messages; e.g. a subsystem named io which will emit messages about I/O status and error.

Perhaps your I/O subsystem then dispatches data to a stream parser, which may emit its own messages and be called parse.


Severity is a number of 'importance' the message has to offer. Yolog defines several severity levels.

The explanation of the levels is from most to least severe, and are entirely advisory


This is a critical message, i.e. something seriously wrong with the application.


Messages which represent environmental or user errors


Messages about things which might be wrong or unusual


Higher level messages indicating status or events


Lower level messages indicating status and events


Messages for function entry/leave, frequently repeated lines of code


Miscellaneous messages, usually temporary (i.e. the value of a certain variable at a certain point in time)

Outputs and Control

Yolog allows for multiple destinations for messages, these destinations may be configured on a per-subsystem basis.

The following targets may be configured


This is the default target and prints messages to standard error

Global Log

This is an application-wide logfile, subsystems can opt to send messages here as well

Subsystem Log

This is a per-subsystem log file, subsystems may additionally log to this file as well.

Each output can be configured to control its minimum allowable severity level. So for example, the io subsystem's DEBUG and lower messages may be logged to the screen, but not to the file.

Additionally, each output may have its own format string.


In order to avoid verbose logging statements, Yolog generates macro stubs for all subsystem+level combinations which result in identifiers which can accept the messages.

The preferred format for the identifier is


So e.g. a DEBUG-level message from the io subsystem would be sent as

    log_io_debug("IO Stuff...");

Macros function exactly as printf(3) and may accept printf format strings and arguments.

Output configuration

Yolog provides a config file parser which can at runtime determine and modify output control. See config/logging2.conf for an example.


Yolog will generate a stub header and source file for your project. These files provide the necessary support and glue for customizing your subsystems.

The header file contains the macro stubs (which can become quite large, but is not an issue since they are all expanded to a single function call during preprocessing).

The source file contains a wrapper init function, and if configured in 'static' mode, contains the source code of Yolog itself, with its symbols specially mangled to avoid conflicts.

The contents and dependencies of these headers are none, so any C compiler should be able to compile and embed the generated source code into your project without any fuss. By default, Yolog generates C99 compatible code, but has an option for generating C89 code as well (which does not make use of variadic macros)


In order to use Yolog you must tell it about the names and subsystems you wish to use in your project

The file conf/sample.cnf shows a simple configuration in conjunction with a simple 'project' (located in the demo directory). This project has Makefile targets for both static and dynamic Yolog using the same codebase.

A simple configuration should look like this

    # Your app's 'namespace'. This will be prefixed to everything
    symbol_prefix myproj

    # By default, debug macros have the same prefix as the namespace. This
    # option will provide a customized prefix. Instead of myproj_debug, we can do
    macro_prefix log
    # and do log_debug

    # Environment variables to manipulate the debugging level and options
    env_color MYAPP_DEBUG_COLOR
    env_debug MYAPP_DEBUG_LEVEL
    env_prefs MYAPP_DEBUG_PREFS

    # Now, sometimes an app wants more than a single logging source. This helps
    # filter out messages based on subsystem/component rather than simple severity.
    subsys io
    subsys config
    subsys main

Now, assuming we've saved this file to myapp.conf we will do the following to generate the Yolog files

For a dynamic Yolog, do

    $ ./srcutil/ -c myapp.conf -o myapp_yolog

For a static Yolog:

    $ ./srcutil/ -c myapp.conf --static -o myapp_yolog -y /usr/src/yolog

In either case, a new directory myapp_yolog will be created, and there will be two files, myapp_yolog.c and myapp_yolog.h. The source file should be linked in with your application, and the header file included.

Assuming that the myapp_yolog directory is in your compiler's search path, the following would be done in order to use the logging libraries

    #include <myapp_yolog/myapp_yolog.h>
    /* other stuff */

    int main(void) {
        log_debug("This is a debug message");
        log_io_error("IO Error!");
        log_config_warn("Configuration Option has no effect!");


If you wanted to add some color

    $ export MYAPP_DEBUG_COLOR=1
    $ ./myapp

Or if you wanted to silence all debug output

    $ export MYAPP_DEBUG_LEVEL=1000
    $ ./myapp

If you wanted to see all TRACE and higher messages from the IO subsystem

    $ export MYAPP_DEBUG_PREFS="io:trace"
    $ ./myapp


I've managed to compile libyolog on GCC for Linux, Windows, Solaris.

The C99-mode macros should work anywhere and require little fuss.


Because yolog can be used from multiple threads, there arise two issues.

FILE* locking

The stdio's FILE pointer must be locked by each thread. On POSIX sysstems this is done with flockfile and funlockfile. I have yet to discover something like this for win32

C89 mode

C89 mode is not 'atomic' in the sense that the macros must set contextual information separately from the actual logging messages. This means a global context placeholder must exist and be set for each message. On POSIX system this global context is protected by pthreads. As I am not a win32 programmer I have not had the time to play around with windows threads here

Thread and Process IDs

Yolog's format string allows thread and process ID specifiers. On POSIX systems this is easy; on Windows systems these both fallback to -1


Copyright 2010-2012 M. Nunberg

See LICENSE for licensing information