You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1046 lines
28 KiB
1046 lines
28 KiB
// 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/helpers/property.h>
|
|
#include <log4cplus/spi/loggingevent.h>
|
|
#include <log4cplus/internal/internal.h>
|
|
#include <log4cplus/internal/env.h>
|
|
#include <cstdlib>
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
|
|
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
|
|
|
|
|
|
namespace log4cplus
|
|
{
|
|
|
|
static tchar const ESCAPE_CHAR = LOG4CPLUS_TEXT('%');
|
|
|
|
extern void formatRelativeTimestamp (log4cplus::tostream & output,
|
|
log4cplus::spi::InternalLoggingEvent const & event);
|
|
|
|
|
|
namespace pattern
|
|
{
|
|
|
|
|
|
/**
|
|
* This is used by PatternConverter class to inform them how to format
|
|
* their output.
|
|
*/
|
|
struct FormattingInfo {
|
|
int minLen;
|
|
std::size_t maxLen;
|
|
bool leftAlign;
|
|
FormattingInfo() { reset(); }
|
|
|
|
void reset();
|
|
void dump(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
|
|
{
|
|
public:
|
|
explicit PatternConverter(const FormattingInfo& info);
|
|
virtual ~PatternConverter() {}
|
|
void formatAndAppend(tostream& output,
|
|
const spi::InternalLoggingEvent& event);
|
|
|
|
virtual void convert(tstring & result,
|
|
const spi::InternalLoggingEvent& event) = 0;
|
|
|
|
private:
|
|
int minLen;
|
|
std::size_t maxLen;
|
|
bool leftAlign;
|
|
};
|
|
|
|
|
|
typedef std::vector<pattern::PatternConverter*> PatternConverterList;
|
|
|
|
|
|
/**
|
|
* This PatternConverter returns a constant string.
|
|
*/
|
|
class LiteralPatternConverter : public PatternConverter
|
|
{
|
|
public:
|
|
LiteralPatternConverter(const tstring& str);
|
|
virtual void convert(tstring & result,
|
|
const spi::InternalLoggingEvent&)
|
|
{
|
|
result = str;
|
|
}
|
|
|
|
private:
|
|
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,
|
|
THREAD2_CONVERTER,
|
|
PROCESS_CONVERTER,
|
|
LOGLEVEL_CONVERTER,
|
|
NDC_CONVERTER,
|
|
MESSAGE_CONVERTER,
|
|
NEWLINE_CONVERTER,
|
|
BASENAME_CONVERTER,
|
|
FILE_CONVERTER,
|
|
LINE_CONVERTER,
|
|
FULL_LOCATION_CONVERTER,
|
|
FUNCTION_CONVERTER };
|
|
BasicPatternConverter(const FormattingInfo& info, Type type);
|
|
virtual void convert(tstring & result,
|
|
const spi::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 void convert(tstring & result,
|
|
const spi::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 tstring& pattern,
|
|
bool use_gmtime);
|
|
virtual void convert(tstring & result,
|
|
const spi::InternalLoggingEvent& event);
|
|
|
|
private:
|
|
bool use_gmtime;
|
|
tstring format;
|
|
};
|
|
|
|
|
|
//! This pattern is used to format miliseconds since process start.
|
|
class RelativeTimestampConverter: public PatternConverter {
|
|
public:
|
|
RelativeTimestampConverter(const FormattingInfo& info);
|
|
virtual void convert(tstring & result,
|
|
const spi::InternalLoggingEvent& event);
|
|
};
|
|
|
|
|
|
/**
|
|
* This PatternConverter is used to format the hostname field.
|
|
*/
|
|
class HostnamePatternConverter : public PatternConverter {
|
|
public:
|
|
HostnamePatternConverter(const FormattingInfo& info, bool fqdn);
|
|
virtual void convert(tstring & result,
|
|
const spi::InternalLoggingEvent& event);
|
|
|
|
private:
|
|
tstring hostname_;
|
|
};
|
|
|
|
|
|
/**
|
|
* This PatternConverter is used to format the MDC field found in
|
|
* the InternalLoggingEvent object, optionally limited to
|
|
* \c k Mapped diagnostic context key.
|
|
*/
|
|
class MDCPatternConverter
|
|
: public PatternConverter
|
|
{
|
|
public:
|
|
MDCPatternConverter(const FormattingInfo& info, tstring const & k);
|
|
virtual void convert(tstring & result,
|
|
const spi::InternalLoggingEvent& event);
|
|
|
|
private:
|
|
tstring key;
|
|
};
|
|
|
|
|
|
/**
|
|
* 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 void convert(tstring & result,
|
|
const spi::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
|
|
{
|
|
public:
|
|
PatternParser(const tstring& pattern, unsigned ndcMaxDepth);
|
|
std::vector<PatternConverter*> parse();
|
|
|
|
private:
|
|
// Types
|
|
enum ParserState { LITERAL_STATE,
|
|
CONVERTER_STATE,
|
|
DOT_STATE,
|
|
MIN_STATE,
|
|
MAX_STATE };
|
|
|
|
// Methods
|
|
tstring extractOption();
|
|
int extractPrecisionOption();
|
|
void finalizeConverter(tchar c);
|
|
|
|
// Data
|
|
tstring pattern;
|
|
FormattingInfo formattingInfo;
|
|
std::vector<PatternConverter*> list;
|
|
ParserState state;
|
|
tstring::size_type pos;
|
|
tstring currentLiteral;
|
|
unsigned ndcMaxDepth;
|
|
};
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
// FormattingInfo methods:
|
|
////////////////////////////////////////////////
|
|
|
|
void
|
|
FormattingInfo::reset() {
|
|
minLen = -1;
|
|
maxLen = 0x7FFFFFFF;
|
|
leftAlign = false;
|
|
}
|
|
|
|
|
|
void
|
|
FormattingInfo::dump(helpers::LogLog& loglog) {
|
|
tostringstream buf;
|
|
buf << LOG4CPLUS_TEXT("min=") << minLen
|
|
<< LOG4CPLUS_TEXT(", max=") << maxLen
|
|
<< LOG4CPLUS_TEXT(", leftAlign=") << std::boolalpha << leftAlign;
|
|
loglog.debug(buf.str());
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
// PatternConverter methods:
|
|
////////////////////////////////////////////////
|
|
|
|
PatternConverter::PatternConverter(const FormattingInfo& i)
|
|
{
|
|
minLen = i.minLen;
|
|
maxLen = i.maxLen;
|
|
leftAlign = i.leftAlign;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
PatternConverter::formatAndAppend(
|
|
tostream& output, const spi::InternalLoggingEvent& event)
|
|
{
|
|
tstring & s = internal::get_ptd ()->faa_str;
|
|
convert (s, event);
|
|
std::size_t len = s.length();
|
|
|
|
if (len > maxLen)
|
|
output << s.substr(len - maxLen);
|
|
else if (static_cast<int>(len) < minLen)
|
|
{
|
|
std::ios_base::fmtflags const original_flags = output.flags ();
|
|
tchar const fill = output.fill (LOG4CPLUS_TEXT(' '));
|
|
output.setf (leftAlign ? std::ios_base::left : std::ios_base::right,
|
|
std::ios_base::adjustfield);
|
|
output.width (minLen);
|
|
output << s;
|
|
output.fill (fill);
|
|
output.flags (original_flags);
|
|
}
|
|
else
|
|
output << s;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
// LiteralPatternConverter methods:
|
|
////////////////////////////////////////////////
|
|
|
|
LiteralPatternConverter::LiteralPatternConverter(
|
|
const tstring& str_)
|
|
: PatternConverter(FormattingInfo())
|
|
, str(str_)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
// BasicPatternConverter methods:
|
|
////////////////////////////////////////////////
|
|
|
|
BasicPatternConverter::BasicPatternConverter(
|
|
const FormattingInfo& info, Type type_)
|
|
: PatternConverter(info)
|
|
, llmCache(getLogLevelManager())
|
|
, type(type_)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
void
|
|
BasicPatternConverter::convert(tstring & result,
|
|
const spi::InternalLoggingEvent& event)
|
|
{
|
|
switch(type)
|
|
{
|
|
case LOGLEVEL_CONVERTER:
|
|
result = llmCache.toString(event.getLogLevel());
|
|
return;
|
|
|
|
case BASENAME_CONVERTER:
|
|
result = get_basename(event.getFile());
|
|
return;
|
|
|
|
case PROCESS_CONVERTER:
|
|
helpers::convertIntegerToString(result, internal::get_process_id ());
|
|
return;
|
|
|
|
case NDC_CONVERTER:
|
|
result = event.getNDC();
|
|
return;
|
|
|
|
case MESSAGE_CONVERTER:
|
|
result = event.getMessage();
|
|
return;
|
|
|
|
case NEWLINE_CONVERTER:
|
|
result = LOG4CPLUS_TEXT("\n");
|
|
return;
|
|
|
|
case FILE_CONVERTER:
|
|
result = event.getFile();
|
|
return;
|
|
|
|
case THREAD_CONVERTER:
|
|
result = event.getThread();
|
|
return;
|
|
|
|
case THREAD2_CONVERTER:
|
|
result = event.getThread2();
|
|
return;
|
|
|
|
case LINE_CONVERTER:
|
|
{
|
|
if(event.getLine() != -1)
|
|
helpers::convertIntegerToString(result, event.getLine());
|
|
else
|
|
result.clear ();
|
|
return;
|
|
}
|
|
|
|
case FULL_LOCATION_CONVERTER:
|
|
{
|
|
tstring const & file = event.getFile();
|
|
if (! file.empty ())
|
|
{
|
|
result = file;
|
|
result += LOG4CPLUS_TEXT(":");
|
|
result += helpers::convertIntegerToString(event.getLine());
|
|
}
|
|
else
|
|
result = LOG4CPLUS_TEXT(":");
|
|
return;
|
|
}
|
|
|
|
case FUNCTION_CONVERTER:
|
|
result = event.getFunction ();
|
|
return;
|
|
}
|
|
|
|
result = LOG4CPLUS_TEXT("INTERNAL LOG4CPLUS ERROR");
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
// LoggerPatternConverter methods:
|
|
////////////////////////////////////////////////
|
|
|
|
LoggerPatternConverter::LoggerPatternConverter(
|
|
const FormattingInfo& info, int prec)
|
|
: PatternConverter(info)
|
|
, precision(prec)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
void
|
|
LoggerPatternConverter::convert(tstring & result,
|
|
const spi::InternalLoggingEvent& event)
|
|
{
|
|
const tstring& name = event.getLoggerName();
|
|
if (precision <= 0) {
|
|
result = name;
|
|
}
|
|
else {
|
|
std::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) {
|
|
result = name;
|
|
return;
|
|
}
|
|
}
|
|
result = name.substr(end + 1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
// DatePatternConverter methods:
|
|
////////////////////////////////////////////////
|
|
|
|
|
|
DatePatternConverter::DatePatternConverter(
|
|
const FormattingInfo& info, const tstring& pattern,
|
|
bool use_gmtime_)
|
|
: PatternConverter(info)
|
|
, use_gmtime(use_gmtime_)
|
|
, format(pattern)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
void
|
|
DatePatternConverter::convert(tstring & result,
|
|
const spi::InternalLoggingEvent& event)
|
|
{
|
|
result = event.getTimestamp().getFormattedTime(format, use_gmtime);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
RelativeTimestampConverter::RelativeTimestampConverter (FormattingInfo const & info)
|
|
: PatternConverter (info)
|
|
{ }
|
|
|
|
|
|
void
|
|
RelativeTimestampConverter::convert (tstring & result,
|
|
spi::InternalLoggingEvent const & event)
|
|
{
|
|
tostringstream & oss = internal::get_ptd ()->layout_oss;
|
|
detail::clear_tostringstream (oss);
|
|
formatRelativeTimestamp (oss, event);
|
|
oss.str ().swap (result);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
// HostnamePatternConverter methods:
|
|
////////////////////////////////////////////////
|
|
|
|
HostnamePatternConverter::HostnamePatternConverter (
|
|
const FormattingInfo& info, bool fqdn)
|
|
: PatternConverter(info)
|
|
, hostname_ (helpers::getHostname (fqdn))
|
|
{ }
|
|
|
|
|
|
void
|
|
HostnamePatternConverter::convert (
|
|
tstring & result, const spi::InternalLoggingEvent&)
|
|
{
|
|
result = hostname_;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
// MDCPatternConverter methods:
|
|
////////////////////////////////////////////////
|
|
|
|
log4cplus::pattern::MDCPatternConverter::MDCPatternConverter (
|
|
const FormattingInfo& info, tstring const & k)
|
|
: PatternConverter(info)
|
|
, key (k)
|
|
{ }
|
|
|
|
|
|
void
|
|
log4cplus::pattern::MDCPatternConverter::convert (tstring & result,
|
|
const spi::InternalLoggingEvent& event)
|
|
{
|
|
result = event.getMDC (key);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
// NDCPatternConverter methods:
|
|
////////////////////////////////////////////////
|
|
|
|
log4cplus::pattern::NDCPatternConverter::NDCPatternConverter (
|
|
const FormattingInfo& info, int precision_)
|
|
: PatternConverter(info)
|
|
, precision(precision_)
|
|
{ }
|
|
|
|
|
|
void
|
|
log4cplus::pattern::NDCPatternConverter::convert (tstring & result,
|
|
const spi::InternalLoggingEvent& event)
|
|
{
|
|
const log4cplus::tstring& text = event.getNDC();
|
|
if (precision <= 0)
|
|
result = 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);
|
|
|
|
result = text.substr(0, p);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
// PatternParser methods:
|
|
////////////////////////////////////////////////
|
|
|
|
PatternParser::PatternParser(
|
|
const tstring& pattern_, unsigned ndcMaxDepth_)
|
|
: pattern(pattern_)
|
|
, state(LITERAL_STATE)
|
|
, pos(0)
|
|
, ndcMaxDepth (ndcMaxDepth_)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
tstring
|
|
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) {
|
|
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("\"");
|
|
helpers::getLogLog().error(buf.str());
|
|
pos = pattern.length();
|
|
}
|
|
}
|
|
|
|
return LOG4CPLUS_TEXT("");
|
|
}
|
|
|
|
|
|
int
|
|
PatternParser::extractPrecisionOption()
|
|
{
|
|
tstring opt = extractOption();
|
|
int r = 0;
|
|
if (! opt.empty ())
|
|
r = std::atoi(LOG4CPLUS_TSTRING_TO_STRING(opt).c_str());
|
|
|
|
return r;
|
|
}
|
|
|
|
|
|
|
|
PatternConverterList
|
|
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 {
|
|
tostringstream buf;
|
|
buf << LOG4CPLUS_TEXT("Error occured in position ")
|
|
<< pos
|
|
<< LOG4CPLUS_TEXT(".\n Was expecting digit, instead got char \"")
|
|
<< c
|
|
<< LOG4CPLUS_TEXT("\".");
|
|
helpers::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
|
|
PatternParser::finalizeConverter(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'):
|
|
{
|
|
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;
|
|
|
|
case LOG4CPLUS_TEXT('M'):
|
|
pc = new BasicPatternConverter (
|
|
formattingInfo, BasicPatternConverter::FUNCTION_CONVERTER);
|
|
//getLogLog().debug("METHOD (function name) converter.");
|
|
//formattingInfo.dump(getLogLog());
|
|
break;
|
|
|
|
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;
|
|
|
|
case LOG4CPLUS_TEXT('r'):
|
|
pc = new RelativeTimestampConverter (formattingInfo);
|
|
//getLogLog().debug("RELATIVE converter.");
|
|
//formattingInfo.dump(getLogLog());
|
|
break;
|
|
|
|
case LOG4CPLUS_TEXT('t'):
|
|
pc = new BasicPatternConverter
|
|
(formattingInfo,
|
|
BasicPatternConverter::THREAD_CONVERTER);
|
|
//getLogLog().debug("THREAD converter.");
|
|
//formattingInfo.dump(getLogLog());
|
|
break;
|
|
|
|
case LOG4CPLUS_TEXT('T'):
|
|
pc = new BasicPatternConverter
|
|
(formattingInfo,
|
|
BasicPatternConverter::THREAD2_CONVERTER);
|
|
//getLogLog().debug("THREAD2 converter.");
|
|
//formattingInfo.dump(getLogLog());
|
|
break;
|
|
|
|
case LOG4CPLUS_TEXT('x'):
|
|
pc = new NDCPatternConverter (formattingInfo, ndcMaxDepth);
|
|
//getLogLog().debug("NDC converter.");
|
|
break;
|
|
|
|
case LOG4CPLUS_TEXT('X'):
|
|
pc = new MDCPatternConverter (formattingInfo, extractOption ());
|
|
//getLogLog().debug("MDC converter.");
|
|
break;
|
|
|
|
default:
|
|
tostringstream buf;
|
|
buf << LOG4CPLUS_TEXT("Unexpected char [")
|
|
<< c
|
|
<< LOG4CPLUS_TEXT("] at position ")
|
|
<< pos
|
|
<< LOG4CPLUS_TEXT(" in conversion patterrn.");
|
|
helpers::getLogLog().error(buf.str());
|
|
pc = new LiteralPatternConverter(currentLiteral);
|
|
}
|
|
|
|
list.push_back(pc);
|
|
currentLiteral.resize(0);
|
|
state = LITERAL_STATE;
|
|
formattingInfo.reset();
|
|
}
|
|
|
|
|
|
} // namespace pattern
|
|
|
|
|
|
typedef pattern::PatternConverterList PatternConverterList;
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
// PatternLayout methods:
|
|
////////////////////////////////////////////////
|
|
|
|
PatternLayout::PatternLayout(const tstring& pattern_)
|
|
{
|
|
init(pattern_, 0);
|
|
}
|
|
|
|
|
|
PatternLayout::PatternLayout(const helpers::Properties& properties)
|
|
{
|
|
unsigned ndcMaxDepth = 0;
|
|
properties.getUInt (ndcMaxDepth, LOG4CPLUS_TEXT ("NDCMaxDepth"));
|
|
|
|
bool hasPattern = properties.exists( LOG4CPLUS_TEXT("Pattern") );
|
|
bool hasConversionPattern = properties.exists( LOG4CPLUS_TEXT("ConversionPattern") );
|
|
|
|
if(hasPattern) {
|
|
helpers::getLogLog().warn(
|
|
LOG4CPLUS_TEXT("PatternLayout- the \"Pattern\" property has been")
|
|
LOG4CPLUS_TEXT(" deprecated. Use \"ConversionPattern\" instead."));
|
|
}
|
|
|
|
if(hasConversionPattern) {
|
|
init(properties.getProperty( LOG4CPLUS_TEXT("ConversionPattern") ),
|
|
ndcMaxDepth);
|
|
}
|
|
else if(hasPattern) {
|
|
init(properties.getProperty( LOG4CPLUS_TEXT("Pattern") ), ndcMaxDepth);
|
|
}
|
|
else {
|
|
helpers::getLogLog().error(
|
|
LOG4CPLUS_TEXT ("ConversionPattern not specified in properties"),
|
|
true);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void
|
|
PatternLayout::init(const tstring& pattern_, unsigned ndcMaxDepth)
|
|
{
|
|
pattern = pattern_;
|
|
parsedPattern = pattern::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 ) {
|
|
helpers::getLogLog().error(
|
|
LOG4CPLUS_TEXT("Parsed Pattern created a NULL PatternConverter"));
|
|
(*it) = new pattern::LiteralPatternConverter( LOG4CPLUS_TEXT("") );
|
|
}
|
|
}
|
|
if(parsedPattern.empty ()) {
|
|
helpers::getLogLog().warn(
|
|
LOG4CPLUS_TEXT("PatternLayout pattern is empty. Using default..."));
|
|
parsedPattern.push_back (
|
|
new pattern::BasicPatternConverter(pattern::FormattingInfo(),
|
|
pattern::BasicPatternConverter::MESSAGE_CONVERTER));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
PatternLayout::~PatternLayout()
|
|
{
|
|
for(PatternConverterList::iterator it=parsedPattern.begin();
|
|
it!=parsedPattern.end();
|
|
++it)
|
|
{
|
|
delete (*it);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
PatternLayout::formatAndAppend(tostream& output,
|
|
const spi::InternalLoggingEvent& event)
|
|
{
|
|
for(PatternConverterList::iterator it=parsedPattern.begin();
|
|
it!=parsedPattern.end();
|
|
++it)
|
|
{
|
|
(*it)->formatAndAppend(output, event);
|
|
}
|
|
}
|
|
|
|
|
|
} // namespace log4cplus
|