mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-30 13:38:17 +01:00
486 lines
9.0 KiB
C++
486 lines
9.0 KiB
C++
//
|
|
// Logger.cpp
|
|
//
|
|
// $Id: //poco/1.4/Foundation/src/Logger.cpp#4 $
|
|
//
|
|
// Library: Foundation
|
|
// Package: Logging
|
|
// Module: Logger
|
|
//
|
|
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
|
|
// and Contributors.
|
|
//
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
//
|
|
|
|
|
|
#include "Poco/Logger.h"
|
|
#include "Poco/Formatter.h"
|
|
#include "Poco/LoggingRegistry.h"
|
|
#include "Poco/Exception.h"
|
|
#include "Poco/NumberFormatter.h"
|
|
#include "Poco/NumberParser.h"
|
|
#include "Poco/String.h"
|
|
|
|
|
|
namespace Poco {
|
|
|
|
|
|
Logger::LoggerMap* Logger::_pLoggerMap = 0;
|
|
Mutex Logger::_mapMtx;
|
|
const std::string Logger::ROOT;
|
|
|
|
|
|
Logger::Logger(const std::string& name, Channel* pChannel, int level): _name(name), _pChannel(pChannel), _level(level)
|
|
{
|
|
if (pChannel) pChannel->duplicate();
|
|
}
|
|
|
|
|
|
Logger::~Logger()
|
|
{
|
|
if (_pChannel) _pChannel->release();
|
|
}
|
|
|
|
|
|
void Logger::setChannel(Channel* pChannel)
|
|
{
|
|
if (_pChannel) _pChannel->release();
|
|
_pChannel = pChannel;
|
|
if (_pChannel) _pChannel->duplicate();
|
|
}
|
|
|
|
|
|
Channel* Logger::getChannel() const
|
|
{
|
|
return _pChannel;
|
|
}
|
|
|
|
|
|
void Logger::setLevel(int level)
|
|
{
|
|
_level = level;
|
|
}
|
|
|
|
|
|
void Logger::setLevel(const std::string& level)
|
|
{
|
|
setLevel(parseLevel(level));
|
|
}
|
|
|
|
|
|
void Logger::setProperty(const std::string& name, const std::string& value)
|
|
{
|
|
if (name == "channel")
|
|
setChannel(LoggingRegistry::defaultRegistry().channelForName(value));
|
|
else if (name == "level")
|
|
setLevel(value);
|
|
else
|
|
Channel::setProperty(name, value);
|
|
}
|
|
|
|
|
|
void Logger::log(const Message& msg)
|
|
{
|
|
if (_level >= msg.getPriority() && _pChannel)
|
|
{
|
|
_pChannel->log(msg);
|
|
}
|
|
}
|
|
|
|
|
|
void Logger::log(const Exception& exc)
|
|
{
|
|
error(exc.displayText());
|
|
}
|
|
|
|
|
|
void Logger::log(const Exception& exc, const char* file, int line)
|
|
{
|
|
error(exc.displayText(), file, line);
|
|
}
|
|
|
|
|
|
void Logger::dump(const std::string& msg, const void* buffer, std::size_t length, Message::Priority prio)
|
|
{
|
|
if (_level >= prio && _pChannel)
|
|
{
|
|
std::string text(msg);
|
|
formatDump(text, buffer, length);
|
|
_pChannel->log(Message(_name, text, prio));
|
|
}
|
|
}
|
|
|
|
|
|
void Logger::setLevel(const std::string& name, int level)
|
|
{
|
|
Mutex::ScopedLock lock(_mapMtx);
|
|
|
|
if (_pLoggerMap)
|
|
{
|
|
std::string::size_type len = name.length();
|
|
for (LoggerMap::iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it)
|
|
{
|
|
if (len == 0 ||
|
|
(it->first.compare(0, len, name) == 0 && (it->first.length() == len || it->first[len] == '.')))
|
|
{
|
|
it->second->setLevel(level);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Logger::setChannel(const std::string& name, Channel* pChannel)
|
|
{
|
|
Mutex::ScopedLock lock(_mapMtx);
|
|
|
|
if (_pLoggerMap)
|
|
{
|
|
std::string::size_type len = name.length();
|
|
for (LoggerMap::iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it)
|
|
{
|
|
if (len == 0 ||
|
|
(it->first.compare(0, len, name) == 0 && (it->first.length() == len || it->first[len] == '.')))
|
|
{
|
|
it->second->setChannel(pChannel);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Logger::setProperty(const std::string& loggerName, const std::string& propertyName, const std::string& value)
|
|
{
|
|
Mutex::ScopedLock lock(_mapMtx);
|
|
|
|
if (_pLoggerMap)
|
|
{
|
|
std::string::size_type len = loggerName.length();
|
|
for (LoggerMap::iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it)
|
|
{
|
|
if (len == 0 ||
|
|
(it->first.compare(0, len, loggerName) == 0 && (it->first.length() == len || it->first[len] == '.')))
|
|
{
|
|
it->second->setProperty(propertyName, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
std::string Logger::format(const std::string& fmt, const std::string& arg)
|
|
{
|
|
std::string args[] =
|
|
{
|
|
arg
|
|
};
|
|
return format(fmt, 1, args);
|
|
}
|
|
|
|
|
|
std::string Logger::format(const std::string& fmt, const std::string& arg0, const std::string& arg1)
|
|
{
|
|
std::string args[] =
|
|
{
|
|
arg0,
|
|
arg1
|
|
};
|
|
return format(fmt, 2, args);
|
|
}
|
|
|
|
|
|
std::string Logger::format(const std::string& fmt, const std::string& arg0, const std::string& arg1, const std::string& arg2)
|
|
{
|
|
std::string args[] =
|
|
{
|
|
arg0,
|
|
arg1,
|
|
arg2
|
|
};
|
|
return format(fmt, 3, args);
|
|
}
|
|
|
|
|
|
std::string Logger::format(const std::string& fmt, const std::string& arg0, const std::string& arg1, const std::string& arg2, const std::string& arg3)
|
|
{
|
|
std::string args[] =
|
|
{
|
|
arg0,
|
|
arg1,
|
|
arg2,
|
|
arg3
|
|
};
|
|
return format(fmt, 4, args);
|
|
}
|
|
|
|
|
|
std::string Logger::format(const std::string& fmt, int argc, std::string argv[])
|
|
{
|
|
std::string result;
|
|
std::string::const_iterator it = fmt.begin();
|
|
while (it != fmt.end())
|
|
{
|
|
if (*it == '$')
|
|
{
|
|
++it;
|
|
if (*it == '$')
|
|
{
|
|
result += '$';
|
|
}
|
|
else if (*it >= '0' && *it <= '9')
|
|
{
|
|
int i = *it - '0';
|
|
if (i < argc)
|
|
result += argv[i];
|
|
}
|
|
else
|
|
{
|
|
result += '$';
|
|
result += *it;
|
|
}
|
|
}
|
|
else result += *it;
|
|
++it;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
void Logger::formatDump(std::string& message, const void* buffer, std::size_t length)
|
|
{
|
|
const int BYTES_PER_LINE = 16;
|
|
|
|
message.reserve(message.size() + length*6);
|
|
if (!message.empty()) message.append("\n");
|
|
unsigned char* base = (unsigned char*) buffer;
|
|
int addr = 0;
|
|
while (addr < length)
|
|
{
|
|
if (addr > 0) message.append("\n");
|
|
message.append(NumberFormatter::formatHex(addr, 4));
|
|
message.append(" ");
|
|
int offset = 0;
|
|
while (addr + offset < length && offset < BYTES_PER_LINE)
|
|
{
|
|
message.append(NumberFormatter::formatHex(base[addr + offset], 2));
|
|
message.append(offset == 7 ? " " : " ");
|
|
++offset;
|
|
}
|
|
if (offset < 7) message.append(" ");
|
|
while (offset < BYTES_PER_LINE) { message.append(" "); ++offset; }
|
|
message.append(" ");
|
|
offset = 0;
|
|
while (addr + offset < length && offset < BYTES_PER_LINE)
|
|
{
|
|
unsigned char c = base[addr + offset];
|
|
message += (c >= 32 && c < 127) ? (char) c : '.';
|
|
++offset;
|
|
}
|
|
addr += BYTES_PER_LINE;
|
|
}
|
|
}
|
|
|
|
|
|
Logger& Logger::get(const std::string& name)
|
|
{
|
|
Mutex::ScopedLock lock(_mapMtx);
|
|
|
|
return unsafeGet(name);
|
|
}
|
|
|
|
|
|
Logger& Logger::unsafeGet(const std::string& name)
|
|
{
|
|
Logger* pLogger = find(name);
|
|
if (!pLogger)
|
|
{
|
|
if (name == ROOT)
|
|
{
|
|
pLogger = new Logger(name, 0, Message::PRIO_INFORMATION);
|
|
}
|
|
else
|
|
{
|
|
Logger& par = parent(name);
|
|
pLogger = new Logger(name, par.getChannel(), par.getLevel());
|
|
}
|
|
add(pLogger);
|
|
}
|
|
return *pLogger;
|
|
}
|
|
|
|
|
|
Logger& Logger::create(const std::string& name, Channel* pChannel, int level)
|
|
{
|
|
Mutex::ScopedLock lock(_mapMtx);
|
|
|
|
if (find(name)) throw ExistsException();
|
|
Logger* pLogger = new Logger(name, pChannel, level);
|
|
add(pLogger);
|
|
return *pLogger;
|
|
}
|
|
|
|
|
|
Logger& Logger::root()
|
|
{
|
|
Mutex::ScopedLock lock(_mapMtx);
|
|
|
|
return unsafeGet(ROOT);
|
|
}
|
|
|
|
|
|
Logger* Logger::has(const std::string& name)
|
|
{
|
|
Mutex::ScopedLock lock(_mapMtx);
|
|
|
|
return find(name);
|
|
}
|
|
|
|
|
|
void Logger::shutdown()
|
|
{
|
|
Mutex::ScopedLock lock(_mapMtx);
|
|
|
|
if (_pLoggerMap)
|
|
{
|
|
for (LoggerMap::iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it)
|
|
{
|
|
it->second->release();
|
|
}
|
|
delete _pLoggerMap;
|
|
_pLoggerMap = 0;
|
|
}
|
|
}
|
|
|
|
|
|
Logger* Logger::find(const std::string& name)
|
|
{
|
|
if (_pLoggerMap)
|
|
{
|
|
LoggerMap::iterator it = _pLoggerMap->find(name);
|
|
if (it != _pLoggerMap->end())
|
|
return it->second;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void Logger::destroy(const std::string& name)
|
|
{
|
|
Mutex::ScopedLock lock(_mapMtx);
|
|
|
|
if (_pLoggerMap)
|
|
{
|
|
LoggerMap::iterator it = _pLoggerMap->find(name);
|
|
if (it != _pLoggerMap->end())
|
|
{
|
|
it->second->release();
|
|
_pLoggerMap->erase(it);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Logger::names(std::vector<std::string>& names)
|
|
{
|
|
Mutex::ScopedLock lock(_mapMtx);
|
|
|
|
names.clear();
|
|
if (_pLoggerMap)
|
|
{
|
|
for (LoggerMap::const_iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it)
|
|
{
|
|
names.push_back(it->first);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Logger& Logger::parent(const std::string& name)
|
|
{
|
|
std::string::size_type pos = name.rfind('.');
|
|
if (pos != std::string::npos)
|
|
{
|
|
std::string pname = name.substr(0, pos);
|
|
Logger* pParent = find(pname);
|
|
if (pParent)
|
|
return *pParent;
|
|
else
|
|
return parent(pname);
|
|
}
|
|
else return unsafeGet(ROOT);
|
|
}
|
|
|
|
|
|
int Logger::parseLevel(const std::string& level)
|
|
{
|
|
if (icompare(level, "none") == 0)
|
|
return 0;
|
|
else if (icompare(level, "fatal") == 0)
|
|
return Message::PRIO_FATAL;
|
|
else if (icompare(level, "critical") == 0)
|
|
return Message::PRIO_CRITICAL;
|
|
else if (icompare(level, "error") == 0)
|
|
return Message::PRIO_ERROR;
|
|
else if (icompare(level, "warning") == 0)
|
|
return Message::PRIO_WARNING;
|
|
else if (icompare(level, "notice") == 0)
|
|
return Message::PRIO_NOTICE;
|
|
else if (icompare(level, "information") == 0)
|
|
return Message::PRIO_INFORMATION;
|
|
else if (icompare(level, "debug") == 0)
|
|
return Message::PRIO_DEBUG;
|
|
else if (icompare(level, "trace") == 0)
|
|
return Message::PRIO_TRACE;
|
|
else
|
|
{
|
|
int numLevel;
|
|
if (Poco::NumberParser::tryParse(level, numLevel))
|
|
{
|
|
if (numLevel > 0 && numLevel < 9)
|
|
return numLevel;
|
|
else
|
|
throw InvalidArgumentException("Log level out of range ", level);
|
|
}
|
|
else
|
|
throw InvalidArgumentException("Not a valid log level", level);
|
|
}
|
|
}
|
|
|
|
|
|
class AutoLoggerShutdown
|
|
{
|
|
public:
|
|
AutoLoggerShutdown()
|
|
{
|
|
}
|
|
~AutoLoggerShutdown()
|
|
{
|
|
try
|
|
{
|
|
Logger::shutdown();
|
|
}
|
|
catch (...)
|
|
{
|
|
poco_unexpected();
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
namespace
|
|
{
|
|
static AutoLoggerShutdown als;
|
|
}
|
|
|
|
|
|
void Logger::add(Logger* pLogger)
|
|
{
|
|
if (!_pLoggerMap)
|
|
_pLoggerMap = new LoggerMap;
|
|
_pLoggerMap->insert(LoggerMap::value_type(pLogger->name(), pLogger));
|
|
}
|
|
|
|
|
|
} // namespace Poco
|