解决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代码如下:
1 // log4cxxconfigurator.h
2 #pragma once
3
4 #include <string>
5 #include <boost/scoped_ptr.hpp>
6
7 namespace log4cxx { namespace helpers {
8 class FileWatchdow;
9 }}
10
11 namespace Log4cxxConfigurator {
12
13 typedef boost::scoped_ptr<log4cxx::helpers::FileWatchdog> FileWatchdogPtr;
14
15 class PropertyWatchdow
16 {
17 public:
18 PropertyWatchdog(const std::string & sPropertyFileName, long lDelayMs);
19 ~PropertyWatchdog();
20 private:
21 FileWatchdogPtr m_pImpl;
22 };
23
24 class XmlWatchdog
25 {
26 public:
27 XmlWatchdog(const std::string & sXmlFileName, long lDelayMs);
28 ~XmlWatchdog();
29 private:
30 FileWatchdogPtr m_pImpl;
31 };
32
33 } // namespace Log4cxxConfigurator
34
1 // log4cxxconfigurator.cpp
2 #include "log4cxxconfigurator.h"
3
4 #include <log4cxx/helpers/filewatchdow.h>
5 #include <log4cxx/logmanager.h>
6 #include <log4cxx/propertyconfigurator.h>
7 #include <log4cxx/xml/domconfigurator.h>
8
9 using namespace log4cxx;
10 using namespace log4cxx::helpers;
11 using namespace log4cxx::xml;
12
13 namespace {
14
15 class XmlWatchdogImp : public FileWatchdog
16 {
17 public:
18 XmlWatchdogImp(const File & filename) : FileWatchdog(filename) {};
19
20 virtural void doOnChange()
21 {
22 DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
23 }
24 };
25
26 class PropertyWatchdogImp : public FileWatchdog
27 {
28 public:
29 explicit PropertyWatchdogImp(const File & filename) : FileWatchdog(filename) {};
30
31 virtual void doOnChange()
32 {
33 PropertyConfigurator().doConfigure(file, LogManager::getLoggerRepository())
34 }
35 };
36
37 } // namespace
38
39 namespace Log4cxxConfigurator {
40
41 PropertyWatchdog::PropertyWatchdog(const std::string & sPropertyFileName, long lDelayMs)
42 : m_pImpl(new PropertyWatchdogImp(File(sPropertyFileName))) // scoped_ptr
43 {
44 m_pImpl->setDelay(lDelayMs);
45 m_pImpl->start();
46 }
47
48 PropertyWatchdog::~PropertyWatchdog()
49 {
50 m_pImpl.reset()
51 LogManager::shutdown();
52 }
53
54 XmlWatchdow::XmlWatchdow(const std::string & sXmlFileName, long lDelayMs)
55 : m_pImpl(new XmlWatchdogImp(File(sXmlFileName))) // scoped_ptr
56 {
57 m_pImpl->setDelay(lDelayMs);
58 m_pImpl->start();
59 }
60
61 XmlWatchdog::~XmlWatchdog()
62 {
63 m_pImpl.reset();
64 LogManager::shutdown();
65 }
66
67 } // namespace Log4cxxConfigurator
68
另外,AsyncAppender线程在退出时也可能抛 ThreadException,
所以在Watchdog的析构中调用了shutdown().
详见:Log4Cxx 0.10.0 在 Linux 下退出程序时导致程序中断
( http://blog.waterlin.org/articles/log4cxx-10-exit-error-under-linux.html )