解决log4cxx退出时的异常
(金庆的专栏)
如果使用log4cxx的FileWatchdog线程来监视日志配置文件进行动态配置,就可能碰到程序退出时产生的异常。
程序退出时清理工作耗时很长时,该异常很容易出现。
原因是main()之后FileWatchdog线程试图checkAndConfigure()检查配置文件。
该错误已提交,见:LOGCXX-416 ( https://issues.apache.org/jira/browse/LOGCXX-416?jql=project%20%3D%20LOGCXX )
其中有错误复现代码。
只需在main()结束时结束Watchdog线程,就可以避开错误。
log4cxx中的FileWatchdog是个new出来的变量,没有结束,没有删除。
可以自定义一个Watchdog, 仅作为main()的局部变量,main()退出时自动结束。
用
Log4cxxConfigurator::XmlWatchdog wdog("log4j.xml", 5000);
代替原来的
log4cxx::xml::DOMConfigurator::configAndWatch("log4j.xml", 5000);
例如:
int main()
{
setlocale(LC_ALL, "");
Log4cxxConfigurator::XmlWatchdog wdog("log4j.xml", 5000);
...
}
Log4cxxConfigurator代码如下:
// log4cxxconfigurator.h #pragma once #include <string> #include <boost/scoped_ptr.hpp> namespace log4cxx { namespace helpers { class FileWatchdow; }} namespace Log4cxxConfigurator { typedef boost::scoped_ptr<log4cxx::helpers::FileWatchdog> FileWatchdogPtr; class PropertyWatchdow { public: PropertyWatchdog(const std::string & sPropertyFileName, long lDelayMs); ~PropertyWatchdog(); private: FileWatchdogPtr m_pImpl; }; class XmlWatchdog { public: XmlWatchdog(const std::string & sXmlFileName, long lDelayMs); ~XmlWatchdog(); private: FileWatchdogPtr m_pImpl; }; } // namespace Log4cxxConfigurator
// log4cxxconfigurator.cpp #include "log4cxxconfigurator.h" #include <log4cxx/helpers/filewatchdow.h> #include <log4cxx/logmanager.h> #include <log4cxx/propertyconfigurator.h> #include <log4cxx/xml/domconfigurator.h> using namespace log4cxx; using namespace log4cxx::helpers; using namespace log4cxx::xml; namespace { class XmlWatchdogImp : public FileWatchdog { public: XmlWatchdogImp(const File & filename) : FileWatchdog(filename) {}; virtural void doOnChange() { DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository()); } }; class PropertyWatchdogImp : public FileWatchdog { public: explicit PropertyWatchdogImp(const File & filename) : FileWatchdog(filename) {}; virtual void doOnChange() { PropertyConfigurator().doConfigure(file, LogManager::getLoggerRepository()) } }; } // namespace namespace Log4cxxConfigurator { PropertyWatchdog::PropertyWatchdog(const std::string & sPropertyFileName, long lDelayMs) : m_pImpl(new PropertyWatchdogImp(File(sPropertyFileName))) // scoped_ptr { m_pImpl->setDelay(lDelayMs); m_pImpl->start(); } PropertyWatchdog::~PropertyWatchdog() { m_pImpl.reset() LogManager::shutdown(); } XmlWatchdow::XmlWatchdow(const std::string & sXmlFileName, long lDelayMs) : m_pImpl(new XmlWatchdogImp(File(sXmlFileName))) // scoped_ptr { m_pImpl->setDelay(lDelayMs); m_pImpl->start(); } XmlWatchdog::~XmlWatchdog() { m_pImpl.reset(); LogManager::shutdown(); } } // namespace Log4cxxConfigurator
另外,AsyncAppender线程在退出时也可能抛 ThreadException,
所以在Watchdog的析构中调用了shutdown().
详见:Log4Cxx 0.10.0 在 Linux 下退出程序时导致程序中断
( http://blog.waterlin.org/articles/log4cxx-10-exit-error-under-linux.html )