|
Hi everybody,
recently I had a problem when using log4cxx with
unicode characters... I used version 0.9.7, RollingFileAppender as an
appender and PatternLayout as a layout...
The problem appeared when I was logging 'special'
characters (like Greek letters, for example). In this situation, log4cxx
didn't log anything and looked like it was hanging/crashed, but it wasn't
actually (the rest of the code executed correctly)... Moreover, the logfile
itself didn't look like an UNICODE file... When I opened it with Notepad, the
encoding type was ANSI (instead of UNICODE as I expected).
I searched the web and I found a similar problem
when using wofstream and unicode characters: http://www.codeproject.com/vcpp/stl/upgradingstlappstounicode.asp.
It seems that the solution is to use a new
codecvt-class that converts wchar_t to wchar_t (i.e. do nothing) and attach
it to the wofstream object. I used this idea in
RollingFileAppender.cpp and the problem was solved (i.e., I was able to log
'special' chars, like Greek chars + the encoding-type of the log file was
UNICODE).
So, at the end of the email, I attached the
modified version of RollingFileAdapter.cpp. If the log4cxx developers
consider this change useful, they can use it in the next log4cxx
release.
Also, I think there is still a problem when logging
'long' messages. When the message to be logged exceeds a certain size (I don't
know for sure which size, but it looks like it's 1000+ chars), the log4cxx
behavior is the same as described earlier (no subsequent log messages are logged
into the file anymore)...
Did any of you encounter this
behavior?
Best regards,
George.
PS1 - Here is the modified
RollingFileAppender.cpp:
/*
* Copyright 2003,2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <log4cxx/fileappender.h> #include <log4cxx/helpers/stringhelper.h> #include <log4cxx/helpers/loglog.h> #include <log4cxx/helpers/optionconverter.h> #if defined(UNICODE) &&
defined(WIN32)
#include <fstream> //--ADDED BY GM 2004.06.23 #endif using namespace log4cxx;
using namespace log4cxx::helpers; using namespace log4cxx::spi; //--SECTION ADDED BY GM 2004.06.23
#if defined(UNICODE) && defined(WIN32) using namespace std; typedef codecvt<wchar_t, char, mbstate_t> Mybase; // CLASS
Simple_codecvt
class Simple_codecvt : public
Mybase
{ public: typedef wchar_t _E; typedef char _To; typedef mbstate_t _St; explicit Simple_codecvt(size_t
_R = 0)
: Mybase(_R) {} protected:
virtual result do_in(_St& _State, const _To *_F1, const _To *_L1, const _To *&_Mid1, _E *F2, _E *_L2, _E *&_Mid2) const {return (noconv);} virtual result do_out(_St&
_State,
const _E *_F1, const _E *_L1, const _E *&_Mid1, _To *F2, _E *_L2, _To *&_Mid2) const {return (noconv);} virtual result
do_unshift(_St& _State,
_To *_F2, _To *_L2, _To *&_Mid2) const {return (noconv);} virtual int do_length(_St&
_State, const _To *_F1,
const _To *_L1, size_t _N2) const _THROW0() {return (_N2 < (size_t)(_L1 - _F1) ? _N2 : _L1 - _F1); } virtual bool do_always_noconv()
const _THROW0()
{return (true);} virtual int do_max_length()
const _THROW0()
{return (2);} virtual int do_encoding() const
_THROW0()
{return (2);} };
#endif //---END MODIFIED BY GM IMPLEMENT_LOG4CXX_OBJECT(FileAppender)
FileAppender::FileAppender()
: fileAppend(true), bufferedIO(false), bufferSize(8*1024) { } FileAppender::FileAppender(const LayoutPtr&
layout, const String& fileName,
bool append, bool bufferedIO, int bufferSize) : fileAppend(true), bufferedIO(false), bufferSize(8*1024) { this->layout = layout; this->setFile(fileName, append, bufferedIO, bufferSize); } FileAppender::FileAppender(const LayoutPtr&
layout, const String& fileName,
bool append) : fileAppend(true), bufferedIO(false), bufferSize(8*1024) { this->layout = layout; this->setFile(fileName, append, false, bufferSize); } FileAppender::FileAppender(const LayoutPtr&
layout, const String& fileName)
: fileAppend(true), bufferedIO(false), bufferSize(8*1024) { this->layout = layout; this->setFile(fileName, true, false, bufferSize); } FileAppender::~FileAppender()
{ finalize(); } void FileAppender::setFile(const String&
file)
{ // Trim spaces from both ends. The users probably does not want // trailing spaces in file names. fileName = StringHelper::trim(file); } void FileAppender::setFile(const String&
fileName, bool append,
bool bufferedIO, int bufferSize) { synchronized sync(this); LOGLOG_DEBUG(_T("FileAppender::activateOptions called : ") << fileName << _T(", ") << append); // It does not make sense to have immediate flush and bufferedIO. if(bufferedIO) { setImmediateFlush(false); } if(ofs.is_open())
{ reset(); } /* if (bufferedIO && bufferSize >
0)
{ buffer = new char[bufferSize]; out.rdbuf()->setbuf(buffer, 0); }*/ #if defined(UNICODE) && defined(WIN32)
//--ADDED BY GM
locale loc = _ADDFAC(locale::classic(), new Simple_codecvt); ofs.imbue(loc); #endif USES_CONVERSION
ofs.open(T2A(fileName.c_str()), (append ? std::ios::app : std::ios::trunc)|std::ios::out | std::ios_base::binary); //--ADDED BY GM (binary flag) if(!ofs.is_open())
{ throw RuntimeException(); } this->os = &ofs;
this->fileName = fileName; this->fileAppend = append; this->bufferedIO = bufferedIO; this->bufferSize = bufferSize; writeHeader(); LogLog::debug(_T("FileAppender::setFile ended")); } void
FileAppender::closeWriter()
{ ofs.close(); os = 0; } void FileAppender::closeFile()
{ if (os != 0) { try { closeWriter(); } catch(Exception& e) { LogLog::error(_T("Could not close file ") + fileName, e); } } } void FileAppender::setBufferedIO(bool
bufferedIO)
{ this->bufferedIO = bufferedIO; if(bufferedIO) { immediateFlush = false; } } void FileAppender::setOption(const String&
option,
const String& value) { if (StringHelper::equalsIgnoreCase(option, _T("file")) || StringHelper::equalsIgnoreCase(option, _T("filename"))) { fileName = value; } else if (StringHelper::equalsIgnoreCase(option, _T("append"))) { fileAppend = OptionConverter::toBoolean(value, true); } else if (StringHelper::equalsIgnoreCase(option, _T("bufferedio"))) { bufferedIO = OptionConverter::toBoolean(value, true); } else if (StringHelper::equalsIgnoreCase(option, _T("immediateflush"))) { bufferedIO = !OptionConverter::toBoolean(value, false); } else if (StringHelper::equalsIgnoreCase(option, _T("buffersize"))) { bufferSize = OptionConverter::toFileSize(value, 8*1024); } else { WriterAppender::setOption(name, value); } } void
FileAppender::activateOptions()
{ if (!fileName.empty()) { try { setFile(fileName, fileAppend, bufferedIO, bufferSize); } catch(Exception& e) { errorHandler->error(_T("Unable to open file: ") + fileName, e, ErrorCode::FILE_OPEN_FAILURE); } } else { LogLog::warn(_T("File option not set for appender [")+name+_T("].")); LogLog::warn(_T("Are you using FileAppender instead of ConsoleAppender?")); } } |
- Re: unicode support (wofstream and codecvt) George Mardale
- Re: unicode support (wofstream and codecvt) Curt Arnold
