/* * 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. */ #if defined(_MSC_VER) #pragma warning ( disable: 4231 4251 4275 4786 ) #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(LOG4CXX) #define LOG4CXX 1 #endif #include #include #include #include #include "assert.h" using namespace log4cxx; using namespace log4cxx::spi; using namespace log4cxx::helpers; IMPLEMENT_LOG4CXX_OBJECT(Hierarchy) Hierarchy::Hierarchy() : pool(), mutex(pool), loggers(new LoggerMap()), provisionNodes(new ProvisionNodeMap()) { synchronized sync(mutex); root = new RootLogger(pool, Level::getDebug()); root->setHierarchy(this); defaultFactory = new DefaultLoggerFactory(); emittedNoAppenderWarning = false; configured = false; thresholdInt = Level::ALL_INT; threshold = Level::getAll(); emittedNoResourceBundleWarning = false; } Hierarchy::~Hierarchy() { // TODO LOGCXX-430 // https://issues.apache.org/jira/browse/LOGCXX-430?focusedCommentId=15175254&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-15175254 #ifndef APR_HAS_THREADS delete loggers; delete provisionNodes; #endif } void Hierarchy::addRef() const { ObjectImpl::addRef(); } void Hierarchy::releaseRef() const { ObjectImpl::releaseRef(); } void Hierarchy::addHierarchyEventListener(const spi::HierarchyEventListenerPtr& listener) { synchronized sync(mutex); if (std::find(listeners.begin(), listeners.end(), listener) != listeners.end()) { LogLog::warn(LOG4CXX_STR("Ignoring attempt to add an existent listener.")); } else { listeners.push_back(listener); } } void Hierarchy::clear() { synchronized sync(mutex); loggers->clear(); } void Hierarchy::emitNoAppenderWarning(const LoggerPtr& logger) { bool emitWarning = false; { synchronized sync(mutex); emitWarning = !emittedNoAppenderWarning; emittedNoAppenderWarning = true; } // No appender in hierarchy, warn user only once. if(emitWarning) { LogLog::warn(((LogString) LOG4CXX_STR("No appender could be found for logger (")) + logger->getName() + LOG4CXX_STR(").")); LogLog::warn(LOG4CXX_STR("Please initialize the log4cxx system properly.")); } } LoggerPtr Hierarchy::exists(const LogString& name) { synchronized sync(mutex); LoggerPtr logger; LoggerMap::iterator it = loggers->find(name); if (it != loggers->end()) { logger = it->second; } return logger; } void Hierarchy::setThreshold(const LevelPtr& l) { if (l != 0) { synchronized sync(mutex); thresholdInt = l->toInt(); threshold = l; if (thresholdInt != Level::ALL_INT) { setConfigured(true); } } } void Hierarchy::setThreshold(const LogString& levelStr) { LevelPtr l(Level::toLevelLS(levelStr, 0)); if(l != 0) { setThreshold(l); } else { LogLog::warn(((LogString) LOG4CXX_STR("No level could be found named \"")) + levelStr + LOG4CXX_STR("\".")); } } void Hierarchy::fireAddAppenderEvent(const LoggerPtr& logger, const AppenderPtr& appender) { setConfigured(true); HierarchyEventListenerList clonedList; { synchronized sync(mutex); clonedList = listeners; } HierarchyEventListenerList::iterator it, itEnd = clonedList.end(); HierarchyEventListenerPtr listener; for(it = clonedList.begin(); it != itEnd; it++) { listener = *it; listener->addAppenderEvent(logger, appender); } } void Hierarchy::fireRemoveAppenderEvent(const LoggerPtr& logger, const AppenderPtr& appender) { HierarchyEventListenerList clonedList; { synchronized sync(mutex); clonedList = listeners; } HierarchyEventListenerList::iterator it, itEnd = clonedList.end(); HierarchyEventListenerPtr listener; for(it = clonedList.begin(); it != itEnd; it++) { listener = *it; listener->removeAppenderEvent(logger, appender); } } const LevelPtr& Hierarchy::getThreshold() const { return threshold; } LoggerPtr Hierarchy::getLogger(const LogString& name) { return getLogger(name, defaultFactory); } LoggerPtr Hierarchy::getLogger(const LogString& name, const spi::LoggerFactoryPtr& factory) { synchronized sync(mutex); LoggerMap::iterator it = loggers->find(name); if (it != loggers->end()) { return it->second; } else { LoggerPtr logger(factory->makeNewLoggerInstance(pool, name)); logger->setHierarchy(this); loggers->insert(LoggerMap::value_type(name, logger)); ProvisionNodeMap::iterator it2 = provisionNodes->find(name); if (it2 != provisionNodes->end()) { updateChildren(it2->second, logger); provisionNodes->erase(it2); } updateParents(logger); return logger; } } LoggerList Hierarchy::getCurrentLoggers() const { synchronized sync(mutex); LoggerList v; LoggerMap::const_iterator it, itEnd = loggers->end(); for (it = loggers->begin(); it != itEnd; it++) { v.push_back(it->second); } return v; } LoggerPtr Hierarchy::getRootLogger() const { return root; } bool Hierarchy::isDisabled(int level) const { if(!configured) { synchronized sync(mutex); if (!configured) { DefaultConfigurator::configure( const_cast(this)); } } return thresholdInt > level; } void Hierarchy::resetConfiguration() { synchronized sync(mutex); getRootLogger()->setLevel(Level::getDebug()); root->setResourceBundle(0); setThreshold(Level::getAll()); shutdown(); // nested locks are OK LoggerList loggers1 = getCurrentLoggers(); LoggerList::iterator it, itEnd = loggers1.end(); for (it = loggers1.begin(); it != itEnd; it++) { LoggerPtr& logger = *it; logger->setLevel(0); logger->setAdditivity(true); logger->setResourceBundle(0); } //rendererMap.clear(); } void Hierarchy::shutdown() { synchronized sync(mutex); setConfigured(false); LoggerPtr root1 = getRootLogger(); // begin by closing nested appenders root1->closeNestedAppenders(); LoggerList loggers1 = getCurrentLoggers(); LoggerList::iterator it, itEnd = loggers1.end(); for (it = loggers1.begin(); it != itEnd; it++) { LoggerPtr& logger = *it; logger->closeNestedAppenders(); } // then, remove all appenders root1->removeAllAppenders(); for (it = loggers1.begin(); it != itEnd; it++) { LoggerPtr& logger = *it; logger->removeAllAppenders(); } } void Hierarchy::updateParents(LoggerPtr logger) { synchronized sync(mutex); const LogString name(logger->getName()); int length = name.size(); bool parentFound = false; // if name = "w.x.y.z", loop through "w.x.y", "w.x" and "w", but not "w.x.y.z" for(size_t i = name.find_last_of(0x2E /* '.' */, length-1); (i != LogString::npos) && (i != 0); i = name.find_last_of(0x2E /* '.' */, i-1)) { LogString substr = name.substr(0, i); LoggerMap::iterator it = loggers->find(substr); if(it != loggers->end()) { parentFound = true; logger->parent = it->second; break; // no need to update the ancestors of the closest ancestor } else { ProvisionNodeMap::iterator it2 = provisionNodes->find(substr); if (it2 != provisionNodes->end()) { it2->second.push_back(logger); } else { ProvisionNode node(1, logger); provisionNodes->insert( ProvisionNodeMap::value_type(substr, node)); } } } // If we could not find any existing parents, then link with root. if(!parentFound) { logger->parent = root; } } void Hierarchy::updateChildren(ProvisionNode& pn, LoggerPtr logger) { ProvisionNode::iterator it, itEnd = pn.end(); for(it = pn.begin(); it != itEnd; it++) { LoggerPtr& l = *it; // Unless this child already points to a correct (lower) parent, // make cat.parent point to l.parent and l.parent to cat. if(!StringHelper::startsWith(l->parent->name, logger->name)) { logger->parent = l->parent; l->parent = logger; } } } void Hierarchy::setConfigured(bool newValue) { synchronized sync(mutex); configured = newValue; } bool Hierarchy::isConfigured() { return configured; }