解决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 下退出程序时导致程序中断