Log4j and its derivatives

Inserting log statements into your code is a low-tech, but nevertheless very useful method for debugging it. It may also be the only way because debuggers are not always available or applicable. This is often the case for distributed and embedded applications.
On the other hand, some people argue that log statements pollute source code and decrease legibility. (We believe that the contrary is true). In the Java language where a preprocessor is not available, log statements increase the size of the code and reduce its speed, even when logging is turned off. Given that a reasonably sized application may contain thousands of log statements, speed is of particular importance.
Log4j is the original implementation of a series of similar packages which provide the ability to enable logging at runtime without modifying the application binary. The log4j package is designed so that these statements can remain in shipped code without incurring a heavy performance cost. Logging behavior can be controlled by editing a configuration file, without touching the application binary.
The log4j page is here and contains links that describes it dfairly completely
Log4j has been used to provide a template for implementations in many other languages. Unfortunately in many cases the documentation has not caught up with the code, so the language specific documentation tends to be very sparse and refer the reader to the more complete log4j manual. The interpreation is easy enough for object oriented languages but is harder for languages such as C.

Log4c

The log4c page is here . You need to set up a "log4crc" configuration file in whatever directory you are running the programs containing it in (alternatively, the file can be in ${LOG4C_RCPATH}/log4rc or ${HOME}/.log4crc). A trivial program which might use log4c looks like this:
A typical one might look like this:
<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE log4c SYSTEM "">



<log4c>



<category name="main" appender="stderr" priority="priority" />



<!-- default appenders ===================================== -->

<appender name="stdout" layout="basic"/>

<appender name="stderr" layout="dated"/>



<!-- default layouts ======================================= -->

<layout name="basic"/>

<layout name="dated"/>

</log4c>

This attaches standard out to the category "main" and will get messages of "info" priority level

or greater. It seems that the category and logger have been

merged.


If you have a category called "root", then that gets logging messages

from all categories.

A simple program is:
#include <stdio.h>

#include <log4c.h>



int main()

{

log4c_category_t* cat = NULL;

int count = 0; /* Just to demonstrate that formatted output works */



if (log4c_init())

{

printf("Log4c initialisation failed\n");

return 0;

}



cat = log4c_category_get("main");



log4c_category_fatal(cat, "This is a fatal message - message %d",

count++);

log4c_category_warn(cat, "This is a warning message -message %d", count);

log4c_category_info(cat, "This is an info message");



if (log4c_fini())

{

printf("Log4c finish failed\n");

return 0;

} }
When run, the output that is displayed is



[stderr] 2003011 13:38:23.583 FATAL main - This is a fatal message -

message 0

[stderr] 20030116 13:38:23.585 WARN main - This is a warning message

-message 1

[stderr] 20030116 13:38:23.586 INFO main - This is an info message
You can send the output to a file (log.out in this case) by changing the appender to a filename in the <category> element, and get it timestamped by adding <appender name="log.out" layout="dated"/>

Log4cpp

The log4cpp page is here . You can either use a properties file which is very similar to the log4j version or you can use a much simpler format file.
#include "log4cpp/Category.hh"

#include "log4cpp/PropertyConfigurator.hh"

const std::string initFileName = "./log4cpp.properties";

try {

log4cpp::PropertyConfigurator::configure("./log4cpp");

} catch(log4cpp::ConfigureFailure& f) {

std::cerr << "Log4cpp Configuriguration thre an exception:" << f.what() << std::endl;

return -1;

}
The PropertyConfigurator class configres log4cpp using a clone of the log4j property file format, and there is a BasicConfigurator class that configures it using a much simpler non-heirarchical file.
A very simple property file might look like this - rootCategory is the default category, used if the specification for the specific category is not present. In this example, INFO and above messages of myFlowControl wil be sent to the terminal, all others will go to a logging file.
# Property configuration file rootCategory=DEBUG, file category.myFlowControl=INFO, terminal # This appender displays messages on the terminal

appender.terminal=org.apache.log4j.ConsoleAppender appender.terminal.layout=org.apache.log4j.BasicLayout # This appender appends the messages to a file appender.file=org.apache.log4j.FileAppender appender.file.fileName=cpp-api.log appender.file.layout=org.apache.log4j.BasicLayout
log4cpp is then used (rather simplistically in this example) as follows


log4cpp::Category& CppApiTest::cat& = log4cpp::Category::getInstance("MyCategory"); ... int value = 43; // For example... cat.info("This is an info message - value is %d", value); ... etc.