logmanager.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. /******************************************************************************
  2. *
  3. * package: Log4Qt
  4. * file: logmanager.cpp
  5. * created: September 2007
  6. * author: Martin Heinrich
  7. *
  8. *
  9. * changes: Sep 2008, Martin Heinrich:
  10. * - Resolved compilation problem with Microsoft Visual Studio 2005
  11. * Feb 2009, Martin Heinrich
  12. * - Fixed VS 2008 unreferenced formal parameter warning by using
  13. * Q_UNUSED in operator<<.
  14. *
  15. *
  16. * Copyright 2007 - 2009 Martin Heinrich
  17. *
  18. * Licensed under the Apache License, Version 2.0 (the "License");
  19. * you may not use this file except in compliance with the License.
  20. * You may obtain a copy of the License at
  21. *
  22. * http://www.apache.org/licenses/LICENSE-2.0
  23. *
  24. * Unless required by applicable law or agreed to in writing, software
  25. * distributed under the License is distributed on an "AS IS" BASIS,
  26. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  27. * See the License for the specific language governing permissions and
  28. * limitations under the License.
  29. *
  30. ******************************************************************************/
  31. /******************************************************************************
  32. * Dependencies
  33. ******************************************************************************/
  34. #include "log4qt/logmanager.h"
  35. #include <QtCore/QCoreApplication>
  36. #include <QtCore/QDebug>
  37. #include <QtCore/QFile>
  38. #include <QtCore/QMutex>
  39. #include <QtCore/QSettings>
  40. #include <QtCore/QStringList>
  41. #include "log4qt/consoleappender.h"
  42. #include "log4qt/helpers/datetime.h"
  43. #include "log4qt/helpers/initialisationhelper.h"
  44. #include "log4qt/helpers/optionconverter.h"
  45. #include "log4qt/hierarchy.h"
  46. #include "log4qt/propertyconfigurator.h"
  47. #include "log4qt/ttcclayout.h"
  48. #include "log4qt/varia/denyallfilter.h"
  49. #include "log4qt/varia/levelrangefilter.h"
  50. namespace Log4Qt
  51. {
  52. /**************************************************************************
  53. * Declarations
  54. **************************************************************************/
  55. /**************************************************************************
  56. * C helper functions
  57. **************************************************************************/
  58. LOG4QT_DECLARE_STATIC_LOGGER(static_logger, Log4Qt::LogManager)
  59. LOG4QT_GLOBAL_STATIC(QMutex, singleton_guard)
  60. /**************************************************************************
  61. * Class implementation: LogManager
  62. **************************************************************************/
  63. LogManager::LogManager() :
  64. mObjectGuard(QMutex::Recursive), // Recursive for doStartup() to call doConfigureLogLogger()
  65. mpLoggerRepository(new Hierarchy()),
  66. mHandleQtMessages(false),
  67. mOldQtMsgHandler(0)
  68. {
  69. }
  70. LogManager::~LogManager()
  71. {
  72. static_logger()->warn("Unexpected destruction of LogManager");
  73. // doSetConfigureHandleQtMessages(false);
  74. // delete mpLoggerRepository;
  75. }
  76. Logger *LogManager::rootLogger()
  77. {
  78. return instance()->mpLoggerRepository->rootLogger();
  79. }
  80. QList<Logger*> LogManager::loggers()
  81. {
  82. return instance()->mpLoggerRepository->loggers();
  83. }
  84. Level LogManager::threshold()
  85. {
  86. return instance()->mpLoggerRepository->threshold();
  87. }
  88. void LogManager::setThreshold(Level level)
  89. {
  90. instance()->mpLoggerRepository->setThreshold(level);
  91. }
  92. bool LogManager::exists(const char *pName)
  93. {
  94. return instance()->mpLoggerRepository->exists(QLatin1String(pName));
  95. }
  96. LogManager *LogManager::instance()
  97. {
  98. // Do not use LOG4QT_GLOBAL_STATIC. The LogManager is rather expensive
  99. // to construct, an exit handler must be set and doStartup must be
  100. // called.
  101. if (!mspInstance)
  102. {
  103. QMutexLocker locker(singleton_guard());
  104. if (!mspInstance)
  105. {
  106. mspInstance = new LogManager;
  107. // qAddPostRoutine(shutdown);
  108. atexit(shutdown);
  109. mspInstance->doConfigureLogLogger();
  110. mspInstance->welcome();
  111. mspInstance->doStartup();
  112. }
  113. }
  114. return mspInstance;
  115. }
  116. Logger *LogManager::logger(const QString &rName)
  117. {
  118. return instance()->mpLoggerRepository->logger(rName);
  119. }
  120. void LogManager::resetConfiguration()
  121. {
  122. setHandleQtMessages(false);
  123. instance()->mpLoggerRepository->resetConfiguration();
  124. configureLogLogger();
  125. }
  126. const char* LogManager::version()
  127. {
  128. return LOG4QT_VERSION_STR;
  129. }
  130. void LogManager::shutdown()
  131. {
  132. instance()->mpLoggerRepository->shutdown();
  133. }
  134. void LogManager::doSetHandleQtMessages(bool handleQtMessages)
  135. {
  136. QMutexLocker locker(&mObjectGuard);
  137. if (instance()->mHandleQtMessages == handleQtMessages)
  138. return;
  139. instance()->mHandleQtMessages = handleQtMessages;
  140. if (instance()->mHandleQtMessages)
  141. {
  142. static_logger()->trace("Activate Qt message handling");
  143. #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
  144. instance()->mOldQtMsgHandler = qInstallMsgHandler(qtMessageHandler);
  145. #else
  146. instance()->mOldQtMsgHandler = qInstallMessageHandler(qtMessageHandler);
  147. #endif
  148. }
  149. else
  150. {
  151. static_logger()->trace("Deactivate Qt message handling");
  152. #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
  153. qInstallMsgHandler(instance()->mOldQtMsgHandler);
  154. #else
  155. qInstallMessageHandler(instance()->mOldQtMsgHandler);
  156. #endif
  157. }
  158. }
  159. void LogManager::doConfigureLogLogger()
  160. {
  161. QMutexLocker locker(&instance()->mObjectGuard);
  162. // Level
  163. QString value = InitialisationHelper::setting(QLatin1String("Debug"),
  164. QLatin1String("ERROR"));
  165. logLogger()->setLevel(OptionConverter::toLevel(value, Level::DEBUG_INT));
  166. // Common layout
  167. TTCCLayout *p_layout = new TTCCLayout();
  168. p_layout->setName(QLatin1String("LogLog TTCC"));
  169. p_layout->setContextPrinting(false);
  170. p_layout->activateOptions();
  171. // Common deny all filter
  172. Filter *p_denyall = new DenyAllFilter();
  173. p_denyall->activateOptions();
  174. // ConsoleAppender on stdout for all events <= INFO
  175. ConsoleAppender *p_appender;
  176. LevelRangeFilter *p_filter;
  177. p_appender = new ConsoleAppender(p_layout, ConsoleAppender::STDOUT_TARGET);
  178. p_filter = new LevelRangeFilter();
  179. p_filter->setNext(p_denyall);
  180. p_filter->setLevelMin(Level::NULL_INT);
  181. p_filter->setLevelMax(Level::INFO_INT);
  182. p_filter->activateOptions();
  183. p_appender->setName(QLatin1String("LogLog stdout"));
  184. p_appender->addFilter(p_filter);
  185. p_appender->activateOptions();
  186. logLogger()->addAppender(p_appender);
  187. // ConsoleAppender on stderr for all events >= WARN
  188. p_appender = new ConsoleAppender(p_layout, ConsoleAppender::STDERR_TARGET);
  189. p_filter = new LevelRangeFilter();
  190. p_filter->setNext(p_denyall);
  191. p_filter->setLevelMin(Level::WARN_INT);
  192. p_filter->setLevelMax(Level::OFF_INT);
  193. p_filter->activateOptions();
  194. p_appender->setName(QLatin1String("LogLog stderr"));
  195. p_appender->addFilter(p_filter);
  196. p_appender->activateOptions();
  197. logLogger()->addAppender(p_appender);
  198. }
  199. void LogManager::doStartup()
  200. {
  201. QMutexLocker locker(&instance()->mObjectGuard);
  202. // Override
  203. QString default_value = QLatin1String("false");
  204. QString value = InitialisationHelper::setting(QLatin1String("DefaultInitOverride"),
  205. default_value);
  206. if (value != default_value)
  207. {
  208. static_logger()->debug("DefaultInitOverride is set. Aborting default initialisation");
  209. return;
  210. }
  211. // Configuration using setting Configuration
  212. value = InitialisationHelper::setting(QLatin1String("Configuration"));
  213. if (QFile::exists(value))
  214. {
  215. static_logger()->debug("Default initialisation configures from file '%1' specified by Configure", value);
  216. PropertyConfigurator::configure(value);
  217. return;
  218. }
  219. // Configuration using setting
  220. if (QCoreApplication::instance())
  221. {
  222. const QLatin1String log4qt_group("Log4Qt");
  223. const QLatin1String properties_group("Properties");
  224. QSettings s;
  225. s.beginGroup(log4qt_group);
  226. if (s.childGroups().contains(properties_group))
  227. {
  228. const QString group(QLatin1String("Log4Qt/Properties"));
  229. static_logger()->debug("Default initialisation configures from setting '%1/%2'", log4qt_group, properties_group);
  230. s.beginGroup(properties_group);
  231. PropertyConfigurator::configure(s);
  232. return;
  233. }
  234. }
  235. // Configuration using default file
  236. const QString default_file(QLatin1String("log4qt.properties"));
  237. if (QFile::exists(default_file))
  238. {
  239. static_logger()->debug("Default initialisation configures from default file '%1'", default_file);
  240. PropertyConfigurator::configure(default_file);
  241. return;
  242. }
  243. static_logger()->debug("Default initialisation leaves package unconfigured");
  244. }
  245. void LogManager::welcome()
  246. {
  247. static_logger()->info("Initialising Log4Qt %1",
  248. QLatin1String(LOG4QT_VERSION_STR));
  249. // Debug: Info
  250. if (static_logger()->isDebugEnabled())
  251. {
  252. // Create a nice timestamp with UTC offset
  253. DateTime start_time = DateTime::fromMilliSeconds(InitialisationHelper::startTime());
  254. QString offset;
  255. {
  256. QDateTime utc = start_time.toUTC();
  257. QDateTime local = start_time.toLocalTime();
  258. QDateTime local_as_utc = QDateTime(local.date(), local.time(), Qt::UTC);
  259. int min = utc.secsTo(local_as_utc) / 60;
  260. if (min < 0)
  261. offset += QLatin1Char('-');
  262. else
  263. offset += QLatin1Char('+');
  264. min = abs(min);
  265. offset += QString::number(min / 60).rightJustified(2, QLatin1Char('0'));
  266. offset += QLatin1Char(':');
  267. offset += QString::number(min % 60).rightJustified(2, QLatin1Char('0'));
  268. }
  269. static_logger()->debug("Program startup time is %1 (UTC%2)",
  270. start_time.toString(QLatin1String("ISO8601")),
  271. offset);
  272. static_logger()->debug("Internal logging uses the level %1",
  273. logLogger()->level().toString());
  274. }
  275. // Trace: Dump settings
  276. if (static_logger()->isTraceEnabled())
  277. {
  278. static_logger()->trace("Settings from the system environment:");
  279. QString entry;
  280. Q_FOREACH (entry, InitialisationHelper::environmentSettings().keys())
  281. static_logger()->trace(" %1: '%2'",
  282. entry,
  283. InitialisationHelper::environmentSettings().value(entry));
  284. static_logger()->trace("Settings from the application settings:");
  285. if (QCoreApplication::instance())
  286. {
  287. const QLatin1String log4qt_group("Log4Qt");
  288. const QLatin1String properties_group("Properties");
  289. static_logger()->trace(" %1:", log4qt_group);
  290. QSettings s;
  291. s.beginGroup(log4qt_group);
  292. Q_FOREACH (entry, s.childKeys())
  293. static_logger()->trace(" %1: '%2'",
  294. entry,
  295. s.value(entry).toString());
  296. static_logger()->trace(" %1/%2:", log4qt_group, properties_group);
  297. s.beginGroup(properties_group);
  298. Q_FOREACH (entry, s.childKeys())
  299. static_logger()->trace(" %1: '%2'",
  300. entry,
  301. s.value(entry).toString());
  302. } else
  303. static_logger()->trace(" QCoreApplication::instance() is not available");
  304. }
  305. }
  306. #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
  307. void LogManager::qtMessageHandler(QtMsgType type, const char *pMessage)
  308. {
  309. Level level;
  310. switch (type)
  311. {
  312. case QtDebugMsg:
  313. level = Level::DEBUG_INT;
  314. break;
  315. case QtWarningMsg:
  316. level = Level::WARN_INT;
  317. break;
  318. case QtCriticalMsg:
  319. level = Level::ERROR_INT;
  320. break;
  321. case QtFatalMsg:
  322. level = Level::FATAL_INT;
  323. break;
  324. default:
  325. level = Level::TRACE_INT;
  326. }
  327. instance()->qtLogger()->log(level, pMessage);
  328. // Qt fatal behaviour copied from global.cpp qt_message_output()
  329. // begin {
  330. if ((type == QtFatalMsg) ||
  331. ((type == QtWarningMsg) && (!qgetenv("QT_FATAL_WARNINGS").isNull())) )
  332. {
  333. #if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
  334. // get the current report mode
  335. int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
  336. _CrtSetReportMode(_CRT_ERROR, reportMode);
  337. int ret = _CrtDbgReport(_CRT_ERROR, __FILE__, __LINE__, QT_VERSION_STR, pMessage);
  338. if (ret == 0 && reportMode & _CRTDBG_MODE_WNDW)
  339. return; // ignore
  340. else if (ret == 1)
  341. _CrtDbgBreak();
  342. #endif
  343. #if defined(Q_OS_UNIX) && defined(QT_DEBUG)
  344. abort(); // trap; generates core dump
  345. #else
  346. exit(1); // goodbye cruel world
  347. #endif
  348. }
  349. // } end
  350. }
  351. #else
  352. void LogManager::qtMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
  353. {
  354. Q_UNUSED(context)
  355. Level level;
  356. switch (type)
  357. {
  358. case QtDebugMsg:
  359. level = Level::DEBUG_INT;
  360. break;
  361. case QtWarningMsg:
  362. level = Level::WARN_INT;
  363. break;
  364. case QtCriticalMsg:
  365. level = Level::ERROR_INT;
  366. break;
  367. case QtFatalMsg:
  368. level = Level::FATAL_INT;
  369. break;
  370. default:
  371. level = Level::TRACE_INT;
  372. }
  373. instance()->qtLogger()->log(level, message);
  374. // Qt fatal behaviour copied from global.cpp qt_message_output()
  375. // begin {
  376. if ((type == QtFatalMsg) ||
  377. ((type == QtWarningMsg) && (!qgetenv("QT_FATAL_WARNINGS").isNull())) )
  378. {
  379. #if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
  380. // get the current report mode
  381. int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
  382. _CrtSetReportMode(_CRT_ERROR, reportMode);
  383. int ret = _CrtDbgReport(_CRT_ERROR, __FILE__, __LINE__, QT_VERSION_STR, message.toUtf8().constData());
  384. if (ret == 0 && reportMode & _CRTDBG_MODE_WNDW)
  385. return; // ignore
  386. else if (ret == 1)
  387. _CrtDbgBreak();
  388. #endif
  389. #if defined(Q_OS_UNIX) && defined(QT_DEBUG)
  390. abort(); // trap; generates core dump
  391. #else
  392. exit(1); // goodbye cruel world
  393. #endif
  394. }
  395. // } end
  396. }
  397. #endif
  398. LogManager *LogManager::mspInstance = 0;
  399. /**************************************************************************
  400. * Implementation: Operators, Helper
  401. **************************************************************************/
  402. #ifndef QT_NO_DEBUG_STREAM
  403. QDebug operator<<(QDebug debug, const LogManager &rLogManager)
  404. {
  405. Q_UNUSED(rLogManager); // To avoid warning C4100 on VS 2008
  406. QList<Logger *> loggers = rLogManager.loggers();
  407. debug.nospace() << "LogManager("
  408. << "loggerrepository:" << *rLogManager.loggerRepository()
  409. << "log-level:" << rLogManager.logLogger()->level().toString()
  410. << "log-appenders:" << rLogManager.logLogger()->appenders().count()
  411. << "qt-level:" << rLogManager.qtLogger()->level().toString()
  412. << "qt-appenders:" << rLogManager.qtLogger()->appenders().count()
  413. << "handleqtmessages:" << rLogManager.handleQtMessages()
  414. << ")";
  415. return debug.space();
  416. }
  417. #endif // QT_NO_DEBUG_STREAM
  418. } // namespace Log4Qt