blob: 3cbcd7cff7308ba8b2e7dbab130137675f0e5e89 [file] [log] [blame]
/***************************************************************************
loggingevent.cpp - class LoggingEvent
-------------------
begin : mar avr 15 2003
copyright : (C) 2003 by michael
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/loggingevent.h>
#include <log4cxx/ndc.h>
#include <log4cxx/helpers/thread.h>
#include <log4cxx/level.h>
#include <log4cxx/helpers/socketoutputstream.h>
#include <log4cxx/helpers/socketinputstream.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/system.h>
#include <log4cxx/helpers/loader.h>
#include <log4cxx/helpers/socket.h>
using namespace log4cxx;
using namespace log4cxx::spi;
using namespace log4cxx::helpers;
IMPLEMENT_LOG4CXX_OBJECT(LoggingEvent)
// time at startup
int64_t LoggingEvent::startTime = System::currentTimeMillis();
LoggingEvent::LoggingEvent()
: timeStamp(0), ndcLookupRequired(true), line(0),
mdcCopyLookupRequired(true), properties(0)
{
}
LoggingEvent::LoggingEvent(const String& fqnOfCategoryClass,
const LoggerPtr& logger, const LevelPtr& level,
const String& message, const char* file, int line)
: fqnOfCategoryClass(fqnOfCategoryClass), logger(logger), level(level),
message(message), file((char*)file), line(line),
timeStamp(System::currentTimeMillis()), ndcLookupRequired(true),
mdcCopyLookupRequired(true), properties(0)
{
threadId = Thread::getCurrentThreadId();
}
LoggingEvent::~LoggingEvent()
{
if (properties != 0)
{
delete properties;
}
}
const String& LoggingEvent::getLoggerName() const
{
return logger->getName();
}
const String& LoggingEvent::getNDC() const
{
if(ndcLookupRequired)
{
((LoggingEvent *)this)->ndcLookupRequired = false;
((LoggingEvent *)this)->ndc = NDC::get();
}
return ndc;
}
String LoggingEvent::getMDC(const String& key) const
{
// Note the mdcCopy is used if it exists. Otherwise we use the MDC
// that is associated with the thread.
if (!mdcCopy.empty())
{
MDC::Map::const_iterator it = mdcCopy.find(key);
if (it != mdcCopy.end())
{
String r = it->second;
if (!r.empty())
{
return r;
}
}
}
return MDC::get(key);
}
std::set<String> LoggingEvent::getMDCKeySet() const
{
std::set<String> set;
if (!mdcCopy.empty())
{
MDC::Map::const_iterator it;
for (it = mdcCopy.begin(); it != mdcCopy.end(); it++)
{
set.insert(it->first);
}
}
else
{
MDC::Map m = MDC::getContext();
MDC::Map::const_iterator it;
for (it = m.begin(); it != m.end(); it++)
{
set.insert(it->first);
}
}
return set;
}
void LoggingEvent::getMDCCopy() const
{
if(mdcCopyLookupRequired)
{
((LoggingEvent *)this)->mdcCopyLookupRequired = false;
// the clone call is required for asynchronous logging.
((LoggingEvent *)this)->mdcCopy = MDC::getContext();
}
}
String LoggingEvent::getProperty(const String& key) const
{
if (properties == 0)
{
return String();
}
std::map<String, String>::const_iterator it = properties->find(key);
if (it != properties->end())
{
const String& p = it->second;
if (!p.empty())
{
return p;
}
}
return String();
}
std::set<String> LoggingEvent::getPropertyKeySet() const
{
std::set<String> set;
if (properties != 0)
{
std::map<String, String>::const_iterator it;
for (it = properties->begin(); it != properties->end(); it++)
{
set.insert(it->first);
}
}
return set;
}
void LoggingEvent::read(const helpers::SocketInputStreamPtr& is)
{
// fqnOfCategoryClass
is->read(fqnOfCategoryClass);
// name
String name;
is->read(name);
logger = Logger::getLogger(name);
// level
readLevel(is);
// message
is->read(message);
// timeStamp
is->read(&timeStamp, sizeof(timeStamp));
// file
String buffer;
is->read(buffer);
if (!buffer.empty())
{
USES_CONVERSION;
fileFromStream = T2A(buffer.c_str());
file = (char *)fileFromStream.c_str();
}
// line
is->read(line);
// ndc
is->read(ndc);
ndcLookupRequired = false;
// mdc
String key, value;
int n, size;
is->read(size);
for (n = 0; n < size; n++)
{
is->read(key);
is->read(value);
mdcCopy[key] = value;
}
mdcCopyLookupRequired = false;
// properties
is->read(size);
for (n = 0; n < size; n++)
{
is->read(key);
is->read(value);
setProperty(key, value);
}
// threadId
is->read(threadId);
}
void LoggingEvent::readLevel(const helpers::SocketInputStreamPtr& is)
{
int levelInt;
is->read(levelInt);
String className;
is->read(className);
if (className.empty())
{
level = Level::toLevel(levelInt);
}
else try
{
Level::LevelClass& levelClass =
(Level::LevelClass&)Loader::loadClass(className);
level = levelClass.toLevel(levelInt);
}
catch (Exception& oops)
{
LogLog::warn(
_T("Level deserialization failed, reverting to default."), oops);
level = Level::toLevel(levelInt);
}
catch (...)
{
LogLog::warn(
_T("Level deserialization failed, reverting to default."));
level = Level::toLevel(levelInt);
}
}
void LoggingEvent::setProperty(const String& key, const String& value)
{
if (properties == 0)
{
properties = new std::map<String, String>;
}
(*properties)[key] = value;
}
void LoggingEvent::write(helpers::SocketOutputStreamPtr& os) const
{
// fqnOfCategoryClass
os->write(fqnOfCategoryClass);
// name
os->write(logger->getName());
// level
writeLevel(os);
// message
os->write(message);
// timeStamp
os->write(&timeStamp, sizeof(timeStamp));
// file
String buffer;
if (file != 0)
{
USES_CONVERSION;
buffer = A2T(file);
}
os->write(buffer);
// line
os->write(line);
// ndc
os->write(getNDC());
// mdc
getMDCCopy();
os->write((int)mdcCopy.size());
MDC::Map::const_iterator it;
for (it = mdcCopy.begin(); it != mdcCopy.end(); it++)
{
os->write(it->first);
os->write(it->second);
}
// properties
int size = (properties != 0) ? (int)properties->size() : 0;
os->write(size);
if (size > 0)
{
std::map<String, String>::const_iterator it;
for (it = properties->begin(); it != properties->end(); it++)
{
os->write(it->first);
os->write(it->second);
}
}
// threadId
os->write(threadId);
}
void LoggingEvent::writeLevel(helpers::SocketOutputStreamPtr& os) const
{
os->write(level->toInt());
const Class& clazz = level->getClass();
if (&clazz == &Level::getStaticClass())
{
os->write(String());
}
else
{
os->write(clazz.getName());
}
}