You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4cxx-user@logging.apache.org by Jeffrey Graham <jg...@sk-tech.com> on 2006/05/26 14:13:34 UTC

how to use %p and %Q formatting options under linux?

Hello,

I downloaded the CVS version  408722 just several days ago and have the following 2 problems 
with the pattern layout under Linux..

1) %p always shows the current log level, not the level of the message
2) %Q does not print the fractional seconds fo time, but the  "%d{ISO8601}" does.

Help, especially on the %p issue is greatly appreciated.

I am using streams in C++.


My code looks like this (inside a class called logWrapper where logger and logs are declared static):

		LoggerPtr logWrapper::logger =  Logger::getRootLogger();
		log4cxx::logstream* logWrapper::logs = new log4cxx::logstream(Logger::getRootLogger(), Level::INFO);

                ConsoleAppenderPtr append_1(new ConsoleAppender());
                append_1->setName(prefix.c_str());
                append_1->setTarget("System.err");
                append_1->setImmediateFlush(true);

                // note: for log4cxx the %Q does not seem to work as advertised
                //const std::string pattern = "%d{%Y-%m-%d|%H:%M:%S %Q}|%-5p|"+prefix+"|%m %n";

                // this gives partial seconds ok
                const std::string pattern = "%d{ISO8601}|%-5p|"+prefix+"|%m %n";

                append_1->setLayout(new PatternLayout(pattern));

                log4cxx::helpers::Pool pool;
                append_1->activateOptions(pool);

                Logger::getRootLogger()->addAppender(append_1);

I'm using this code to set the loglevel, for example:
		logger->setLevel(Level::INFO);
                logs->setLevel(Level::INFO);


And finally I use this macros for logging in my application:
#define LOG_BASE(l,x) \
        {\
        if ( logWrapper::logs->isEnabledFor(l)) \
                {\
                (*logWrapper::logs) << x << LOG4CXX_ENDMSG; \
                } \
        }
#define LOG_INFO(x) LOG_BASE(log4cxx::Level::INFO,x)
#define LOG_WARN(x) LOG_BASE(log4cxx::Level::WARN,x)
#define LOG_DEBUG(x) LOG_BASE(log4cxx::Level::DEBUG,x)
#define LOG_ERROR(x) LOG_BASE(log4cxx::Level::ERROR,x)
#define LOG_FATAL(x) LOG_BASE(log4cxx::Level::FATAL,x)

So my app can do this now:
	 LOG_INFO("this is some INFO");

This problem is that if log level has been set to debug, then the above message shows up with %p as DEBUG instead of INFO.

Thanks for your help!
-Jeff





Re: how to use %p and %Q formatting options under linux?

Posted by Curt Arnold <ca...@apache.org>.
On May 26, 2006, at 7:13 AM, Jeffrey Graham wrote:

> Hello,
>
> I downloaded the CVS version  408722 just several days ago and have  
> the following 2 problems with the pattern layout under Linux..
>
> 1) %p always shows the current log level, not the level of the message

When you set the level of the logstream, you are setting the level of  
the logging requests that are generated from the logstream, not the  
threshold for the logger.  So if I do:

log4cxx::logstream logWrapper::logs(Logger::getRootLogger(),  
Level::getInfo());
logs << "Info Message" << LOG4CXX_ENDMSG;
logs.setLevel(Level::getDebug());
logs << "Debug Message" << LOG4CXX_ENDMSG;

You would generate an INFO level request and a DEBUG level request.   
The threshold of the logger is a totally distinct thing.


> 2) %Q does not print the fractional seconds fo time, but the  "%d 
> {ISO8601}" does.

You should use the java.text.SimpleDateFormat syntax (http:// 
java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html  
which does support fractional seconds.  For backward compatibility  
with log4cxx 0.9.7 if a strftime-type format (that is with %'s) is  
detected, then apr_strftime used to format the time.  %Q is not  
implemented in APR's apr_strftime (and is not documented typically in  
systems that do implement it).


>
> Help, especially on the %p issue is greatly appreciated.
>
> I am using streams in C++.
>
>
> My code looks like this (inside a class called logWrapper where  
> logger and logs are declared static):

Have a logstream as a class member is strongly discouraged.  All  
actions on a logger are atomic, so they can be members or static  
members.  However, logstreams keep an internal state and interleaved  
calls could result in scrambled messages.  For example, if you had:

class Foo {
    private:
    static log4cxx::logstream ls(Logger::getRootLogger(),  
Level::getInfo());
    public:
    Foo() {}
    void action1() {
          ls << "Hello" << " World" << LOG4CXX_ENDMSG;
    }
    void action2() {
          ls << "Kitty" << LOG4CXX_ENDMSG;
    }
}

you could end up with any of the following combinations if action2  
and action2 were called simultaneously;

Hello World
Kitty

Kitty
Hello World

KittyHello World
(blank)

HelloKitty
World

KittyHello
World


logstream's make no attempt to synchronize their action and couldn't  
avoid the interleaving of actions if they tried.  They are designed  
to be instantiated upon entry to a routine and potentially used  
repeatedly in the body of a routine.  They are not designed to be  
shared or long-lived.

In addition, use Level::getInfo() in preference to Level::INFO as  
static member variables have initialization order issues and INFO and  
the like may be removed if they prove to be unsafe in the current  
implementation.

Using a logstream* seems to be strange since it would likely leak.