On Feb 6, 2007, at 12:25 PM, Andrew Chalk wrote:

I had to upgrade an app. that used log4cxx. We made a lot of use of lines
like:

LOG4CXX_INFO(eventLogger, _T("Binding to: " << sBindIP.c_str() << ". Port: "
<< usPort << ". Link: " << sLinkNo.c_str()));

I.e. we used inline ostringstream constructs.

In 0.9.8 none of this appears to work. We appear to have to make major
modifications to our code along the lines of:

ostringstream os;
os << _T("Binding to: " << sBindIP.c_str() << ". Port: " << usPort << ".
Link: " << sLinkNo.c_str());
LOG4CXX_INFO(eventLogger, os.str().c_str());

Am I missing a way to continue with inline ostringstream?

Many thanks.,


The log4cxx 0.9.7 macros looked like:

#define LOG4CXX_INFO(logger, message) { \
        if (logger->isInfoEnabled()) {\
        ::log4cxx::StringBuffer oss; \
        oss << message; \
logger->forcedLog(::log4cxx::Level::INFO, oss.str(), __FILE__, __LINE__); }}

And would allow you to pass a TCHAR* (where TCHAR was either char or wchar_t depending on the compile flags) or any other statement fragment that could complete the oss << message statement.

In log4cxx 0.10.0, we did not want the artificial limit of supporting only one character type per build since many apps could easily use both char and wchar_t within the same application. The macro looks like:

#define LOG4CXX_INFO(logger, message) { \
        if (logger->isInfoEnabled()) {\
logger->forcedLog(::log4cxx::Level::INFO, message, LOG4CXX_LOCATION); }}

and the compiler picks the appropriate flavor of forcedLog (std::string or std::wstring) based on the type of the message expression. However that requires that message be an expression and not a statement fragment. I do not believe that it is possible to construct a macro that will both accept statement fragments that 0.9.7 accepted and also support multiple string types, but I'm willing to be proved wrong.

You appear to be misusing the Win32 _T construct (http:// msdn2.microsoft.com/en-us/library/c426s321(VS.80).aspx) which is intended to be used to decorate a string literal so that it matches the TCHAR type. For example, _T("Hello, World") would expand to "Hello, World"L if _UNICODE is set and "Hello, World" otherwise. The examples shown about would not compile if _UNICODE was set since they would just add a L to the end of the fragment and change .c_str() to .c_str()L.

log4cxx no longer defines or uses _T. It does define LOG4CXX_STR() to create string literals that match the internal logchar type, however LOG4CXX_STR should not be used in logging statements since both char and wchar_t flavors are provided regardless of the logchar type.

That is do

LOG4CXX_INFO(logger, "Hello, World");

or

LOG4CXX_INFO(logger, "Hello, World"L);

but do not do:

LOG4CXX_INFO(logger, LOG4CXX_STR("Hello, World"));

The last would compile and work properly, but it reflects a misunderstanding of logchar as the internal char type.

It appears from your fragments that you have no interest in wchar_t strings (or other string types like CFString on Macs) and would be willing to trade the multiple string type support for getting the statement fragment support back. You could create your own header file that you include after logger.h that redefines LOG4CXX_INFO et al for your own objectives, so instead of rewriting all your logging calls, all you have to do is create the header file and include it where ever you used statement fragments.

Reply via email to