123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- /******************************************************************************
- *
- * package: Log4Qt
- * file: logmanager.cpp
- * created: September 2007
- * author: Martin Heinrich
- *
- *
- * changes: Sep 2008, Martin Heinrich:
- * - Resolved compilation problem with Microsoft Visual Studio 2005
- * Feb 2009, Martin Heinrich
- * - Fixed VS 2008 unreferenced formal parameter warning by using
- * Q_UNUSED in operator<<.
- *
- *
- * Copyright 2007 - 2009 Martin Heinrich
- *
- * 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.
- *
- ******************************************************************************/
- /******************************************************************************
- * Dependencies
- ******************************************************************************/
- #include "log4qt/logmanager.h"
- #include <QtCore/QCoreApplication>
- #include <QtCore/QDebug>
- #include <QtCore/QFile>
- #include <QtCore/QMutex>
- #include <QtCore/QSettings>
- #include <QtCore/QStringList>
- #include "log4qt/consoleappender.h"
- #include "log4qt/helpers/datetime.h"
- #include "log4qt/helpers/initialisationhelper.h"
- #include "log4qt/helpers/optionconverter.h"
- #include "log4qt/hierarchy.h"
- #include "log4qt/propertyconfigurator.h"
- #include "log4qt/ttcclayout.h"
- #include "log4qt/varia/denyallfilter.h"
- #include "log4qt/varia/levelrangefilter.h"
- namespace Log4Qt
- {
-
-
- /**************************************************************************
- * Declarations
- **************************************************************************/
-
-
- /**************************************************************************
- * C helper functions
- **************************************************************************/
-
-
- LOG4QT_DECLARE_STATIC_LOGGER(static_logger, Log4Qt::LogManager)
- LOG4QT_GLOBAL_STATIC(QMutex, singleton_guard)
-
-
-
- /**************************************************************************
- * Class implementation: LogManager
- **************************************************************************/
-
-
- LogManager::LogManager() :
- mObjectGuard(QMutex::Recursive), // Recursive for doStartup() to call doConfigureLogLogger()
- mpLoggerRepository(new Hierarchy()),
- mHandleQtMessages(false),
- mOldQtMsgHandler(0)
- {
- }
-
-
- LogManager::~LogManager()
- {
- static_logger()->warn("Unexpected destruction of LogManager");
-
- // doSetConfigureHandleQtMessages(false);
- // delete mpLoggerRepository;
- }
-
-
- Logger *LogManager::rootLogger()
- {
- return instance()->mpLoggerRepository->rootLogger();
- }
-
-
- QList<Logger*> LogManager::loggers()
- {
- return instance()->mpLoggerRepository->loggers();
- }
-
-
- Level LogManager::threshold()
- {
- return instance()->mpLoggerRepository->threshold();
- }
-
-
- void LogManager::setThreshold(Level level)
- {
- instance()->mpLoggerRepository->setThreshold(level);
- }
-
-
- bool LogManager::exists(const char *pName)
- {
- return instance()->mpLoggerRepository->exists(QLatin1String(pName));
- }
-
-
- LogManager *LogManager::instance()
- {
- // Do not use LOG4QT_GLOBAL_STATIC. The LogManager is rather expensive
- // to construct, an exit handler must be set and doStartup must be
- // called.
-
- if (!mspInstance)
- {
- QMutexLocker locker(singleton_guard());
- if (!mspInstance)
- {
- mspInstance = new LogManager;
- // qAddPostRoutine(shutdown);
- atexit(shutdown);
- mspInstance->doConfigureLogLogger();
- mspInstance->welcome();
- mspInstance->doStartup();
- }
- }
- return mspInstance;
- }
-
-
- Logger *LogManager::logger(const QString &rName)
- {
- return instance()->mpLoggerRepository->logger(rName);
- }
-
-
- void LogManager::resetConfiguration()
- {
- setHandleQtMessages(false);
- instance()->mpLoggerRepository->resetConfiguration();
- configureLogLogger();
- }
-
-
- const char* LogManager::version()
- {
- return LOG4QT_VERSION_STR;
- }
-
-
- void LogManager::shutdown()
- {
- instance()->mpLoggerRepository->shutdown();
- }
-
-
- void LogManager::doSetHandleQtMessages(bool handleQtMessages)
- {
- QMutexLocker locker(&mObjectGuard);
-
- if (instance()->mHandleQtMessages == handleQtMessages)
- return;
-
- instance()->mHandleQtMessages = handleQtMessages;
- if (instance()->mHandleQtMessages)
- {
- static_logger()->trace("Activate Qt message handling");
- #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
- instance()->mOldQtMsgHandler = qInstallMsgHandler(qtMessageHandler);
- #else
- instance()->mOldQtMsgHandler = qInstallMessageHandler(qtMessageHandler);
- #endif
- }
- else
- {
- static_logger()->trace("Deactivate Qt message handling");
- #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
- qInstallMsgHandler(instance()->mOldQtMsgHandler);
- #else
- qInstallMessageHandler(instance()->mOldQtMsgHandler);
- #endif
- }
- }
-
-
- void LogManager::doConfigureLogLogger()
- {
- QMutexLocker locker(&instance()->mObjectGuard);
-
- // Level
- QString value = InitialisationHelper::setting(QLatin1String("Debug"),
- QLatin1String("ERROR"));
- logLogger()->setLevel(OptionConverter::toLevel(value, Level::DEBUG_INT));
-
- // Common layout
- TTCCLayout *p_layout = new TTCCLayout();
- p_layout->setName(QLatin1String("LogLog TTCC"));
- p_layout->setContextPrinting(false);
- p_layout->activateOptions();
-
- // Common deny all filter
- Filter *p_denyall = new DenyAllFilter();
- p_denyall->activateOptions();
-
- // ConsoleAppender on stdout for all events <= INFO
- ConsoleAppender *p_appender;
- LevelRangeFilter *p_filter;
- p_appender = new ConsoleAppender(p_layout, ConsoleAppender::STDOUT_TARGET);
- p_filter = new LevelRangeFilter();
- p_filter->setNext(p_denyall);
- p_filter->setLevelMin(Level::NULL_INT);
- p_filter->setLevelMax(Level::INFO_INT);
- p_filter->activateOptions();
- p_appender->setName(QLatin1String("LogLog stdout"));
- p_appender->addFilter(p_filter);
- p_appender->activateOptions();
- logLogger()->addAppender(p_appender);
-
- // ConsoleAppender on stderr for all events >= WARN
- p_appender = new ConsoleAppender(p_layout, ConsoleAppender::STDERR_TARGET);
- p_filter = new LevelRangeFilter();
- p_filter->setNext(p_denyall);
- p_filter->setLevelMin(Level::WARN_INT);
- p_filter->setLevelMax(Level::OFF_INT);
- p_filter->activateOptions();
- p_appender->setName(QLatin1String("LogLog stderr"));
- p_appender->addFilter(p_filter);
- p_appender->activateOptions();
- logLogger()->addAppender(p_appender);
- }
-
-
- void LogManager::doStartup()
- {
- QMutexLocker locker(&instance()->mObjectGuard);
-
- // Override
- QString default_value = QLatin1String("false");
- QString value = InitialisationHelper::setting(QLatin1String("DefaultInitOverride"),
- default_value);
- if (value != default_value)
- {
- static_logger()->debug("DefaultInitOverride is set. Aborting default initialisation");
- return;
- }
-
- // Configuration using setting Configuration
- value = InitialisationHelper::setting(QLatin1String("Configuration"));
- if (QFile::exists(value))
- {
- static_logger()->debug("Default initialisation configures from file '%1' specified by Configure", value);
- PropertyConfigurator::configure(value);
- return;
- }
-
- // Configuration using setting
- if (QCoreApplication::instance())
- {
- const QLatin1String log4qt_group("Log4Qt");
- const QLatin1String properties_group("Properties");
- QSettings s;
- s.beginGroup(log4qt_group);
- if (s.childGroups().contains(properties_group))
- {
- const QString group(QLatin1String("Log4Qt/Properties"));
- static_logger()->debug("Default initialisation configures from setting '%1/%2'", log4qt_group, properties_group);
- s.beginGroup(properties_group);
- PropertyConfigurator::configure(s);
- return;
- }
- }
- // Configuration using default file
- const QString default_file(QLatin1String("log4qt.properties"));
- if (QFile::exists(default_file))
- {
- static_logger()->debug("Default initialisation configures from default file '%1'", default_file);
- PropertyConfigurator::configure(default_file);
- return;
- }
-
- static_logger()->debug("Default initialisation leaves package unconfigured");
- }
-
-
- void LogManager::welcome()
- {
- static_logger()->info("Initialising Log4Qt %1",
- QLatin1String(LOG4QT_VERSION_STR));
-
- // Debug: Info
- if (static_logger()->isDebugEnabled())
- {
- // Create a nice timestamp with UTC offset
- DateTime start_time = DateTime::fromMilliSeconds(InitialisationHelper::startTime());
- QString offset;
- {
- QDateTime utc = start_time.toUTC();
- QDateTime local = start_time.toLocalTime();
- QDateTime local_as_utc = QDateTime(local.date(), local.time(), Qt::UTC);
- int min = utc.secsTo(local_as_utc) / 60;
- if (min < 0)
- offset += QLatin1Char('-');
- else
- offset += QLatin1Char('+');
- min = abs(min);
- offset += QString::number(min / 60).rightJustified(2, QLatin1Char('0'));
- offset += QLatin1Char(':');
- offset += QString::number(min % 60).rightJustified(2, QLatin1Char('0'));
- }
- static_logger()->debug("Program startup time is %1 (UTC%2)",
- start_time.toString(QLatin1String("ISO8601")),
- offset);
- static_logger()->debug("Internal logging uses the level %1",
- logLogger()->level().toString());
- }
-
- // Trace: Dump settings
- if (static_logger()->isTraceEnabled())
- {
- static_logger()->trace("Settings from the system environment:");
- QString entry;
- Q_FOREACH (entry, InitialisationHelper::environmentSettings().keys())
- static_logger()->trace(" %1: '%2'",
- entry,
- InitialisationHelper::environmentSettings().value(entry));
-
- static_logger()->trace("Settings from the application settings:");
- if (QCoreApplication::instance())
- {
- const QLatin1String log4qt_group("Log4Qt");
- const QLatin1String properties_group("Properties");
- static_logger()->trace(" %1:", log4qt_group);
- QSettings s;
- s.beginGroup(log4qt_group);
- Q_FOREACH (entry, s.childKeys())
- static_logger()->trace(" %1: '%2'",
- entry,
- s.value(entry).toString());
- static_logger()->trace(" %1/%2:", log4qt_group, properties_group);
- s.beginGroup(properties_group);
- Q_FOREACH (entry, s.childKeys())
- static_logger()->trace(" %1: '%2'",
- entry,
- s.value(entry).toString());
- } else
- static_logger()->trace(" QCoreApplication::instance() is not available");
- }
- }
-
- #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
- void LogManager::qtMessageHandler(QtMsgType type, const char *pMessage)
- {
- Level level;
- switch (type)
- {
- case QtDebugMsg:
- level = Level::DEBUG_INT;
- break;
- case QtWarningMsg:
- level = Level::WARN_INT;
- break;
- case QtCriticalMsg:
- level = Level::ERROR_INT;
- break;
- case QtFatalMsg:
- level = Level::FATAL_INT;
- break;
- default:
- level = Level::TRACE_INT;
- }
- instance()->qtLogger()->log(level, pMessage);
- // Qt fatal behaviour copied from global.cpp qt_message_output()
- // begin {
- if ((type == QtFatalMsg) ||
- ((type == QtWarningMsg) && (!qgetenv("QT_FATAL_WARNINGS").isNull())) )
- {
- #if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
- // get the current report mode
- int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
- _CrtSetReportMode(_CRT_ERROR, reportMode);
- int ret = _CrtDbgReport(_CRT_ERROR, __FILE__, __LINE__, QT_VERSION_STR, pMessage);
- if (ret == 0 && reportMode & _CRTDBG_MODE_WNDW)
- return; // ignore
- else if (ret == 1)
- _CrtDbgBreak();
- #endif
- #if defined(Q_OS_UNIX) && defined(QT_DEBUG)
- abort(); // trap; generates core dump
- #else
- exit(1); // goodbye cruel world
- #endif
- }
- // } end
- }
- #else
- void LogManager::qtMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
- {
- Q_UNUSED(context)
- Level level;
- switch (type)
- {
- case QtDebugMsg:
- level = Level::DEBUG_INT;
- break;
- case QtWarningMsg:
- level = Level::WARN_INT;
- break;
- case QtCriticalMsg:
- level = Level::ERROR_INT;
- break;
- case QtFatalMsg:
- level = Level::FATAL_INT;
- break;
- default:
- level = Level::TRACE_INT;
- }
- instance()->qtLogger()->log(level, message);
- // Qt fatal behaviour copied from global.cpp qt_message_output()
- // begin {
- if ((type == QtFatalMsg) ||
- ((type == QtWarningMsg) && (!qgetenv("QT_FATAL_WARNINGS").isNull())) )
- {
- #if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
- // get the current report mode
- int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
- _CrtSetReportMode(_CRT_ERROR, reportMode);
- int ret = _CrtDbgReport(_CRT_ERROR, __FILE__, __LINE__, QT_VERSION_STR, message.toUtf8().constData());
- if (ret == 0 && reportMode & _CRTDBG_MODE_WNDW)
- return; // ignore
- else if (ret == 1)
- _CrtDbgBreak();
- #endif
- #if defined(Q_OS_UNIX) && defined(QT_DEBUG)
- abort(); // trap; generates core dump
- #else
- exit(1); // goodbye cruel world
- #endif
- }
- // } end
- }
- #endif
-
-
- LogManager *LogManager::mspInstance = 0;
-
-
-
- /**************************************************************************
- * Implementation: Operators, Helper
- **************************************************************************/
-
-
- #ifndef QT_NO_DEBUG_STREAM
- QDebug operator<<(QDebug debug, const LogManager &rLogManager)
- {
- Q_UNUSED(rLogManager); // To avoid warning C4100 on VS 2008
- QList<Logger *> loggers = rLogManager.loggers();
- debug.nospace() << "LogManager("
- << "loggerrepository:" << *rLogManager.loggerRepository()
- << "log-level:" << rLogManager.logLogger()->level().toString()
- << "log-appenders:" << rLogManager.logLogger()->appenders().count()
- << "qt-level:" << rLogManager.qtLogger()->level().toString()
- << "qt-appenders:" << rLogManager.qtLogger()->appenders().count()
- << "handleqtmessages:" << rLogManager.handleQtMessages()
- << ")";
- return debug.space();
- }
- #endif // QT_NO_DEBUG_STREAM
-
-
- } // namespace Log4Qt
|