38 #include "blocxx/BLOCXX_config.h"
54 #ifdef BLOCXX_HAVE_UNISTD_H
63 namespace BLOCXX_NAMESPACE
68 namespace LogMessagePatternFormatterImpl
95 using namespace LogMessagePatternFormatterImpl;
105 : m_formatting(formatting)
114 convert(message, output);
119 convert(message, buf);
123 if (m_formatting.minWidth > 0)
125 output.
append(&(std::vector<char>(
size_t(m_formatting.minWidth),
' ')[0]), m_formatting.minWidth);
131 if (len > m_formatting.maxWidth)
135 buf.
truncate(m_formatting.maxWidth);
143 else if (len < m_formatting.minWidth)
148 output.
append(&(std::vector<char>(
size_t(m_formatting.minWidth - len),
' ')[0]), m_formatting.minWidth - len);
152 output.
append(&(std::vector<char>(
size_t(m_formatting.minWidth - len),
' ')[0]), m_formatting.minWidth - len);
183 iter_t end(m_patternConverters.end());
184 for (iter_t
i(m_patternConverters.begin());
i != end; ++
i)
186 (*i)->formatMessage(message, output);
198 class MessageConverter :
public Converter
202 : Converter(formatting)
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 "]]>"
221 class XMLMessageConverter :
public Converter
224 XMLMessageConverter(
const Formatting&
formatting)
225 : Converter(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);
261 class LiteralConverter :
public Converter
264 LiteralConverter(
const String&
literal)
268 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
278 class ThreadConverter :
public Converter
282 : Converter(formatting)
285 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
292 class PidConverter :
public Converter
295 PidConverter(
const Formatting& formatting)
296 : Converter(formatting)
299 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
302 output += ::GetCurrentProcessId();
304 output += ::getpid();
310 class ComponentConverter :
public Converter
313 ComponentConverter(
const Formatting& formatting,
int precision)
314 : Converter(formatting)
318 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
322 output += message.component;
326 const String& component(message.component);
327 size_t len(component.length());
331 end = component.lastIndexOf(
'.', end - 1);
338 output += component.substring(end + 1, len - (end + 1));
347 class FileLocationConverter :
public Converter
350 FileLocationConverter(
const Formatting& formatting)
351 : Converter(formatting)
354 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
356 if (message.filename != 0)
358 output += message.filename;
364 class FullLocationConverter :
public Converter
367 FullLocationConverter(
const Formatting& formatting)
368 : Converter(formatting)
371 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
373 if (message.filename != 0)
375 output += message.filename;
377 output += message.fileline;
384 class LineLocationConverter :
public Converter
387 LineLocationConverter(
const Formatting& formatting)
388 : Converter(formatting)
391 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
393 output += message.fileline;
398 class MethodLocationConverter :
public Converter
401 MethodLocationConverter(
const Formatting& formatting)
402 : Converter(formatting)
405 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
407 if (message.methodname != 0)
409 output += message.methodname;
415 class CategoryConverter :
public Converter
418 CategoryConverter(
const Formatting& formatting)
419 : Converter(formatting)
422 virtual void convert(
const LogMessage &message, StringBuffer &output)
const
424 output += message.category;
429 class RelativeTimeConverter :
public Converter
432 RelativeTimeConverter(
const Formatting& formatting)
433 : Converter(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);
470 class DateConverter :
public Converter
473 DateConverter(
const Formatting& formatting,
const String& format)
474 : Converter(formatting)
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())
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;
591 formatting = Formatting();
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:
669 formatting.minWidth = c -
'0';
674 converters.push_back(finalizeConverter(c));
684 formatting.minWidth = formatting.minWidth * 10 + (c -
'0');
692 converters.push_back(finalizeConverter(c));
701 formatting.maxWidth = c -
'0';
707 Format(
"Invalid pattern \"%1\" in position %2. Was expecting a digit, instead got char %3.",
718 formatting.maxWidth = formatting.maxWidth * 10 + (c -
'0');
722 converters.push_back(finalizeConverter(c));
723 state = E_LITERAL_STATE;
733 converters.push_back(ConverterRef(
new LiteralConverter(
literal.toString())));
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).",
779 ConverterRef finalizeConverter(
char c)
787 rv =
new ComponentConverter(formatting, getPrecision());
794 String dateOpt = getOption();
801 dateFormat = dateOpt;
805 if (dateFormat.equalsIgnoreCase(DateConverter::ISO8601_DATE_FORMAT))
809 else if (dateFormat.equalsIgnoreCase(DateConverter::ABSOLUTE_DATE_FORMAT))
813 else if (dateFormat.equalsIgnoreCase(DateConverter::DATE_DATE_FORMAT))
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);
881 #if 0 // don't support these for now.
897 Format(
"Invalid pattern \"%1\" in position %2. Unsupported conversion (%3).",
906 state = E_LITERAL_STATE;
907 formatting = Formatting();
925 Parser parser(pattern);
926 parser.parse(m_patternConverters);