| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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. |
| */ |
| |
| #include <log4cxx/logstring.h> |
| #include <log4cxx/xml/domconfigurator.h> |
| #include <log4cxx/appender.h> |
| #include <log4cxx/layout.h> |
| #include <log4cxx/logger.h> |
| #include <log4cxx/logmanager.h> |
| #include <log4cxx/level.h> |
| #include <log4cxx/spi/filter.h> |
| #include <log4cxx/helpers/loglog.h> |
| #include <log4cxx/helpers/stringhelper.h> |
| #include <log4cxx/helpers/loader.h> |
| #include <log4cxx/helpers/optionconverter.h> |
| #include <log4cxx/config/propertysetter.h> |
| #include <log4cxx/spi/errorhandler.h> |
| #include <log4cxx/spi/loggerfactory.h> |
| #include <log4cxx/defaultloggerfactory.h> |
| #include <log4cxx/helpers/filewatchdog.h> |
| #include <log4cxx/helpers/synchronized.h> |
| #include <log4cxx/spi/loggerrepository.h> |
| #include <log4cxx/spi/loggingevent.h> |
| #include <log4cxx/helpers/pool.h> |
| #include <sstream> |
| #include <log4cxx/helpers/transcoder.h> |
| #include <log4cxx/rolling/rollingfileappender.h> |
| #include <log4cxx/rolling/filterbasedtriggeringpolicy.h> |
| #include <apr_xml.h> |
| #include <log4cxx/helpers/bytebuffer.h> |
| #include <log4cxx/helpers/charsetdecoder.h> |
| #include <log4cxx/net/smtpappender.h> |
| #include <log4cxx/helpers/messagebuffer.h> |
| |
| #define LOG4CXX 1 |
| #include <log4cxx/helpers/aprinitializer.h> |
| |
| using namespace log4cxx; |
| using namespace log4cxx::xml; |
| using namespace log4cxx::helpers; |
| using namespace log4cxx::spi; |
| using namespace log4cxx::config; |
| using namespace log4cxx::rolling; |
| |
| |
| #if APR_HAS_THREADS |
| namespace log4cxx |
| { |
| namespace xml |
| { |
| class XMLWatchdog : public FileWatchdog |
| { |
| public: |
| XMLWatchdog(const File& filename) : FileWatchdog(filename) |
| { |
| } |
| |
| /** |
| Call DOMConfigurator#doConfigure with the |
| <code>filename</code> to reconfigure log4cxx. |
| */ |
| void doOnChange() |
| { |
| DOMConfigurator().doConfigure(file, |
| LogManager::getLoggerRepository()); |
| } |
| }; |
| } |
| } |
| XMLWatchdog* DOMConfigurator::xdog = NULL; |
| #endif |
| |
| |
| IMPLEMENT_LOG4CXX_OBJECT(DOMConfigurator) |
| |
| #define CONFIGURATION_TAG "log4j:configuration" |
| #define OLD_CONFIGURATION_TAG "configuration" |
| #define APPENDER_TAG "appender" |
| #define APPENDER_REF_TAG "appender-ref" |
| #define PARAM_TAG "param" |
| #define LAYOUT_TAG "layout" |
| #define ROLLING_POLICY_TAG "rollingPolicy" |
| #define TRIGGERING_POLICY_TAG "triggeringPolicy" |
| #define CATEGORY "category" |
| #define LOGGER "logger" |
| #define LOGGER_REF "logger-ref" |
| #define CATEGORY_FACTORY_TAG "categoryFactory" |
| #define NAME_ATTR "name" |
| #define CLASS_ATTR "class" |
| #define VALUE_ATTR "value" |
| #define ROOT_TAG "root" |
| #define ROOT_REF "root-ref" |
| #define LEVEL_TAG "level" |
| #define PRIORITY_TAG "priority" |
| #define FILTER_TAG "filter" |
| #define ERROR_HANDLER_TAG "errorHandler" |
| #define REF_ATTR "ref" |
| #define ADDITIVITY_ATTR "additivity" |
| #define THRESHOLD_ATTR "threshold" |
| #define STRINGSTREAM_ATTR "stringstream" |
| #define CONFIG_DEBUG_ATTR "configDebug" |
| #define INTERNAL_DEBUG_ATTR "debug" |
| |
| DOMConfigurator::DOMConfigurator() |
| : props(), repository() |
| { |
| } |
| |
| void DOMConfigurator::addRef() const |
| { |
| ObjectImpl::addRef(); |
| } |
| |
| void DOMConfigurator::releaseRef() const |
| { |
| ObjectImpl::releaseRef(); |
| } |
| |
| /** |
| Used internally to parse appenders by IDREF name. |
| */ |
| AppenderPtr DOMConfigurator::findAppenderByName(log4cxx::helpers::Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* element, |
| apr_xml_doc* doc, |
| const LogString& appenderName, |
| AppenderMap& appenders) |
| { |
| AppenderPtr appender; |
| std::string tagName(element->name); |
| |
| if (tagName == APPENDER_TAG) |
| { |
| if (appenderName == getAttribute(utf8Decoder, element, NAME_ATTR)) |
| { |
| appender = parseAppender(p, utf8Decoder, element, doc, appenders); |
| } |
| } |
| |
| if (element->first_child && !appender) |
| { |
| appender = findAppenderByName(p, utf8Decoder, element->first_child, doc, appenderName, appenders); |
| } |
| |
| if (element->next && !appender) |
| { |
| appender = findAppenderByName(p, utf8Decoder, element->next, doc, appenderName, appenders); |
| } |
| |
| return appender; |
| } |
| |
| /** |
| Used internally to parse appenders by IDREF element. |
| */ |
| AppenderPtr DOMConfigurator::findAppenderByReference( |
| log4cxx::helpers::Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* appenderRef, |
| apr_xml_doc* doc, |
| AppenderMap& appenders) |
| { |
| LogString appenderName(subst(getAttribute(utf8Decoder, appenderRef, REF_ATTR))); |
| AppenderMap::const_iterator match = appenders.find(appenderName); |
| AppenderPtr appender; |
| |
| if (match != appenders.end()) |
| { |
| appender = match->second; |
| } |
| else if (doc) |
| { |
| appender = findAppenderByName(p, utf8Decoder, doc->root, doc, appenderName, appenders); |
| |
| if (appender) |
| { |
| appenders.insert(AppenderMap::value_type(appenderName, appender)); |
| } |
| } |
| |
| if (!appender) |
| { |
| LogLog::error(LOG4CXX_STR("No appender named [") + |
| appenderName + LOG4CXX_STR("] could be found.")); |
| } |
| |
| return appender; |
| } |
| |
| /** |
| Used internally to parse an appender element. |
| */ |
| AppenderPtr DOMConfigurator::parseAppender(Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* appenderElement, |
| apr_xml_doc* doc, |
| AppenderMap& appenders) |
| { |
| |
| LogString className(subst(getAttribute(utf8Decoder, appenderElement, CLASS_ATTR))); |
| LogLog::debug(LOG4CXX_STR("Class name: [") + className + LOG4CXX_STR("]")); |
| |
| try |
| { |
| ObjectPtr instance = Loader::loadClass(className).newInstance(); |
| AppenderPtr appender = instance; |
| PropertySetter propSetter(appender); |
| |
| appender->setName(subst(getAttribute(utf8Decoder, appenderElement, NAME_ATTR))); |
| |
| for (apr_xml_elem* currentElement = appenderElement->first_child; |
| currentElement; |
| currentElement = currentElement->next) |
| { |
| |
| std::string tagName(currentElement->name); |
| |
| // Parse appender parameters |
| if (tagName == PARAM_TAG) |
| { |
| setParameter(p, utf8Decoder, currentElement, propSetter); |
| } |
| // Set appender layout |
| else if (tagName == LAYOUT_TAG) |
| { |
| appender->setLayout(parseLayout(p, utf8Decoder, currentElement)); |
| } |
| // Add filters |
| else if (tagName == FILTER_TAG) |
| { |
| std::vector<log4cxx::spi::FilterPtr> filters; |
| parseFilters(p, utf8Decoder, currentElement, filters); |
| |
| for (std::vector<log4cxx::spi::FilterPtr>::iterator iter = filters.begin(); |
| iter != filters.end(); |
| iter++) |
| { |
| appender->addFilter(*iter); |
| } |
| } |
| else if (tagName == ERROR_HANDLER_TAG) |
| { |
| parseErrorHandler(p, utf8Decoder, currentElement, appender, doc, appenders); |
| } |
| else if (tagName == ROLLING_POLICY_TAG) |
| { |
| RollingPolicyPtr rollPolicy(parseRollingPolicy(p, utf8Decoder, currentElement)); |
| RollingFileAppenderPtr rfa(appender); |
| |
| if (rfa != NULL) |
| { |
| rfa->setRollingPolicy(rollPolicy); |
| } |
| } |
| else if (tagName == TRIGGERING_POLICY_TAG) |
| { |
| ObjectPtr policy(parseTriggeringPolicy(p, utf8Decoder, currentElement)); |
| RollingFileAppenderPtr rfa(appender); |
| |
| if (rfa != NULL) |
| { |
| rfa->setTriggeringPolicy(policy); |
| } |
| else |
| { |
| log4cxx::net::SMTPAppenderPtr smtpa(appender); |
| |
| if (smtpa != NULL) |
| { |
| log4cxx::spi::TriggeringEventEvaluatorPtr evaluator(policy); |
| smtpa->setEvaluator(evaluator); |
| } |
| } |
| } |
| else if (tagName == APPENDER_REF_TAG) |
| { |
| LogString refName = subst(getAttribute(utf8Decoder, currentElement, REF_ATTR)); |
| |
| if (appender->instanceof(AppenderAttachable::getStaticClass())) |
| { |
| AppenderAttachablePtr aa(appender); |
| LogLog::debug(LOG4CXX_STR("Attaching appender named [") + |
| refName + LOG4CXX_STR("] to appender named [") + |
| appender->getName() + LOG4CXX_STR("].")); |
| aa->addAppender(findAppenderByReference(p, utf8Decoder, currentElement, doc, appenders)); |
| } |
| else |
| { |
| LogLog::error(LOG4CXX_STR("Requesting attachment of appender named [") + |
| refName + LOG4CXX_STR("] to appender named [") + appender->getName() + |
| LOG4CXX_STR("] which does not implement AppenderAttachable.")); |
| } |
| } |
| } |
| |
| propSetter.activate(p); |
| return appender; |
| } |
| /* Yes, it's ugly. But all of these exceptions point to the same |
| problem: we can't create an Appender */ |
| catch (Exception& oops) |
| { |
| LogLog::error(LOG4CXX_STR("Could not create an Appender. Reported error follows."), |
| oops); |
| return 0; |
| } |
| } |
| |
| /** |
| Used internally to parse an {@link ErrorHandler} element. |
| */ |
| void DOMConfigurator::parseErrorHandler(Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* element, |
| AppenderPtr& appender, |
| apr_xml_doc* doc, |
| AppenderMap& appenders) |
| { |
| |
| ErrorHandlerPtr eh = OptionConverter::instantiateByClassName( |
| subst(getAttribute(utf8Decoder, element, CLASS_ATTR)), |
| ErrorHandler::getStaticClass(), |
| 0); |
| |
| if (eh != 0) |
| { |
| eh->setAppender(appender); |
| |
| PropertySetter propSetter(eh); |
| |
| for (apr_xml_elem* currentElement = element->first_child; |
| currentElement; |
| currentElement = currentElement->next) |
| { |
| std::string tagName(currentElement->name); |
| |
| if (tagName == PARAM_TAG) |
| { |
| setParameter(p, utf8Decoder, currentElement, propSetter); |
| } |
| else if (tagName == APPENDER_REF_TAG) |
| { |
| eh->setBackupAppender(findAppenderByReference(p, utf8Decoder, currentElement, doc, appenders)); |
| } |
| else if (tagName == LOGGER_REF) |
| { |
| LogString loggerName(getAttribute(utf8Decoder, currentElement, REF_ATTR)); |
| LoggerPtr logger = repository->getLogger(loggerName, loggerFactory); |
| eh->setLogger(logger); |
| } |
| else if (tagName == ROOT_REF) |
| { |
| LoggerPtr root = repository->getRootLogger(); |
| eh->setLogger(root); |
| } |
| } |
| |
| propSetter.activate(p); |
| ObjectPtrT<AppenderSkeleton> appSkeleton(appender); |
| |
| if (appSkeleton != 0) |
| { |
| appSkeleton->setErrorHandler(eh); |
| } |
| } |
| } |
| |
| /** |
| Used internally to parse a filter element. |
| */ |
| void DOMConfigurator::parseFilters(Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* element, |
| std::vector<log4cxx::spi::FilterPtr>& filters) |
| { |
| LogString clazz = subst(getAttribute(utf8Decoder, element, CLASS_ATTR)); |
| FilterPtr filter = OptionConverter::instantiateByClassName(clazz, |
| Filter::getStaticClass(), 0); |
| |
| if (filter != 0) |
| { |
| PropertySetter propSetter(filter); |
| |
| for (apr_xml_elem* currentElement = element->first_child; |
| currentElement; |
| currentElement = currentElement->next) |
| { |
| std::string tagName(currentElement->name); |
| |
| if (tagName == PARAM_TAG) |
| { |
| setParameter(p, utf8Decoder, currentElement, propSetter); |
| } |
| } |
| |
| propSetter.activate(p); |
| filters.push_back(filter); |
| } |
| } |
| |
| /** |
| Used internally to parse an category or logger element. |
| */ |
| void DOMConfigurator::parseLogger( |
| log4cxx::helpers::Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* loggerElement, |
| apr_xml_doc* doc, |
| AppenderMap& appenders) |
| { |
| // Create a new Logger object from the <category> element. |
| LogString loggerName = subst(getAttribute(utf8Decoder, loggerElement, NAME_ATTR)); |
| |
| LogLog::debug(LOG4CXX_STR("Retreiving an instance of Logger.")); |
| LoggerPtr logger = repository->getLogger(loggerName, loggerFactory); |
| |
| // Setting up a logger needs to be an atomic operation, in order |
| // to protect potential log operations while logger |
| // configuration is in progress. |
| LOCK_W sync(logger->getMutex()); |
| bool additivity = OptionConverter::toBoolean( |
| subst(getAttribute(utf8Decoder, loggerElement, ADDITIVITY_ATTR)), |
| true); |
| |
| LogLog::debug(LOG4CXX_STR("Setting [") + logger->getName() + LOG4CXX_STR("] additivity to [") + |
| (additivity ? LogString(LOG4CXX_STR("true")) : LogString(LOG4CXX_STR("false"))) + LOG4CXX_STR("].")); |
| logger->setAdditivity(additivity); |
| parseChildrenOfLoggerElement(p, utf8Decoder, loggerElement, logger, false, doc, appenders); |
| } |
| |
| /** |
| Used internally to parse the logger factory element. |
| */ |
| void DOMConfigurator::parseLoggerFactory( |
| log4cxx::helpers::Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* factoryElement) |
| { |
| LogString className(subst(getAttribute(utf8Decoder, factoryElement, CLASS_ATTR))); |
| |
| if (className.empty()) |
| { |
| LogLog::error(LOG4CXX_STR("Logger Factory tag class attribute not found.")); |
| LogLog::debug(LOG4CXX_STR("No Logger Factory configured.")); |
| } |
| else |
| { |
| LogLog::debug(LOG4CXX_STR("Desired logger factory: [") + className + LOG4CXX_STR("]")); |
| loggerFactory = OptionConverter::instantiateByClassName( |
| className, |
| LoggerFactory::getStaticClass(), |
| 0); |
| PropertySetter propSetter(loggerFactory); |
| |
| for (apr_xml_elem* currentElement = factoryElement->first_child; |
| currentElement; |
| currentElement = currentElement->next) |
| { |
| std::string tagName(currentElement->name); |
| |
| if (tagName == PARAM_TAG) |
| { |
| setParameter(p, utf8Decoder, currentElement, propSetter); |
| } |
| } |
| } |
| } |
| |
| /** |
| Used internally to parse the root logger element. |
| */ |
| void DOMConfigurator::parseRoot( |
| log4cxx::helpers::Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* rootElement, |
| apr_xml_doc* doc, |
| AppenderMap& appenders) |
| { |
| LoggerPtr root = repository->getRootLogger(); |
| // logger configuration needs to be atomic |
| LOCK_W sync(root->getMutex()); |
| parseChildrenOfLoggerElement(p, utf8Decoder, rootElement, root, true, doc, appenders); |
| } |
| |
| /** |
| Used internally to parse the children of a logger element. |
| */ |
| void DOMConfigurator::parseChildrenOfLoggerElement( |
| log4cxx::helpers::Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* loggerElement, LoggerPtr logger, bool isRoot, |
| apr_xml_doc* doc, |
| AppenderMap& appenders) |
| { |
| |
| PropertySetter propSetter(logger); |
| |
| // Remove all existing appenders from logger. They will be |
| // reconstructed if need be. |
| logger->removeAllAppenders(); |
| |
| |
| for (apr_xml_elem* currentElement = loggerElement->first_child; |
| currentElement; |
| currentElement = currentElement->next) |
| { |
| std::string tagName(currentElement->name); |
| |
| if (tagName == APPENDER_REF_TAG) |
| { |
| AppenderPtr appender = findAppenderByReference(p, utf8Decoder, currentElement, doc, appenders); |
| LogString refName = subst(getAttribute(utf8Decoder, currentElement, REF_ATTR)); |
| |
| if (appender != 0) |
| { |
| LogLog::debug(LOG4CXX_STR("Adding appender named [") + refName + |
| LOG4CXX_STR("] to logger [") + logger->getName() + LOG4CXX_STR("].")); |
| } |
| else |
| { |
| LogLog::debug(LOG4CXX_STR("Appender named [") + refName + |
| LOG4CXX_STR("] not found.")); |
| } |
| |
| logger->addAppender(appender); |
| |
| } |
| else if (tagName == LEVEL_TAG) |
| { |
| parseLevel(p, utf8Decoder, currentElement, logger, isRoot); |
| } |
| else if (tagName == PRIORITY_TAG) |
| { |
| parseLevel(p, utf8Decoder, currentElement, logger, isRoot); |
| } |
| else if (tagName == PARAM_TAG) |
| { |
| setParameter(p, utf8Decoder, currentElement, propSetter); |
| } |
| } |
| |
| propSetter.activate(p); |
| } |
| |
| /** |
| Used internally to parse a layout element. |
| */ |
| LayoutPtr DOMConfigurator::parseLayout ( |
| log4cxx::helpers::Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* layout_element) |
| { |
| LogString className(subst(getAttribute(utf8Decoder, layout_element, CLASS_ATTR))); |
| LogLog::debug(LOG4CXX_STR("Parsing layout of class: \"") + className + LOG4CXX_STR("\"")); |
| |
| try |
| { |
| ObjectPtr instance = Loader::loadClass(className).newInstance(); |
| LayoutPtr layout = instance; |
| PropertySetter propSetter(layout); |
| |
| for (apr_xml_elem* currentElement = layout_element->first_child; |
| currentElement; |
| currentElement = currentElement->next) |
| { |
| std::string tagName(currentElement->name); |
| |
| if (tagName == PARAM_TAG) |
| { |
| setParameter(p, utf8Decoder, currentElement, propSetter); |
| } |
| } |
| |
| propSetter.activate(p); |
| return layout; |
| } |
| catch (Exception& oops) |
| { |
| LogLog::error(LOG4CXX_STR("Could not create the Layout. Reported error follows."), |
| oops); |
| return 0; |
| } |
| } |
| |
| /** |
| Used internally to parse a triggering policy |
| */ |
| ObjectPtr DOMConfigurator::parseTriggeringPolicy ( |
| log4cxx::helpers::Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* layout_element) |
| { |
| LogString className = subst(getAttribute(utf8Decoder, layout_element, CLASS_ATTR)); |
| LogLog::debug(LOG4CXX_STR("Parsing triggering policy of class: \"") + className + LOG4CXX_STR("\"")); |
| |
| try |
| { |
| ObjectPtr instance = Loader::loadClass(className).newInstance(); |
| PropertySetter propSetter(instance); |
| |
| for (apr_xml_elem* currentElement = layout_element->first_child; |
| currentElement; |
| currentElement = currentElement->next) |
| { |
| std::string tagName(currentElement->name); |
| |
| if (tagName == PARAM_TAG) |
| { |
| setParameter(p, utf8Decoder, currentElement, propSetter); |
| } |
| else if (tagName == FILTER_TAG) |
| { |
| std::vector<log4cxx::spi::FilterPtr> filters; |
| parseFilters(p, utf8Decoder, currentElement, filters); |
| FilterBasedTriggeringPolicyPtr fbtp(instance); |
| |
| if (fbtp != NULL) |
| { |
| for (std::vector<log4cxx::spi::FilterPtr>::iterator iter = filters.begin(); |
| iter != filters.end(); |
| iter++) |
| { |
| fbtp->addFilter(*iter); |
| } |
| } |
| } |
| } |
| |
| propSetter.activate(p); |
| return instance; |
| } |
| catch (Exception& oops) |
| { |
| LogLog::error(LOG4CXX_STR("Could not create the TriggeringPolicy. Reported error follows."), |
| oops); |
| return 0; |
| } |
| } |
| |
| /** |
| Used internally to parse a triggering policy |
| */ |
| RollingPolicyPtr DOMConfigurator::parseRollingPolicy ( |
| log4cxx::helpers::Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* layout_element) |
| { |
| LogString className = subst(getAttribute(utf8Decoder, layout_element, CLASS_ATTR)); |
| LogLog::debug(LOG4CXX_STR("Parsing rolling policy of class: \"") + className + LOG4CXX_STR("\"")); |
| |
| try |
| { |
| ObjectPtr instance = Loader::loadClass(className).newInstance(); |
| RollingPolicyPtr layout = instance; |
| PropertySetter propSetter(layout); |
| |
| for (apr_xml_elem* currentElement = layout_element->first_child; |
| currentElement; |
| currentElement = currentElement->next) |
| { |
| std::string tagName(currentElement->name); |
| |
| if (tagName == PARAM_TAG) |
| { |
| setParameter(p, utf8Decoder, currentElement, propSetter); |
| } |
| } |
| |
| propSetter.activate(p); |
| return layout; |
| } |
| catch (Exception& oops) |
| { |
| LogLog::error(LOG4CXX_STR("Could not create the RollingPolicy. Reported error follows."), |
| oops); |
| return 0; |
| } |
| } |
| |
| |
| |
| /** |
| Used internally to parse a level element. |
| */ |
| void DOMConfigurator::parseLevel( |
| log4cxx::helpers::Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* element, LoggerPtr logger, bool isRoot) |
| { |
| LogString loggerName = logger->getName(); |
| |
| if (isRoot) |
| { |
| loggerName = LOG4CXX_STR("root"); |
| } |
| |
| LogString levelStr(subst(getAttribute(utf8Decoder, element, VALUE_ATTR))); |
| LogLog::debug(LOG4CXX_STR("Level value for ") + loggerName + LOG4CXX_STR(" is [") + levelStr + LOG4CXX_STR("].")); |
| |
| if (StringHelper::equalsIgnoreCase(levelStr, LOG4CXX_STR("INHERITED"), LOG4CXX_STR("inherited")) |
| || StringHelper::equalsIgnoreCase(levelStr, LOG4CXX_STR("NULL"), LOG4CXX_STR("null"))) |
| { |
| if (isRoot) |
| { |
| LogLog::error(LOG4CXX_STR("Root level cannot be inherited. Ignoring directive.")); |
| } |
| else |
| { |
| logger->setLevel(0); |
| } |
| } |
| else |
| { |
| LogString className(subst(getAttribute(utf8Decoder, element, CLASS_ATTR))); |
| |
| if (className.empty()) |
| { |
| logger->setLevel(OptionConverter::toLevel(levelStr, Level::getDebug())); |
| } |
| else |
| { |
| LogLog::debug(LOG4CXX_STR("Desired Level sub-class: [") + className + LOG4CXX_STR("]")); |
| |
| try |
| { |
| Level::LevelClass& levelClass = |
| (Level::LevelClass&)Loader::loadClass(className); |
| LevelPtr level = levelClass.toLevel(levelStr); |
| logger->setLevel(level); |
| } |
| catch (Exception& oops) |
| { |
| LogLog::error( |
| LOG4CXX_STR("Could not create level [") + levelStr + |
| LOG4CXX_STR("]. Reported error follows."), |
| oops); |
| |
| return; |
| } |
| catch (...) |
| { |
| LogLog::error( |
| LOG4CXX_STR("Could not create level [") + levelStr); |
| |
| return; |
| } |
| } |
| } |
| |
| LogLog::debug(loggerName + LOG4CXX_STR(" level set to ") + |
| logger->getEffectiveLevel()->toString()); |
| } |
| |
| void DOMConfigurator::setParameter(log4cxx::helpers::Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* elem, |
| PropertySetter& propSetter) |
| { |
| LogString name(subst(getAttribute(utf8Decoder, elem, NAME_ATTR))); |
| LogString value(subst(getAttribute(utf8Decoder, elem, VALUE_ATTR))); |
| value = subst(value); |
| propSetter.setProperty(name, value, p); |
| } |
| |
| void DOMConfigurator::doConfigure(const File& filename, spi::LoggerRepositoryPtr& repository1) |
| { |
| repository1->setConfigured(true); |
| this->repository = repository1; |
| LogString msg(LOG4CXX_STR("DOMConfigurator configuring file ")); |
| msg.append(filename.getPath()); |
| msg.append(LOG4CXX_STR("...")); |
| LogLog::debug(msg); |
| |
| loggerFactory = new DefaultLoggerFactory(); |
| |
| Pool p; |
| apr_file_t* fd; |
| |
| log4cxx_status_t rv = filename.open(&fd, APR_READ, APR_OS_DEFAULT, p); |
| |
| if (rv != APR_SUCCESS) |
| { |
| LogString msg2(LOG4CXX_STR("Could not open file [")); |
| msg2.append(filename.getPath()); |
| msg2.append(LOG4CXX_STR("].")); |
| LogLog::error(msg2); |
| } |
| else |
| { |
| apr_xml_parser* parser = NULL; |
| apr_xml_doc* doc = NULL; |
| rv = apr_xml_parse_file(p.getAPRPool(), &parser, &doc, fd, 2000); |
| |
| if (rv != APR_SUCCESS) |
| { |
| char errbuf[2000]; |
| char errbufXML[2000]; |
| LogString msg2(LOG4CXX_STR("Error parsing file [")); |
| msg2.append(filename.getPath()); |
| msg2.append(LOG4CXX_STR("], ")); |
| apr_strerror(rv, errbuf, sizeof(errbuf)); |
| LOG4CXX_DECODE_CHAR(lerrbuf, std::string(errbuf)); |
| msg2.append(lerrbuf); |
| |
| if (parser) |
| { |
| apr_xml_parser_geterror(parser, errbufXML, sizeof(errbufXML)); |
| LOG4CXX_DECODE_CHAR(lerrbufXML, std::string(errbufXML)); |
| msg2.append(lerrbufXML); |
| } |
| |
| LogLog::error(msg2); |
| } |
| else |
| { |
| AppenderMap appenders; |
| CharsetDecoderPtr utf8Decoder(CharsetDecoder::getUTF8Decoder()); |
| parse(p, utf8Decoder, doc->root, doc, appenders); |
| } |
| } |
| } |
| |
| void DOMConfigurator::configure(const std::string& filename) |
| { |
| File file(filename); |
| DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository()); |
| } |
| |
| #if LOG4CXX_WCHAR_T_API |
| void DOMConfigurator::configure(const std::wstring& filename) |
| { |
| File file(filename); |
| DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository()); |
| } |
| #endif |
| |
| #if LOG4CXX_UNICHAR_API |
| void DOMConfigurator::configure(const std::basic_string<UniChar>& filename) |
| { |
| File file(filename); |
| DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository()); |
| } |
| #endif |
| |
| #if LOG4CXX_CFSTRING_API |
| void DOMConfigurator::configure(const CFStringRef& filename) |
| { |
| File file(filename); |
| DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository()); |
| } |
| #endif |
| |
| |
| void DOMConfigurator::configureAndWatch(const std::string& filename) |
| { |
| configureAndWatch(filename, FileWatchdog::DEFAULT_DELAY); |
| } |
| |
| #if LOG4CXX_WCHAR_T_API |
| void DOMConfigurator::configureAndWatch(const std::wstring& filename) |
| { |
| configureAndWatch(filename, FileWatchdog::DEFAULT_DELAY); |
| } |
| #endif |
| |
| #if LOG4CXX_UNICHAR_API |
| void DOMConfigurator::configureAndWatch(const std::basic_string<UniChar>& filename) |
| { |
| configureAndWatch(filename, FileWatchdog::DEFAULT_DELAY); |
| } |
| #endif |
| |
| #if LOG4CXX_CFSTRING_API |
| void DOMConfigurator::configureAndWatch(const CFStringRef& filename) |
| { |
| configureAndWatch(filename, FileWatchdog::DEFAULT_DELAY); |
| } |
| #endif |
| |
| void DOMConfigurator::configureAndWatch(const std::string& filename, long delay) |
| { |
| File file(filename); |
| #if APR_HAS_THREADS |
| |
| if ( xdog ) |
| { |
| APRInitializer::unregisterCleanup(xdog); |
| delete xdog; |
| } |
| |
| xdog = new XMLWatchdog(file); |
| APRInitializer::registerCleanup(xdog); |
| xdog->setDelay(delay); |
| xdog->start(); |
| #else |
| DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository()); |
| #endif |
| } |
| |
| #if LOG4CXX_WCHAR_T_API |
| void DOMConfigurator::configureAndWatch(const std::wstring& filename, long delay) |
| { |
| File file(filename); |
| #if APR_HAS_THREADS |
| |
| if ( xdog ) |
| { |
| APRInitializer::unregisterCleanup(xdog); |
| delete xdog; |
| } |
| |
| xdog = new XMLWatchdog(file); |
| APRInitializer::registerCleanup(xdog); |
| xdog->setDelay(delay); |
| xdog->start(); |
| #else |
| DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository()); |
| #endif |
| } |
| #endif |
| |
| #if LOG4CXX_UNICHAR_API |
| void DOMConfigurator::configureAndWatch(const std::basic_string<UniChar>& filename, long delay) |
| { |
| File file(filename); |
| #if APR_HAS_THREADS |
| |
| if ( xdog ) |
| { |
| APRInitializer::unregisterCleanup(xdog); |
| delete xdog; |
| } |
| |
| xdog = new XMLWatchdog(file); |
| APRInitializer::registerCleanup(xdog); |
| xdog->setDelay(delay); |
| xdog->start(); |
| #else |
| DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository()); |
| #endif |
| } |
| #endif |
| |
| #if LOG4CXX_CFSTRING_API |
| void DOMConfigurator::configureAndWatch(const CFStringRef& filename, long delay) |
| { |
| File file(filename); |
| #if APR_HAS_THREADS |
| |
| if ( xdog ) |
| { |
| APRInitializer::unregisterCleanup(xdog); |
| delete xdog; |
| } |
| |
| xdog = new XMLWatchdog(file); |
| APRInitializer::registerCleanup(xdog); |
| xdog->setDelay(delay); |
| xdog->start(); |
| #else |
| DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository()); |
| #endif |
| } |
| #endif |
| |
| void DOMConfigurator::parse( |
| Pool& p, |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* element, |
| apr_xml_doc* doc, |
| AppenderMap& appenders) |
| { |
| std::string rootElementName(element->name); |
| |
| if (rootElementName != CONFIGURATION_TAG) |
| { |
| if (rootElementName == OLD_CONFIGURATION_TAG) |
| { |
| //LogLog::warn(LOG4CXX_STR("The <")+String(OLD_CONFIGURATION_TAG)+ |
| // LOG4CXX_STR("> element has been deprecated.")); |
| //LogLog::warn(LOG4CXX_STR("Use the <")+String(CONFIGURATION_TAG)+ |
| // LOG4CXX_STR("> element instead.")); |
| } |
| else |
| { |
| LogLog::error(LOG4CXX_STR("DOM element is - not a <configuration> element.")); |
| return; |
| } |
| } |
| |
| LogString debugAttrib = subst(getAttribute(utf8Decoder, element, INTERNAL_DEBUG_ATTR)); |
| |
| static const LogString NuLL(LOG4CXX_STR("NULL")); |
| LogLog::debug(LOG4CXX_STR("debug attribute= \"") + debugAttrib + LOG4CXX_STR("\".")); |
| |
| // if the log4j.dtd is not specified in the XML file, then the |
| // "debug" attribute is returned as the empty string. |
| if (!debugAttrib.empty() && debugAttrib != NuLL) |
| { |
| LogLog::setInternalDebugging(OptionConverter::toBoolean(debugAttrib, true)); |
| } |
| else |
| { |
| LogLog::debug(LOG4CXX_STR("Ignoring internalDebug attribute.")); |
| } |
| |
| |
| LogString confDebug = subst(getAttribute(utf8Decoder, element, CONFIG_DEBUG_ATTR)); |
| |
| if (!confDebug.empty() && confDebug != NuLL) |
| { |
| LogLog::warn(LOG4CXX_STR("The \"configDebug\" attribute is deprecated.")); |
| LogLog::warn(LOG4CXX_STR("Use the \"internalDebug\" attribute instead.")); |
| LogLog::setInternalDebugging(OptionConverter::toBoolean(confDebug, true)); |
| } |
| |
| LogString thresholdStr = subst(getAttribute(utf8Decoder, element, THRESHOLD_ATTR)); |
| LogLog::debug(LOG4CXX_STR("Threshold =\"") + thresholdStr + LOG4CXX_STR("\".")); |
| |
| if (!thresholdStr.empty() && thresholdStr != NuLL) |
| { |
| repository->setThreshold(thresholdStr); |
| } |
| |
| LogString strstrValue = subst(getAttribute(utf8Decoder, element, STRINGSTREAM_ATTR)); |
| LogLog::debug(LOG4CXX_STR("Stringstream =\"") + strstrValue + LOG4CXX_STR("\".")); |
| |
| if (!strstrValue.empty() && strstrValue != NuLL) |
| { |
| MessageBufferUseStaticStream(); |
| } |
| |
| apr_xml_elem* currentElement; |
| |
| for (currentElement = element->first_child; |
| currentElement; |
| currentElement = currentElement->next) |
| { |
| std::string tagName(currentElement->name); |
| |
| if (tagName == CATEGORY_FACTORY_TAG) |
| { |
| parseLoggerFactory(p, utf8Decoder, currentElement); |
| } |
| } |
| |
| for (currentElement = element->first_child; |
| currentElement; |
| currentElement = currentElement->next) |
| { |
| std::string tagName(currentElement->name); |
| |
| if (tagName == CATEGORY || tagName == LOGGER) |
| { |
| parseLogger(p, utf8Decoder, currentElement, doc, appenders); |
| } |
| else if (tagName == ROOT_TAG) |
| { |
| parseRoot(p, utf8Decoder, currentElement, doc, appenders); |
| } |
| } |
| } |
| |
| LogString DOMConfigurator::subst(const LogString& value) |
| { |
| try |
| { |
| return OptionConverter::substVars(value, props); |
| } |
| catch (IllegalArgumentException& e) |
| { |
| LogLog::warn(LOG4CXX_STR("Could not perform variable substitution."), e); |
| return value; |
| } |
| } |
| |
| |
| LogString DOMConfigurator::getAttribute( |
| log4cxx::helpers::CharsetDecoderPtr& utf8Decoder, |
| apr_xml_elem* element, |
| const std::string& attrName) |
| { |
| LogString attrValue; |
| |
| for (apr_xml_attr* attr = element->attr; |
| attr; |
| attr = attr->next) |
| { |
| if (attrName == attr->name) |
| { |
| ByteBuffer buf((char*) attr->value, strlen(attr->value)); |
| utf8Decoder->decode(buf, attrValue); |
| } |
| } |
| |
| return attrValue; |
| } |