blob: bfa29aeef740ac43c6f5a7ff4ca2ef6f21066a1c [file] [log] [blame]
/***************************************************************************
hierarchy.cpp - description
-------------------
begin : jeu avr 17 2003
copyright : (C) 2003 by Michael CATANZARITI
email : mcatan@free.fr
***************************************************************************/
/***************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* *
* This software is published under the terms of the Apache Software *
* License version 1.1, a copy of which has been included with this *
* distribution in the LICENSE.txt file. *
***************************************************************************/
#include <log4cxx/spi/loggerfactory.h>
#include <log4cxx/hierarchy.h>
#include <log4cxx/defaultcategoryfactory.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>
using namespace log4cxx;
using namespace log4cxx::spi;
using namespace log4cxx::helpers;
IMPLEMENT_LOG4CXX_OBJECT(Hierarchy)
namespace {
bool startsWith(const String& teststr, const String& substr)
{
bool val = false;
if(teststr.length() > substr.length()) {
val = teststr.substr(0, substr.length()) == substr;
}
return val;
}
}
Hierarchy::Hierarchy(const LoggerPtr& root) : root(root),
emittedNoAppenderWarning(false), emittedNoResourceBundleWarning(false)
{
// Enable all level levels by default.
setThreshold(Level::ALL);
this->root->setHierarchy(this);
defaultFactory = new DefaultCategoryFactory();
}
Hierarchy::~Hierarchy()
{
}
void Hierarchy::addHierarchyEventListener(const spi::HierarchyEventListenerPtr& listener)
{
if (std::find(listeners.begin(), listeners.end(), listener) != listeners.end())
{
LogLog::warn(_T("Ignoring attempt to add an existent listener."));
}
else
{
listeners.push_back(listener);
}
}
void Hierarchy::clear()
{
mapCs.lock();
loggers.clear();
mapCs.unlock();
}
void Hierarchy::emitNoAppenderWarning(const LoggerPtr& logger)
{
// No appenders in hierarchy, warn user only once.
if(!this->emittedNoAppenderWarning)
{
LogLog::warn(_T("No appenders could be found for logger (") +
logger->getName() + _T(")."));
LogLog::warn(_T("Please initialize the log4cxx system properly."));
this->emittedNoAppenderWarning = true;
}
}
LoggerPtr Hierarchy::exists(const String& name)
{
mapCs.lock();
LoggerMap::iterator it = loggers.find(name);
return (it != loggers.end()) ? it->second : 0;
mapCs.unlock();
}
void Hierarchy::setThreshold(const LevelPtr& l)
{
if (l != 0)
{
thresholdInt = l->level;
threshold = l;
}
}
void Hierarchy::setThreshold(const String& levelStr)
{
const LevelPtr& l = Level::toLevel(levelStr, 0);
if(l != 0)
{
setThreshold(l);
}
else
{
LogLog::warn(_T("Could not convert [")+levelStr+_T("] to Level."));
}
}
void Hierarchy::fireAddAppenderEvent(const LoggerPtr& logger, const AppenderPtr& appender)
{
HierarchyEventListenerList::iterator it, itEnd = listeners.end();
HierarchyEventListenerPtr listener;
for(it = listeners.begin(); it != itEnd; it++)
{
listener = *it;
listener->addAppenderEvent(logger, appender);
}
}
void Hierarchy::fireRemoveAppenderEvent(const LoggerPtr& logger, const AppenderPtr& appender)
{
HierarchyEventListenerList::iterator it, itEnd = listeners.end();
HierarchyEventListenerPtr listener;
for(it = listeners.begin(); it != itEnd; it++)
{
listener = *it;
listener->removeAppenderEvent(logger, appender);
}
}
const LevelPtr& Hierarchy::getThreshold() const
{
return threshold;
}
LoggerPtr Hierarchy::getLogger(const String& name)
{
return getLogger(name, defaultFactory);
}
LoggerPtr Hierarchy::getLogger(const String& name, spi::LoggerFactoryPtr factory)
{
// Synchronize to prevent write conflicts. Read conflicts (in
// getEffectiveLevel method) are possible only if variable
// assignments are non-atomic.
LoggerPtr logger;
mapCs.lock();
LoggerMap::iterator it = loggers.find(name);
if (it != loggers.end())
{
logger = it->second;
}
else
{
logger = factory->makeNewLoggerInstance(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);
}
mapCs.unlock();
return logger;
}
LoggerList Hierarchy::getCurrentLoggers() const
{
mapCs.lock();
LoggerList v;
LoggerMap::const_iterator it, itEnd = loggers.end();
for (it = loggers.begin(); it != itEnd; it++)
{
v.push_back(it->second);
}
mapCs.unlock();
return v;
}
LoggerPtr Hierarchy::getRootLogger() const
{
return root;
}
bool Hierarchy::isDisabled(int level) const
{
return thresholdInt > level;
}
void Hierarchy::resetConfiguration()
{
mapCs.lock();
getRootLogger()->setLevel(Level::DEBUG);
root->setResourceBundle(0);
setThreshold(Level::ALL);
shutdown(); // nested locks are OK
LoggerList loggers = getCurrentLoggers();
LoggerList::iterator it, itEnd = loggers.end();
for (it = loggers.begin(); it != itEnd; it++)
{
LoggerPtr& logger = *it;
logger->setLevel(0);
logger->setAdditivity(true);
logger->setResourceBundle(0);
}
//rendererMap.clear();
mapCs.unlock();
}
void Hierarchy::shutdown()
{
LoggerPtr root = getRootLogger();
// begin by closing nested appenders
root->closeNestedAppenders();
LoggerList loggers = getCurrentLoggers();
LoggerList::iterator it, itEnd = loggers.end();
for (it = loggers.begin(); it != itEnd; it++)
{
LoggerPtr& logger = *it;
logger->closeNestedAppenders();
}
// then, remove all appenders
root->removeAllAppenders();
for (it = loggers.begin(); it != itEnd; it++)
{
LoggerPtr& logger = *it;
logger->removeAllAppenders();
}
}
void Hierarchy::updateParents(LoggerPtr& logger)
{
const String& name = logger->name;
int length = name.size();
bool parentFound = false;
//tcout << _T("UpdateParents called for ") << name << std::endl;
// if name = "w.x.y.z", loop thourgh "w.x.y", "w.x" and "w", but not "w.x.y.z"
for(int i = name.find_last_of(_T('.'), length-1); i != String::npos;
i = name.find_last_of(_T('.'), i-1))
{
String substr = name.substr(0, i);
//tcout << _T("UpdateParents processing ") << substr << std::endl;
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(name);
if (it2 != provisionNodes.end())
{
it2->second.push_back(logger);
}
else
{
//tcout << _T("Inserting ProvisionNode for ") << substr << std::endl;
ProvisionNode node(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)
{
//tcout << _T("updateChildren called for ") << logger->name << std::endl;
ProvisionNode::iterator it, itEnd = pn.end();
for(it = pn.begin(); it != itEnd; it++)
{
LoggerPtr& l = *it;
//tcout << _T("Updating child ") << l->name << std::endl;
// Unless this child already points to a correct (lower) parent,
// make cat.parent point to l.parent and l.parent to cat.
if(!startsWith(l->parent->name, logger->name))
{
logger->parent = l->parent;
l->parent = logger;
}
}
}