blob: 7d1078e49c5e3de955d19d3df8ccd32fede49115 [file] [log] [blame]
/*
* 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 <log4cxx/logstring.h>
#include <log4cxx/spi/loggerfactory.h>
#include <log4cxx/hierarchy.h>
#include <log4cxx/defaultloggerfactory.h>
#include <log4cxx/logger.h>
#include <log4cxx/spi/hierarchyeventlistener.h>
#include <log4cxx/level.h>
#include <algorithm>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/appender.h>
#include <log4cxx/helpers/synchronized.h>
#include <log4cxx/logstring.h>
#include <log4cxx/helpers/stringhelper.h>
#if !defined(LOG4CXX)
#define LOG4CXX 1
#endif
#include <log4cxx/helpers/aprinitializer.h>
#include <log4cxx/defaultconfigurator.h>
#include <log4cxx/spi/rootlogger.h>
#include <apr_atomic.h>
#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<Hierarchy*>(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;
}