diff options
Diffstat (limited to 'ext/Log4Qt/src/propertyconfigurator.cpp')
| -rwxr-xr-x | ext/Log4Qt/src/propertyconfigurator.cpp | 588 |
1 files changed, 588 insertions, 0 deletions
diff --git a/ext/Log4Qt/src/propertyconfigurator.cpp b/ext/Log4Qt/src/propertyconfigurator.cpp new file mode 100755 index 0000000..1fe3860 --- /dev/null +++ b/ext/Log4Qt/src/propertyconfigurator.cpp @@ -0,0 +1,588 @@ +/****************************************************************************** + * + * package: Logging + * file: propertyconfigurator.cpp + * created: September 2007 + * author: Martin Heinrich + * + * + * changes 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 "propertyconfigurator.h" + +#include <QtCore/QDebug> +#include <QtCore/QFile> +#include "helpers/configuratorhelper.h" +#include "helpers/factory.h" +#include "helpers/optionconverter.h" +#include "helpers/properties.h" +#include "appender.h" +#include "layout.h" +#include "logger.h" +#include "logmanager.h" +#include "loggerrepository.h" +#include "varia/listappender.h" + + + +namespace Log4Qt +{ + + + /************************************************************************** + * Declarations + **************************************************************************/ + + + + /************************************************************************** + * C helper functions + **************************************************************************/ + + + LOG4QT_DECLARE_STATIC_LOGGER(logger, Log4Qt::PropertyConfigurator) + + + + /************************************************************************** + * Class implementation: PropertyConfigurator + **************************************************************************/ + + + bool PropertyConfigurator::doConfigure(const Properties &rProperties, + LoggerRepository *pLoggerRepository) + { + startCaptureErrors(); + configureFromProperties(rProperties, pLoggerRepository); + return stopCaptureErrors(); + } + + + bool PropertyConfigurator::doConfigure(const QString &rConfigFileName, + LoggerRepository *pLoggerRepository) + { + startCaptureErrors(); + configureFromFile(rConfigFileName, pLoggerRepository); + return stopCaptureErrors(); + } + + + bool PropertyConfigurator::doConfigure(const QSettings &rSettings, + LoggerRepository *pLoggerRepository) + { + startCaptureErrors(); + configureFromSettings(rSettings, pLoggerRepository); + return stopCaptureErrors(); + } + + + bool PropertyConfigurator::configure(const Properties &rProperties) + { + PropertyConfigurator configurator; + return configurator.doConfigure(rProperties); + } + + + bool PropertyConfigurator::configure(const QString &rConfigFilename) + { + PropertyConfigurator configurator; + return configurator.doConfigure(rConfigFilename); + } + + + bool PropertyConfigurator::configure(const QSettings &rSettings) + { + PropertyConfigurator configurator; + return configurator.doConfigure(rSettings); + } + + + bool PropertyConfigurator::configureAndWatch(const QString &rConfigFileName) + { + // Stop an existing watch to avoid a possible concurrent configuration + ConfiguratorHelper::setConfigurationFile(); + if (rConfigFileName.isEmpty()) + return true; + + PropertyConfigurator configurator; + bool result = configurator.doConfigure(rConfigFileName); + ConfiguratorHelper::setConfigurationFile(rConfigFileName, configure); + return result; + } + + + void PropertyConfigurator::configureFromFile(const QString &rConfigFileName, + LoggerRepository *pLoggerRepository) + { + QFile file(rConfigFileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + LogError e = LOG4QT_ERROR(QT_TR_NOOP("Unable to open property file '%1'"), + CONFIGURATOR_OPENING_FILE_ERROR, + "Log4Qt::PropertyConfigurator"); + e << rConfigFileName; + e.addCausingError(LogError(file.errorString(), file.error())); + logger()->error(e); + return; + } + Properties properties; + properties.load(&file); + if (file.error()) + { + LogError e = LOG4QT_ERROR(QT_TR_NOOP("Unable to read property file '%1'"), + CONFIGURATOR_READING_FILE_ERROR, + "Log4Qt::PropertyConfigurator"); + e << rConfigFileName; + e.addCausingError(LogError(file.errorString(), file.error())); + logger()->error(e); + return; + } + configureFromProperties(properties, pLoggerRepository); + } + + + void PropertyConfigurator::configureFromProperties(const Properties &rProperties, + LoggerRepository *pLoggerRepository) + { + if (!pLoggerRepository) + pLoggerRepository = LogManager::loggerRepository(); + + configureGlobalSettings(rProperties, pLoggerRepository); + configureRootLogger(rProperties, pLoggerRepository); + configureNonRootElements(rProperties, pLoggerRepository); + mAppenderRegistry.clear(); + } + + + void PropertyConfigurator::configureFromSettings(const QSettings &rSettings, + LoggerRepository *pLoggerRepository) + { + Properties properties; + properties.load(rSettings); + configureFromProperties(properties, pLoggerRepository); + } + + + void PropertyConfigurator::configureGlobalSettings(const Properties &rProperties, + LoggerRepository *pLoggerRepository) const + { + Q_ASSERT_X(pLoggerRepository, "PropertyConfigurator::configureGlobalSettings()", "pLoggerRepository must not be null."); + + const QLatin1String key_reset("log4j.reset"); + const QLatin1String key_debug("log4j.Debug"); + const QLatin1String key_config_debug("log4j.configDebug"); + const QLatin1String key_threshold("log4j.threshold"); + const QLatin1String key_handle_qt_messages("log4j.handleQtMessages"); + + // Test each global setting and set it + // - Reset: log4j.reset + // - Debug: log4j.Debug, log4j.configDebug + // - Threshold: log4j.threshold + // - Handle Qt Messages: log4j.handleQtMessages + + // Reset + QString value = rProperties.property(key_reset); + if (!value.isEmpty() && OptionConverter::toBoolean(value, false)) + { + // Use LogManager and not pLoggerRepository to reset internal + // logging. + LogManager::resetConfiguration(); + logger()->debug("Reset configuration"); + } + + // Debug + value = rProperties.property(key_debug); + if (value.isNull()) + { + value = rProperties.property(key_config_debug); + if (!value.isNull()) + logger()->warn("[%1] is deprecated. Use [%2] instead.", key_config_debug, key_debug); + } + if (!value.isNull()) + { + // Don't use OptionConverter::toLevel(). Invalid level string is a valid setting + bool ok; + Level level = Level::fromString(value, &ok); + if (!ok) + level = Level::DEBUG_INT; + LogManager::logLogger()->setLevel(level); + logger()->debug("Set level for Log4Qt logging to %1", + LogManager::logLogger()->level().toString()); + } + + // Threshold + value = rProperties.property(key_threshold); + if (!value.isNull()) + { + pLoggerRepository->setThreshold(OptionConverter::toLevel(value, Level::ALL_INT)); + logger()->debug("Set threshold for LoggerRepository to %1", + pLoggerRepository->threshold().toString()); + } + + // Handle Qt messages + value = rProperties.property(key_handle_qt_messages); + if (!value.isNull()) + { + LogManager::setHandleQtMessages(OptionConverter::toBoolean(value, false)); + logger()->debug("Set handling of Qt messages LoggerRepository to %1", + QVariant(LogManager::handleQtMessages()).toString()); + } + } + + + void PropertyConfigurator::configureNonRootElements(const Properties &rProperties, + LoggerRepository *pLoggerRepository) + { + Q_ASSERT_X(pLoggerRepository, "PropertyConfigurator::configureNonRootElements()", "pLoggerRepository must not be null."); + + const QString logger_prefix = QLatin1String("log4j.logger."); + const QString category_prefix = QLatin1String("log4j.category."); + + // Iterate through all entries: + // - Test for the logger/category prefix + // - Convert JAVA class names to C++ ones + // - Parse logger data (Level, Appender) + // - Parse logger additivity + + QStringList keys = rProperties.propertyNames(); + QString key; + Q_FOREACH(key, keys) + { + QString java_name; + if (key.startsWith(logger_prefix)) + java_name = key.mid(logger_prefix.length()); + else if (key.startsWith(category_prefix)) + java_name = key.mid(category_prefix.length()); + QString cpp_name = OptionConverter::classNameJavaToCpp(java_name); + if (!java_name.isEmpty()) + { + Logger *p_logger = pLoggerRepository->logger(cpp_name); + QString value = OptionConverter::findAndSubst(rProperties, key); + parseLogger(rProperties, p_logger, key, value); + parseAdditivityForLogger(rProperties, p_logger, java_name); + } + } + } + + + void PropertyConfigurator::configureRootLogger(const Properties &rProperties, + LoggerRepository *pLoggerRepository) + { + Q_ASSERT_X(pLoggerRepository, "PropertyConfigurator::configureRootLogger()", "pLoggerRepository must not be null."); + + const QLatin1String key_root_logger("log4j.rootLogger"); + const QLatin1String key_root_category("log4j.rootCategory"); + + // - Test for the logger/category prefix + // - Parse logger data for root logger + + QString key = key_root_logger; + QString value = OptionConverter::findAndSubst(rProperties, key); + if (value.isNull()) + { + key = key_root_category; + value = OptionConverter::findAndSubst(rProperties, key); + if (!value.isNull()) + logger()->warn("[%1] is deprecated. Use [%2] instead.", key_root_category, key_root_logger); + } + + if (value.isNull()) + logger()->debug("Could not find root logger information. Is this correct?"); + else + parseLogger(rProperties, pLoggerRepository->rootLogger(), key, value); + } + + + void PropertyConfigurator::parseAdditivityForLogger(const Properties &rProperties, + Logger *pLogger, + const QString &rLog4jName) const + { + Q_ASSERT_X(pLogger, "parseAdditivityForLogger()", "pLogger must not be null."); + + const QLatin1String additivity_prefix("log4j.additivity."); + + // - Lookup additivity key for logger + // - Set additivity, if specified + + QString key = additivity_prefix + rLog4jName; + QString value = OptionConverter::findAndSubst(rProperties, key); + logger()->debug("Parsing additivity for logger: key '%1', value '%2'", key, value); + if (!value.isEmpty()) + { + bool additivity = OptionConverter::toBoolean(value, true); + logger()->debug("Setting additivity for logger '%1' to '%2'", pLogger->name(), QVariant(value).toString()); + pLogger->setAdditivity(additivity); + } + } + + + LogObjectPtr<Appender> PropertyConfigurator::parseAppender(const Properties &rProperties, + const QString &rName) + { + // - Test if appender has been parsed before + // - Find appender key + // - Create appender object + // - Set layout, if required by appender + // - Set properties + // - Activate options + // - Add appender to registry + + const QLatin1String appender_prefix("log4j.appender."); + + logger()->debug("Parsing appender named '%1'", rName); + + if (mAppenderRegistry.contains(rName)) + { + logger()->debug("Appender '%1' was already parsed.", rName); + return mAppenderRegistry.value(rName); + } + + QString key = appender_prefix + rName; + QString value = OptionConverter::findAndSubst(rProperties, key); + if (value.isNull()) + { + LogError e = LOG4QT_ERROR(QT_TR_NOOP("Missing appender definition for appender named '%1'"), + CONFIGURATOR_MISSING_APPENDER_ERROR, + "Log4Qt::PropertyConfigurator"); + e << rName; + logger()->error(e); + return 0; + } + LogObjectPtr<Appender> p_appender = Factory::createAppender(value); + if (!p_appender) + { + LogError e = LOG4QT_ERROR(QT_TR_NOOP("Unable to create appender of class '%1' named '%2'"), + CONFIGURATOR_UNKNOWN_APPENDER_CLASS_ERROR, + "Log4Qt::PropertyConfigurator"); + e << value << rName; + logger()->error(e); + return 0; + } + p_appender->setName(rName); + + if (p_appender->requiresLayout()) + { + LogObjectPtr<Layout> p_layout = parseLayout(rProperties, key); + if (p_layout) + p_appender->setLayout(p_layout); + else + return 0; + } + + QStringList exclusions; + exclusions << QLatin1String("layout"); + setProperties(rProperties, key + QLatin1String("."), exclusions, p_appender); + AppenderSkeleton *p_appenderskeleton = qobject_cast<AppenderSkeleton *>(p_appender); + if (p_appenderskeleton) + p_appenderskeleton->activateOptions(); + + mAppenderRegistry.insert(rName, p_appender); + return p_appender; + } + + + LogObjectPtr<Layout> PropertyConfigurator::parseLayout(const Properties &rProperties, + const QString &rAppenderKey) + { + Q_ASSERT_X(!rAppenderKey.isEmpty(), "PropertyConfigurator::parseLayout()", "rAppenderKey must not be empty."); + + // - Find layout key + // - Create layput object + // - Set properties + // - Activate options + + const QLatin1String layout_suffix(".layout"); + + logger()->debug("Parsing layout for appender named '%1'", rAppenderKey); + + QString key = rAppenderKey + layout_suffix; + QString value = OptionConverter::findAndSubst(rProperties, key); + if (value.isNull()) + { + LogError e = LOG4QT_ERROR(QT_TR_NOOP("Missing layout definition for appender '%1'"), + CONFIGURATOR_MISSING_LAYOUT_ERROR, + "Log4Qt::PropertyConfigurator"); + e << rAppenderKey; + logger()->error(e); + return 0; + } + LogObjectPtr<Layout> p_layout = Factory::createLayout(value); + if (!p_layout) + { + LogError e = LOG4QT_ERROR(QT_TR_NOOP("Unable to create layoput of class '%1' requested by appender '%2'"), + CONFIGURATOR_UNKNOWN_LAYOUT_CLASS_ERROR, + "Log4Qt::PropertyConfigurator"); + e << value << rAppenderKey; + logger()->error(e); + return 0; + } + + QStringList exclusions; + setProperties(rProperties, key + QLatin1String("."), QStringList(), p_layout); + p_layout->activateOptions(); + + return p_layout; + } + + + void PropertyConfigurator::parseLogger(const Properties &rProperties, + Logger *pLogger, + const QString &rKey, + const QString &rValue) + { + Q_ASSERT_X(pLogger, "PropertyConfigurator::parseLogger()", "pLogger must not be null."); + Q_ASSERT_X(!rKey.isEmpty(), "PropertyConfigurator::parseLogger()", "rKey must not be empty."); + + const QLatin1String keyword_inherited("INHERITED"); + + // - Split value on comma + // - If level value, is specified + // - Test for NULL and INHERITED + // - Ensure root logger is not set to NULL + // - Set level + // - For each entry + // - Create Appender + + logger()->debug("Parsing logger: key '%1', value '%2'", rKey, rValue); + QStringList appenders = rValue.split(QLatin1Char(',')); + QStringListIterator i (appenders); + + // First entry is the level. There will be always one entry, even if the rValue is + // empty or does not contain a comma. + QString value = i.next().trimmed(); + if (!value.isEmpty()) + { + Level level; + if (value.compare(keyword_inherited,Qt::CaseInsensitive) == 0) + level = Level::NULL_INT; + else + level = OptionConverter::toLevel(value, Level::DEBUG_INT); + if (level == Level::NULL_INT && pLogger->name() == QString()) + logger()->warn("The root logger level cannot be set to NULL."); + else + { + pLogger->setLevel(level); + logger()->debug("Set level for logger '%1' to '%2'", + pLogger->name(), pLogger->level().toString()); + } + } + + pLogger->removeAllAppenders(); + while(i.hasNext()) + { + value = i.next().trimmed(); + if(value.isEmpty()) + continue; + LogObjectPtr<Appender> p_appender = parseAppender(rProperties, value); + if (p_appender) + pLogger->addAppender(p_appender); + } + } + + + void PropertyConfigurator::setProperties(const Properties &rProperties, + const QString &rPrefix, + const QStringList &rExclusions, + QObject *pObject) + { + Q_ASSERT_X(!rPrefix.isEmpty(), "PropertyConfigurator::setProperties()", "rPrefix must not be empty."); + Q_ASSERT_X(pObject, "PropertyConfigurator::setProperties()", "pObject must not be null."); + + // Iterate through all entries: + // - Test for prefix to determine, if setting is for object + // - Skip empty property name + // - Skip property names in exclusion list + // - Set property on object + + logger()->debug("Setting properties for object of class '%1' from keys starting with '%2'", + QLatin1String(pObject->metaObject()->className()), + rPrefix); + + QStringList keys = rProperties.propertyNames(); + QString key; + Q_FOREACH(key, keys) + { + if (!key.startsWith(rPrefix)) + continue; + QString property = key.mid(rPrefix.length()); + if (property.isEmpty()) + continue; + QStringList split_property = property.split(QLatin1Char('.')); + if (rExclusions.contains(split_property.at(0), Qt::CaseInsensitive)) + continue; + QString value = OptionConverter::findAndSubst(rProperties, key); + Factory::setObjectProperty(pObject, property, value); + } + } + + + void PropertyConfigurator::startCaptureErrors() + { + Q_ASSERT_X(!mpConfigureErrors, "PropertyConfigurator::startCaptureErrors()", "mpConfigureErrors must be empty."); + + mpConfigureErrors = new ListAppender; + mpConfigureErrors->setName(QLatin1String("PropertyConfigurator")); + mpConfigureErrors->setConfiguratorList(true); + mpConfigureErrors->setThreshold(Level::ERROR_INT); + LogManager::logLogger()->addAppender(mpConfigureErrors); + } + + + bool PropertyConfigurator::stopCaptureErrors() + { + Q_ASSERT_X(mpConfigureErrors, "PropertyConfigurator::stopCaptureErrors()", "mpConfigureErrors must not be empty."); + + LogManager::logLogger()->removeAppender(mpConfigureErrors); + ConfiguratorHelper::setConfigureError(mpConfigureErrors->list()); + bool result = (mpConfigureErrors->list().count() == 0); + mpConfigureErrors = 0; + return result; + } + + + + /************************************************************************** + * Implementation: Operators, Helper + **************************************************************************/ + + +#ifndef QT_NO_DEBUG_STREAM + QDebug operator<<(QDebug debug, + const PropertyConfigurator &rPropertyConfigurator) + { + Q_UNUSED(rPropertyConfigurator); + debug.nospace() << "PropertyConfigurator(" + << ")"; + return debug.space(); + } +#endif + + + +} // namespace Log4Qt Logging |
