Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Log to different file with log4cxx

I want to log to different files in my code.

How can i do that in Log4cxx with xml configuration or programatically in code...

  • Suppose that I have 1.k,k+1,..n components.
  • They run in the same application
  • I want component k log to Logger-k, k+1 component log to Logger-k+1 at the same time

Update:

Logger.addAppender() approach:

log4cxx::helpers::Pool p; 

std::string paramAppender = "appxNormalAppender";
std::string paramFileName = "\\Logs\\MyLog.txt";

LOG4CXX_DECODE_CHAR(logAppender, paramAppender );
LOG4CXX_DECODE_CHAR(logFileName, paramFileName );


FileAppenderPtr fileAppender = 
logger->getLoggerRepository()->getRootLogger()->getAppender(logAppender);

if(fileAppender!= NULL)
{


    fileAppender->setFile(logFileName);

    fileAppender->activateOptions(p);

}

This does not work because

Suppose that i set FileName to Logger-k for k component, it logs to Logger-k, then i set file name to Logger-k+1 for compoent k+1, then both component k, and k+1 log the same loggerk+1 file. It seems last file name overrides or effects all others...

And

All compoenent compenent 1, ...compoeent k, componentk+1,.... component n are in the same application...

like image 556
Novalis Avatar asked Jan 09 '12 13:01

Novalis


3 Answers

Create Each of the Loggers as normal, and then for each logger add a FileAppender set to the desired file via the Logger.addAppender() method.

like image 54
diverscuba23 Avatar answered Oct 20 '22 03:10

diverscuba23


You do need to create separate appenders for you loggers. In my example i've created afile1 and afile2 appenders. I have also created two loggers : my.logger1 and my.logger2. When you use my.logger1 it logs to mylog1 file, When you use my.logger2 it logs to mylog2 file.

Here is my log.properties file:

log4cplus.appender.afile1.layout=log4cplus::PatternLayout
log4cplus.appender.afile1.layout.ConversionPattern=%d [ %c{1} ] [ %-5p ] %m%n
log4cplus.appender.afile1=log4cplus::RollingFileAppender
log4cplus.appender.afile1.File=mylog1.log
log4cplus.appender.afile1.MaxFileSize=5MB
log4cplus.appender.afile1.MaxBackupIndex=2

log4cplus.appender.afile2.layout=log4cplus::PatternLayout
log4cplus.appender.afile2.layout.ConversionPattern=%d [ %c{1} ] [ %-5p ] %m%n
log4cplus.appender.afile2=log4cplus::RollingFileAppender
log4cplus.appender.afile2.File=mylog2.log
log4cplus.appender.afile2.MaxFileSize=5MB
log4cplus.appender.afile2.MaxBackupIndex=2

log4cplus.logger.my.logger1=INHERIT, afile1
log4cplus.additivity.my.logger1=false
log4cplus.logger.my.logger2=INHERIT, afile2
log4cplus.additivity.my.logger2=false 

Here is an example programm:
example.cpp:

#include <iostream>
#include <log4cplus/logger.h>
#include <log4cplus/loglevel.h>
#include <log4cplus/configurator.h>
#include <log4cplus/fileappender.h>

#define MYLOG1_INFO(logEvent) LOG4CPLUS_INFO (log4cplus::Logger::getInstance("my.logger1"), logEvent)
#define MYLOG2_INFO(logEvent) LOG4CPLUS_INFO (log4cplus::Logger::getInstance("my.logger2"), logEvent)

int main(int argc, char**argv)
{
    try
    {
        log4cplus::PropertyConfigurator::doConfigure("log.properties");
    }
    catch( ... )
    {
    std::cerr<<"Exception occured while opening log.properties\n";
    return -1;
    }
    MYLOG1_INFO("hello world!");
    MYLOG2_INFO("hello world!");
    return 0;
}

Here is Makefile( i suppose my log4cplus is built in parent dirrectory):

CXXFLAGS+=-I$(abspath ../log4cplus-1.0.4/include)
all: example.o
    $(CXX) $^ $(abspath ../log4cplus-1.0.4/src/.libs/liblog4cplus.a) -lpthread -o test

Try this example and you should understand how appenders works

Log4cplus is mostly like log4j. so you can read basic principles log4j. And To get classes names you got to visit log4cplus.sourceforge.net

About log format. Documentation for log4cplus is available only in doxygen . so here you can read about formating in pattern layout
And if you want to log process id , than you should use %i in your layout conversion pattern
example:

...
log4cplus.appender.afile2.layout.ConversionPattern=[%i] %m%n
...

It will log process id and message

like image 2
2r2w Avatar answered Oct 20 '22 04:10

2r2w


For dynamic components try this:

#include <boost/foreach.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>

#include <log4cxx/Logger.h>
#include <log4cxx/LogManager.h>
#include <log4cxx/xml/domconfigurator.h>
#include <log4cxx/FileAppender.h>
#include <log4cxx/SimpleLayout.h>
#include <log4cxx/helpers/transcoder.h>


void func(int k) {
    std::string strName = "Log." + boost::lexical_cast<std::string>(k);
    log4cxx::LoggerPtr log = log4cxx::Logger::getLogger(strName);
    LOG4CXX_DECODE_CHAR(fileName, strName + ".log");
    log4cxx::FileAppenderPtr appender(new log4cxx::FileAppender(new log4cxx::SimpleLayout, fileName, false));
    log->addAppender(appender);

    LOG4CXX_INFO(log, strName);

    log->removeAppender(appender);
}

int main(int argc, char * argv[]) {
    log4cxx::xml::DOMConfigurator::configure("trace.xml");
    if(log4cxx::Logger::getLogger("Log")->getAllAppenders().empty()) {
        std::cout << "failed to config log4cxx" << std::endl;
        return 1;
    }
    log4cxx::LoggerPtr log = log4cxx::Logger::getLogger("Log");

    boost::thread_group threadGroup;
    for(int k = 0; k != 3; ++k) {
        threadGroup.create_thread(boost::bind(func, k));
    }
    threadGroup.join_all();
    return 0;
}

with simple trace.xml

<?xml version="1.0" encoding="UTF-8" ?>
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender"> 
        <param name="Target" value="System.out"/> 
        <layout class="org.apache.log4j.SimpleLayout"/> 
    </appender>

    <root>
        <level value="all"/>
    </root> 

    <category name="Log">
        <level value="INFO"/>
        <appender-ref ref="ConsoleAppender"/>
    </category>
</log4j:configuration>
like image 1
ronhartleyone Avatar answered Oct 20 '22 05:10

ronhartleyone