38#include "blocxx/BLOCXX_config.h"
54#ifdef BLOCXX_HAVE_UNISTD_H
68namespace LogMessagePatternFormatterImpl
95using namespace LogMessagePatternFormatterImpl;
186 (*i)->formatMessage(message, output);
198class MessageConverter :
public Converter
205 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
207 output += message.message;
211#define CDATA_START_DEF "<![CDATA["
212#define CDATA_END_DEF "]]>"
213#define CDATA_PSEUDO_END_DEF "]]>"
221class XMLMessageConverter :
public Converter
224 XMLMessageConverter(
const Formatting&
formatting)
228 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
230 output += CDATA_START;
231 const String& msg(message.message);
234 size_t end = msg.indexOf(CDATA_END);
243 output.append(&msg[start], end - start);
244 output += CDATA_EMBEDDED_END;
245 start = end +
static_cast<String
>(CDATA_END).length();
246 if (start < msg.length())
248 end = msg.indexOf(CDATA_END, start);
261class LiteralConverter :
public Converter
264 LiteralConverter(
const String&
literal)
268 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
278class ThreadConverter :
public Converter
285 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
292class PidConverter :
public Converter
299 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
302 output += ::GetCurrentProcessId();
304 output += ::getpid();
310class ComponentConverter :
public Converter
313 ComponentConverter(
const Formatting&
formatting,
int precision)
318 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
320 if (m_precision <= 0)
322 output += message.component;
326 const String& component(message.component);
327 size_t len(component.length());
329 for (
int i = m_precision;
i > 0; --
i)
331 end = component.lastIndexOf(
'.', end - 1);
338 output += component.substring(end + 1, len - (end + 1));
347class FileLocationConverter :
public Converter
350 FileLocationConverter(
const Formatting&
formatting)
354 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
356 if (message.filename != 0)
358 output += message.filename;
364class FullLocationConverter :
public Converter
367 FullLocationConverter(
const Formatting&
formatting)
371 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
373 if (message.filename != 0)
375 output += message.filename;
377 output += message.fileline;
384class LineLocationConverter :
public Converter
387 LineLocationConverter(
const Formatting&
formatting)
391 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
393 output += message.fileline;
398class MethodLocationConverter :
public Converter
401 MethodLocationConverter(
const Formatting&
formatting)
405 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
407 if (message.methodname != 0)
409 output += message.methodname;
415class CategoryConverter :
public Converter
418 CategoryConverter(
const Formatting&
formatting)
422 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
424 output += message.category;
429class RelativeTimeConverter :
public Converter
432 RelativeTimeConverter(
const Formatting&
formatting)
436 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
438 output += getRelativeTime();
442 static UInt64 getRelativeTime()
449 static UInt64 getNowMillis()
453 return UInt64(now.get()) * 1000 + (now.getMicrosecond() / 1000);
457UInt64 RelativeTimeConverter::startMillis(RelativeTimeConverter::getNowMillis());
470class DateConverter :
public Converter
473 DateConverter(
const Formatting&
formatting,
const String& format)
477 size_t pos =
m_format.indexOf(
"%Q");
485 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
494 size_t len = ::strftime(buf,
sizeof(buf),
m_format.c_str(), &nowTm);
499 char* p = strstr(buf,
"%Q");
504 long deciMillis = now.getMicrosecond() / 1000;
505 String strMillis(deciMillis);
507 switch (strMillis.length())
534const char*
const DateConverter::ISO8601_DATE_FORMAT =
"ISO8601";
535const char*
const DateConverter::ISO8601_PATTERN =
"%Y-%m-%d %H:%M:%S,%Q";
536const char*
const DateConverter::ABSOLUTE_DATE_FORMAT =
"ABSOLUTE";
537const char*
const DateConverter::ABSOLUTE_PATTERN =
"%H:%M:%S,%Q";
538const char*
const DateConverter::DATE_DATE_FORMAT =
"DATE";
539const char*
const DateConverter::DATE_PATTERN =
"%d %b %Y %H:%M:%S,%Q";
545 Parser(
const String& pattern_)
547 ,
state(E_LITERAL_STATE)
552 void parse(Array<ConverterRef>& converters)
555 size_t patternLength(
pattern.length());
557 while (i < patternLength)
563 case E_LITERAL_STATE:
565 if (i == patternLength)
586 converters.push_back(ConverterRef(
new LiteralConverter(
literal.toString())));
590 state = E_CONVERTER_STATE;
621 if (i + 1 > patternLength)
631 int hexNumber = std::strtol(begin, &end, 16);
632 if (end == begin || errno == ERANGE || hexNumber > CHAR_MAX)
638 literal +=
static_cast<char>(hexNumber);
639 i += (end - begin) + 1;
655 case E_CONVERTER_STATE:
674 converters.push_back(finalizeConverter(c));
692 converters.push_back(finalizeConverter(c));
707 Format(
"Invalid pattern \"%1\" in position %2. Was expecting a digit, instead got char %3.",
708 pattern, i, c).c_str(),
722 converters.push_back(finalizeConverter(c));
723 state = E_LITERAL_STATE;
733 converters.push_back(ConverterRef(
new LiteralConverter(
literal.toString())));
741 if ((i <
pattern.length()) && (pattern[i] ==
'{'))
743 size_t end =
pattern.indexOf(
'}', i);
746 String rv =
pattern.substring(i + 1, end - (i + 1));
759 String opt = getOption();
767 catch (StringConversionException& e)
770 Format(
"Invalid pattern \"%1\" in position %2. A positive integer is required for precision option (%3).",
771 pattern, i, opt).c_str(),
779 ConverterRef finalizeConverter(
char c)
787 rv =
new ComponentConverter(formatting, getPrecision());
794 String dateOpt = getOption();
797 dateFormat = DateConverter::ISO8601_DATE_FORMAT;
801 dateFormat = dateOpt;
805 if (dateFormat.equalsIgnoreCase(DateConverter::ISO8601_DATE_FORMAT))
807 dateFormat = DateConverter::ISO8601_PATTERN;
809 else if (dateFormat.equalsIgnoreCase(DateConverter::ABSOLUTE_DATE_FORMAT))
811 dateFormat = DateConverter::ABSOLUTE_PATTERN;
813 else if (dateFormat.equalsIgnoreCase(DateConverter::DATE_DATE_FORMAT))
815 dateFormat = DateConverter::DATE_PATTERN;
818 rv =
new DateConverter(formatting, dateFormat);
824 rv =
new FileLocationConverter(formatting);
830 rv =
new FullLocationConverter(formatting);
836 rv =
new LineLocationConverter(formatting);
842 rv =
new MethodLocationConverter(formatting);
848 rv =
new MessageConverter(formatting);
854 rv =
new XMLMessageConverter(formatting);
860 rv =
new CategoryConverter(formatting);
866 rv =
new RelativeTimeConverter(formatting);
872 rv =
new ThreadConverter(formatting);
878 rv =
new PidConverter(formatting);
897 Format(
"Invalid pattern \"%1\" in position %2. Unsupported conversion (%3).",
898 pattern, i, c).c_str(),
906 state = E_LITERAL_STATE;
#define BLOCXX_DEFINE_EXCEPTION_WITH_ID(NAME)
Define a new exception class named <NAME>Exception that derives from Exception.
#define BLOCXX_THROW_ERR(exType, msg, err)
Throw an exception using FILE and LINE.
#define BLOCXX_GLOBAL_STRING_INIT(str)
V::const_iterator const_iterator
This class can be used to store a global variable that is lazily initialized in a thread safe manner.
StringBuffer & append(char c)
void truncate(size_t index)
Truncate the string at the given index.
This String class is an abstract data type that represents as NULL terminated string of characters.
String substring(size_t beginIndex, size_t length=npos) const
Create another String object that is comprised of a substring of this String object.
BLOCXX_COMMON_API UInt64 thread_t_ToUInt64(Thread_t thr)
Convert a Thread_t to an UInt64.
LazyGlobal< String, char const *const > GlobalString