gremlin/libs/log4cplus/src/patternlayout.cxx

958 lines
28 KiB
C++

// Module: Log4CPLUS
// File: patternlayout.cxx
// Created: 6/2001
// Author: Tad E. Smith
//
//
// Copyright 2001-2010 Tad E. Smith
//
// Licensed 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.
#include <log4cplus/layout.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/timehelper.h>
#include <log4cplus/helpers/stringhelper.h>
#include <log4cplus/helpers/socket.h>
#include <log4cplus/spi/loggingevent.h>
#ifdef LOG4CPLUS_HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <exception>
#ifdef LOG4CPLUS_HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef LOG4CPLUS_HAVE_UNISTD_H
#include <unistd.h>
#endif
namespace
{
static
#if defined (_WIN32)
DWORD
get_process_id ()
{
return GetCurrentProcessId ();
}
#elif defined (LOG4CPLUS_HAVE_GETPID)
pid_t
get_process_id ()
{
return getpid ();
}
#else
int
get_process_id ()
{
return 0;
}
#endif
static
log4cplus::tstring
get_basename (const log4cplus::tstring& filename)
{
#if defined(_WIN32)
log4cplus::tchar const dir_sep(LOG4CPLUS_TEXT('\\'));
#else
log4cplus::tchar const dir_sep(LOG4CPLUS_TEXT('/'));
#endif
log4cplus::tstring::size_type pos = filename.rfind(dir_sep);
if (pos != log4cplus::tstring::npos)
return filename.substr(pos+1);
else
return filename;
}
} // namespace
using namespace std;
using namespace log4cplus;
using namespace log4cplus::helpers;
using namespace log4cplus::spi;
#define ESCAPE_CHAR LOG4CPLUS_TEXT('%')
namespace log4cplus {
namespace pattern {
/**
* This is used by PatternConverter class to inform them how to format
* their output.
*/
struct FormattingInfo {
int minLen;
size_t maxLen;
bool leftAlign;
FormattingInfo() { reset(); }
void reset();
void dump(log4cplus::helpers::LogLog&);
};
/**
* This is the base class of all "Converter" classes that format a
* field of InternalLoggingEvent objects. In fact, the PatternLayout
* class simply uses an array of PatternConverter objects to format
* and append a logging event.
*/
class PatternConverter : protected log4cplus::helpers::LogLogUser {
public:
PatternConverter(const FormattingInfo& info);
virtual ~PatternConverter() {}
void formatAndAppend(log4cplus::tostream& output,
const InternalLoggingEvent& event);
protected:
virtual log4cplus::tstring convert(const InternalLoggingEvent& event) = 0;
private:
int minLen;
size_t maxLen;
bool leftAlign;
};
/**
* This PatternConverter returns a constant string.
*/
class LiteralPatternConverter : public PatternConverter {
public:
LiteralPatternConverter(const log4cplus::tstring& str);
virtual log4cplus::tstring convert(const InternalLoggingEvent&) {
return str;
}
private:
log4cplus::tstring str;
};
/**
* This PatternConverter is used to format most of the "simple" fields
* found in the InternalLoggingEvent object.
*/
class BasicPatternConverter : public PatternConverter {
public:
enum Type { THREAD_CONVERTER,
PROCESS_CONVERTER,
LOGLEVEL_CONVERTER,
NDC_CONVERTER,
MESSAGE_CONVERTER,
NEWLINE_CONVERTER,
BASENAME_CONVERTER,
FILE_CONVERTER,
LINE_CONVERTER,
FULL_LOCATION_CONVERTER };
BasicPatternConverter(const FormattingInfo& info, Type type);
virtual log4cplus::tstring convert(const InternalLoggingEvent& event);
private:
// Disable copy
BasicPatternConverter(const BasicPatternConverter&);
BasicPatternConverter& operator=(BasicPatternConverter&);
LogLevelManager& llmCache;
Type type;
};
/**
* This PatternConverter is used to format the Logger field found in
* the InternalLoggingEvent object.
*/
class LoggerPatternConverter : public PatternConverter {
public:
LoggerPatternConverter(const FormattingInfo& info, int precision);
virtual log4cplus::tstring convert(const InternalLoggingEvent& event);
private:
int precision;
};
/**
* This PatternConverter is used to format the timestamp field found in
* the InternalLoggingEvent object. It will be formatted according to
* the specified "pattern".
*/
class DatePatternConverter : public PatternConverter {
public:
DatePatternConverter(const FormattingInfo& info,
const log4cplus::tstring& pattern,
bool use_gmtime);
virtual log4cplus::tstring convert(const InternalLoggingEvent& event);
private:
bool use_gmtime;
log4cplus::tstring format;
};
/**
* This PatternConverter is used to format the hostname field.
*/
class HostnamePatternConverter : public PatternConverter {
public:
HostnamePatternConverter(const FormattingInfo& info, bool fqdn);
virtual log4cplus::tstring convert(const InternalLoggingEvent& event);
private:
log4cplus::tstring hostname_;
};
/**
* This PatternConverter is used to format the NDC field found in
* the InternalLoggingEvent object, optionally limited to
* \c precision levels (using space to separate levels).
*/
class NDCPatternConverter : public PatternConverter {
public:
NDCPatternConverter(const FormattingInfo& info, int precision);
virtual log4cplus::tstring convert(const InternalLoggingEvent& event);
private:
int precision;
};
/**
* This class parses a "pattern" string into an array of
* PatternConverter objects.
* <p>
* @see PatternLayout for the formatting of the "pattern" string.
*/
class PatternParser : protected log4cplus::helpers::LogLogUser {
public:
PatternParser(const log4cplus::tstring& pattern, unsigned ndcMaxDepth);
std::vector<PatternConverter*> parse();
private:
// Types
enum ParserState { LITERAL_STATE,
CONVERTER_STATE,
DOT_STATE,
MIN_STATE,
MAX_STATE };
// Methods
log4cplus::tstring extractOption();
int extractPrecisionOption();
void finalizeConverter(log4cplus::tchar c);
// Data
log4cplus::tstring pattern;
FormattingInfo formattingInfo;
std::vector<PatternConverter*> list;
ParserState state;
tstring::size_type pos;
log4cplus::tstring currentLiteral;
unsigned ndcMaxDepth;
};
}
}
using namespace log4cplus::pattern;
typedef std::vector<log4cplus::pattern::PatternConverter*> PatternConverterList;
////////////////////////////////////////////////
// PatternConverter methods:
////////////////////////////////////////////////
void
log4cplus::pattern::FormattingInfo::reset() {
minLen = -1;
maxLen = 0x7FFFFFFF;
leftAlign = false;
}
void
log4cplus::pattern::FormattingInfo::dump(log4cplus::helpers::LogLog& loglog) {
log4cplus::tostringstream buf;
buf << LOG4CPLUS_TEXT("min=") << minLen
<< LOG4CPLUS_TEXT(", max=") << maxLen
<< LOG4CPLUS_TEXT(", leftAlign=")
<< (leftAlign ? LOG4CPLUS_TEXT("true") : LOG4CPLUS_TEXT("false"));
loglog.debug(buf.str());
}
////////////////////////////////////////////////
// PatternConverter methods:
////////////////////////////////////////////////
log4cplus::pattern::PatternConverter::PatternConverter(const FormattingInfo& i)
{
minLen = i.minLen;
maxLen = i.maxLen;
leftAlign = i.leftAlign;
}
void
log4cplus::pattern::PatternConverter::formatAndAppend
(log4cplus::tostream& output, const InternalLoggingEvent& event)
{
log4cplus::tstring s = convert(event);
size_t len = s.length();
if(len > maxLen) {
output << s.substr(len - maxLen);
}
else if(static_cast<int>(len) < minLen) {
if(leftAlign) {
output << s;
output << log4cplus::tstring(minLen - len, LOG4CPLUS_TEXT(' '));
}
else {
output << log4cplus::tstring(minLen - len, LOG4CPLUS_TEXT(' '));
output << s;
}
}
else {
output << s;
}
}
////////////////////////////////////////////////
// LiteralPatternConverter methods:
////////////////////////////////////////////////
log4cplus::pattern::LiteralPatternConverter::LiteralPatternConverter
(const log4cplus::tstring& str_)
: PatternConverter(FormattingInfo()),
str(str_)
{
}
////////////////////////////////////////////////
// BasicPatternConverter methods:
////////////////////////////////////////////////
log4cplus::pattern::BasicPatternConverter::BasicPatternConverter
(const FormattingInfo& info, Type type_)
: PatternConverter(info),
llmCache(getLogLevelManager()),
type(type_)
{
}
log4cplus::tstring
log4cplus::pattern::BasicPatternConverter::convert
(const InternalLoggingEvent& event)
{
switch(type) {
case LOGLEVEL_CONVERTER: return llmCache.toString(event.getLogLevel());
case NDC_CONVERTER: return event.getNDC();
case MESSAGE_CONVERTER: return event.getMessage();
case NEWLINE_CONVERTER: return LOG4CPLUS_TEXT("\n");
case BASENAME_CONVERTER: return get_basename(event.getFile());
case FILE_CONVERTER: return event.getFile();
case THREAD_CONVERTER: return event.getThread();
case PROCESS_CONVERTER: return convertIntegerToString(get_process_id ());
case LINE_CONVERTER:
{
int line = event.getLine();
if(line != -1) {
return convertIntegerToString(line);
}
else {
return log4cplus::tstring();
}
}
case FULL_LOCATION_CONVERTER:
{
tstring const & filename = event.getFile();
if(! filename.empty ()) {
return filename
+ LOG4CPLUS_TEXT(":")
+ convertIntegerToString(event.getLine());
}
else {
return LOG4CPLUS_TEXT(":");
}
}
}
return LOG4CPLUS_TEXT("INTERNAL LOG4CPLUS ERROR");
}
////////////////////////////////////////////////
// LoggerPatternConverter methods:
////////////////////////////////////////////////
log4cplus::pattern::LoggerPatternConverter::LoggerPatternConverter
(const FormattingInfo& info, int precision_)
: PatternConverter(info),
precision(precision_)
{
}
log4cplus::tstring
log4cplus::pattern::LoggerPatternConverter::convert
(const InternalLoggingEvent& event)
{
const log4cplus::tstring& name = event.getLoggerName();
if (precision <= 0) {
return name;
}
else {
size_t len = name.length();
// We substract 1 from 'len' when assigning to 'end' to avoid out of
// bounds exception in return r.substring(end+1, len). This can happen
// if precision is 1 and the logger name ends with a dot.
tstring::size_type end = len - 1;
for(int i=precision; i>0; --i) {
end = name.rfind(LOG4CPLUS_TEXT('.'), end - 1);
if(end == tstring::npos) {
return name;
}
}
return name.substr(end + 1);
}
}
////////////////////////////////////////////////
// DatePatternConverter methods:
////////////////////////////////////////////////
log4cplus::pattern::DatePatternConverter::DatePatternConverter
(const FormattingInfo& info,
const log4cplus::tstring& pattern,
bool use_gmtime_)
: PatternConverter(info),
use_gmtime(use_gmtime_),
format(pattern)
{
}
log4cplus::tstring
log4cplus::pattern::DatePatternConverter::convert
(const InternalLoggingEvent& event)
{
return event.getTimestamp().getFormattedTime(format, use_gmtime);
}
////////////////////////////////////////////////
// HostnamePatternConverter methods:
////////////////////////////////////////////////
log4cplus::pattern::HostnamePatternConverter::HostnamePatternConverter (
const FormattingInfo& info, bool fqdn)
: PatternConverter(info)
, hostname_ (helpers::getHostname (fqdn))
{ }
log4cplus::tstring
log4cplus::pattern::HostnamePatternConverter::convert (
const InternalLoggingEvent &)
{
return hostname_;
}
////////////////////////////////////////////////
// NDCPatternConverter methods:
////////////////////////////////////////////////
log4cplus::pattern::NDCPatternConverter::NDCPatternConverter (
const FormattingInfo& info, int precision_)
: PatternConverter(info)
, precision(precision_)
{ }
log4cplus::tstring
log4cplus::pattern::NDCPatternConverter::convert (
const InternalLoggingEvent& event)
{
const log4cplus::tstring& text = event.getNDC();
if (precision <= 0)
return text;
else
{
tstring::size_type p = text.find(LOG4CPLUS_TEXT(' '));
for (int i = 1; i < precision && p != tstring::npos; ++i)
p = text.find(LOG4CPLUS_TEXT(' '), p + 1);
return text.substr(0, p);
}
}
////////////////////////////////////////////////
// PatternParser methods:
////////////////////////////////////////////////
log4cplus::pattern::PatternParser::PatternParser(
const log4cplus::tstring& pattern_, unsigned ndcMaxDepth_)
: pattern(pattern_)
, state(LITERAL_STATE)
, pos(0)
, ndcMaxDepth (ndcMaxDepth_)
{
}
log4cplus::tstring
log4cplus::pattern::PatternParser::extractOption()
{
if ( (pos < pattern.length())
&& (pattern[pos] == LOG4CPLUS_TEXT('{')))
{
tstring::size_type end = pattern.find_first_of(LOG4CPLUS_TEXT('}'), pos);
if (end != tstring::npos) {
log4cplus::tstring r = pattern.substr(pos + 1, end - pos - 1);
pos = end + 1;
return r;
}
else {
log4cplus::tostringstream buf;
buf << LOG4CPLUS_TEXT("No matching '}' found in conversion pattern string \"")
<< pattern
<< LOG4CPLUS_TEXT("\"");
getLogLog().error(buf.str());
pos = pattern.length();
}
}
return LOG4CPLUS_TEXT("");
}
int
log4cplus::pattern::PatternParser::extractPrecisionOption()
{
log4cplus::tstring opt = extractOption();
int r = 0;
if(! opt.empty ()) {
r = std::atoi(LOG4CPLUS_TSTRING_TO_STRING(opt).c_str());
}
return r;
}
PatternConverterList
log4cplus::pattern::PatternParser::parse()
{
tchar c;
pos = 0;
while(pos < pattern.length()) {
c = pattern[pos++];
switch (state) {
case LITERAL_STATE :
// In literal state, the last char is always a literal.
if(pos == pattern.length()) {
currentLiteral += c;
continue;
}
if(c == ESCAPE_CHAR) {
// peek at the next char.
switch (pattern[pos]) {
case ESCAPE_CHAR:
currentLiteral += c;
pos++; // move pointer
break;
default:
if(! currentLiteral.empty ()) {
list.push_back
(new LiteralPatternConverter(currentLiteral));
//getLogLog().debug("Parsed LITERAL converter: \""
// +currentLiteral+"\".");
}
currentLiteral.resize(0);
currentLiteral += c; // append %
state = CONVERTER_STATE;
formattingInfo.reset();
}
}
else {
currentLiteral += c;
}
break;
case CONVERTER_STATE:
currentLiteral += c;
switch (c) {
case LOG4CPLUS_TEXT('-'):
formattingInfo.leftAlign = true;
break;
case LOG4CPLUS_TEXT('.'):
state = DOT_STATE;
break;
default:
if(c >= LOG4CPLUS_TEXT('0') && c <= LOG4CPLUS_TEXT('9')) {
formattingInfo.minLen = c - LOG4CPLUS_TEXT('0');
state = MIN_STATE;
}
else {
finalizeConverter(c);
}
} // switch
break;
case MIN_STATE:
currentLiteral += c;
if (c >= LOG4CPLUS_TEXT('0') && c <= LOG4CPLUS_TEXT('9')) {
formattingInfo.minLen = formattingInfo.minLen * 10 + (c - LOG4CPLUS_TEXT('0'));
}
else if(c == LOG4CPLUS_TEXT('.')) {
state = DOT_STATE;
}
else {
finalizeConverter(c);
}
break;
case DOT_STATE:
currentLiteral += c;
if(c >= LOG4CPLUS_TEXT('0') && c <= LOG4CPLUS_TEXT('9')) {
formattingInfo.maxLen = c - LOG4CPLUS_TEXT('0');
state = MAX_STATE;
}
else {
log4cplus::tostringstream buf;
buf << LOG4CPLUS_TEXT("Error occured in position ")
<< pos
<< LOG4CPLUS_TEXT(".\n Was expecting digit, instead got char \"")
<< c
<< LOG4CPLUS_TEXT("\".");
getLogLog().error(buf.str());
state = LITERAL_STATE;
}
break;
case MAX_STATE:
currentLiteral += c;
if (c >= LOG4CPLUS_TEXT('0') && c <= LOG4CPLUS_TEXT('9'))
formattingInfo.maxLen = formattingInfo.maxLen * 10 + (c - LOG4CPLUS_TEXT('0'));
else {
finalizeConverter(c);
state = LITERAL_STATE;
}
break;
} // end switch
} // end while
if(! currentLiteral.empty ()) {
list.push_back(new LiteralPatternConverter(currentLiteral));
//getLogLog().debug("Parsed LITERAL converter: \""+currentLiteral+"\".");
}
return list;
}
void
log4cplus::pattern::PatternParser::finalizeConverter(log4cplus::tchar c)
{
PatternConverter* pc = 0;
switch (c) {
case LOG4CPLUS_TEXT('b'):
pc = new BasicPatternConverter
(formattingInfo,
BasicPatternConverter::BASENAME_CONVERTER);
//getLogLog().debug("BASENAME converter.");
//formattingInfo.dump(getLogLog());
break;
case LOG4CPLUS_TEXT('c'):
pc = new LoggerPatternConverter(formattingInfo,
extractPrecisionOption());
getLogLog().debug( LOG4CPLUS_TEXT("LOGGER converter.") );
formattingInfo.dump(getLogLog());
break;
case LOG4CPLUS_TEXT('d'):
case LOG4CPLUS_TEXT('D'):
{
log4cplus::tstring dOpt = extractOption();
if(dOpt.empty ()) {
dOpt = LOG4CPLUS_TEXT("%Y-%m-%d %H:%M:%S");
}
bool use_gmtime = c == LOG4CPLUS_TEXT('d');
pc = new DatePatternConverter(formattingInfo, dOpt, use_gmtime);
//if(use_gmtime) {
// getLogLog().debug("GMT DATE converter.");
//}
//else {
// getLogLog().debug("LOCAL DATE converter.");
//}
//formattingInfo.dump(getLogLog());
}
break;
case LOG4CPLUS_TEXT('F'):
pc = new BasicPatternConverter
(formattingInfo,
BasicPatternConverter::FILE_CONVERTER);
//getLogLog().debug("FILE NAME converter.");
//formattingInfo.dump(getLogLog());
break;
case LOG4CPLUS_TEXT('h'):
case LOG4CPLUS_TEXT('H'):
{
bool fqdn = (c == LOG4CPLUS_TEXT('H'));
pc = new HostnamePatternConverter(formattingInfo, fqdn);
// getLogLog().debug( LOG4CPLUS_TEXT("HOSTNAME converter.") );
// formattingInfo.dump(getLogLog());
}
break;
case LOG4CPLUS_TEXT('i'):
pc = new BasicPatternConverter
(formattingInfo,
BasicPatternConverter::PROCESS_CONVERTER);
//getLogLog().debug("PROCESS_CONVERTER converter.");
//formattingInfo.dump(getLogLog());
break;
case LOG4CPLUS_TEXT('l'):
pc = new BasicPatternConverter
(formattingInfo,
BasicPatternConverter::FULL_LOCATION_CONVERTER);
//getLogLog().debug("FULL LOCATION converter.");
//formattingInfo.dump(getLogLog());
break;
case LOG4CPLUS_TEXT('L'):
pc = new BasicPatternConverter
(formattingInfo,
BasicPatternConverter::LINE_CONVERTER);
//getLogLog().debug("LINE NUMBER converter.");
//formattingInfo.dump(getLogLog());
break;
case LOG4CPLUS_TEXT('m'):
pc = new BasicPatternConverter
(formattingInfo,
BasicPatternConverter::MESSAGE_CONVERTER);
//getLogLog().debug("MESSAGE converter.");
//formattingInfo.dump(getLogLog());
break;
// 'M' is METHOD converter in log4j.
// Not implemented.
case LOG4CPLUS_TEXT('M'):
goto not_implemented;
case LOG4CPLUS_TEXT('n'):
pc = new BasicPatternConverter
(formattingInfo,
BasicPatternConverter::NEWLINE_CONVERTER);
//getLogLog().debug("MESSAGE converter.");
//formattingInfo.dump(getLogLog());
break;
case LOG4CPLUS_TEXT('p'):
pc = new BasicPatternConverter
(formattingInfo,
BasicPatternConverter::LOGLEVEL_CONVERTER);
//getLogLog().debug("LOGLEVEL converter.");
//formattingInfo.dump(getLogLog());
break;
// 'r' is RELATIVE time converter in log4j.
// Not implemented.
case LOG4CPLUS_TEXT('r'):
goto not_implemented;
case LOG4CPLUS_TEXT('t'):
pc = new BasicPatternConverter
(formattingInfo,
BasicPatternConverter::THREAD_CONVERTER);
//getLogLog().debug("THREAD converter.");
//formattingInfo.dump(getLogLog());
break;
case LOG4CPLUS_TEXT('x'):
pc = new NDCPatternConverter (formattingInfo, ndcMaxDepth);
//getLogLog().debug("NDC converter.");
break;
// 'X' is MDC in log4j.
// Not implemented.
case LOG4CPLUS_TEXT('X'):
goto not_implemented;
not_implemented:;
default:
log4cplus::tostringstream buf;
buf << LOG4CPLUS_TEXT("Unexpected char [")
<< c
<< LOG4CPLUS_TEXT("] at position ")
<< pos
<< LOG4CPLUS_TEXT(" in conversion patterrn.");
getLogLog().error(buf.str());
pc = new LiteralPatternConverter(currentLiteral);
}
currentLiteral.resize(0);
list.push_back(pc);
state = LITERAL_STATE;
formattingInfo.reset();
}
////////////////////////////////////////////////
// PatternLayout methods:
////////////////////////////////////////////////
PatternLayout::PatternLayout(const log4cplus::tstring& pattern_)
{
init(pattern_, 0);
}
PatternLayout::PatternLayout(const log4cplus::helpers::Properties& properties)
{
unsigned ndcMaxDepth
= std::atoi (LOG4CPLUS_TSTRING_TO_STRING (
properties.getProperty (
LOG4CPLUS_TEXT ("NDCMaxDepth"),
LOG4CPLUS_TEXT ("0"))).c_str ());
bool hasPattern = properties.exists( LOG4CPLUS_TEXT("Pattern") );
bool hasConversionPattern = properties.exists( LOG4CPLUS_TEXT("ConversionPattern") );
if(hasPattern) {
getLogLog().warn( LOG4CPLUS_TEXT("PatternLayout- the \"Pattern\" property has been deprecated. Use \"ConversionPattern\" instead."));
}
if(hasConversionPattern) {
init(properties.getProperty( LOG4CPLUS_TEXT("ConversionPattern") ),
ndcMaxDepth);
}
else if(hasPattern) {
init(properties.getProperty( LOG4CPLUS_TEXT("Pattern") ), ndcMaxDepth);
}
else {
throw std::runtime_error("ConversionPattern not specified in properties");
}
}
void
PatternLayout::init(const log4cplus::tstring& pattern_, unsigned ndcMaxDepth)
{
this->pattern = pattern_;
this->parsedPattern = PatternParser(pattern, ndcMaxDepth).parse();
// Let's validate that our parser didn't give us any NULLs. If it did,
// we will convert them to a valid PatternConverter that does nothing so
// at least we don't core.
for(PatternConverterList::iterator it=parsedPattern.begin();
it!=parsedPattern.end();
++it)
{
if( (*it) == 0 ) {
getLogLog().error(LOG4CPLUS_TEXT("Parsed Pattern created a NULL PatternConverter"));
(*it) = new LiteralPatternConverter( LOG4CPLUS_TEXT("") );
}
}
if(parsedPattern.empty ()) {
getLogLog().warn(LOG4CPLUS_TEXT("PatternLayout pattern is empty. Using default..."));
parsedPattern.push_back
(new BasicPatternConverter(FormattingInfo(),
BasicPatternConverter::MESSAGE_CONVERTER));
}
}
PatternLayout::~PatternLayout()
{
for(PatternConverterList::iterator it=parsedPattern.begin();
it!=parsedPattern.end();
++it)
{
delete (*it);
}
}
void
PatternLayout::formatAndAppend(log4cplus::tostream& output,
const InternalLoggingEvent& event)
{
for(PatternConverterList::iterator it=parsedPattern.begin();
it!=parsedPattern.end();
++it)
{
(*it)->formatAndAppend(output, event);
}
}