blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved. 00003 * Copyright (C) 2006, Novell, Inc. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Vintela, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 00031 *******************************************************************************/ 00032 00033 00038 #include "blocxx/BLOCXX_config.h" 00039 #include "blocxx/LogMessagePatternFormatter.hpp" 00040 #include "blocxx/String.hpp" 00041 #include "blocxx/LogMessage.hpp" 00042 #include "blocxx/StringBuffer.hpp" 00043 #include "blocxx/IntrusiveCountableBase.hpp" 00044 #include "blocxx/Format.hpp" 00045 #include "blocxx/ExceptionIds.hpp" 00046 #include "blocxx/DateTime.hpp" 00047 #include "blocxx/ThreadImpl.hpp" 00048 #include "blocxx/GlobalString.hpp" 00049 00050 #include <vector> 00051 #include <cstdlib> // for strtol 00052 #include <climits> // for CHAR_MAX 00053 00054 #ifdef BLOCXX_HAVE_UNISTD_H 00055 #include <unistd.h> 00056 #endif 00057 00058 extern "C" 00059 { 00060 #include <errno.h> 00061 } 00062 00063 namespace BLOCXX_NAMESPACE 00064 { 00065 00066 BLOCXX_DEFINE_EXCEPTION_WITH_ID(LogMessagePatternFormatter); 00067 00068 namespace LogMessagePatternFormatterImpl // if this is anonymous, gcc 4.1.1 spits out a warning about using a data member from an unnamed namespace. 00069 { 00070 00071 enum EJustificationFlag 00072 { 00073 E_RIGHT_JUSTIFY, 00074 E_LEFT_JUSTIFY 00075 }; 00076 00077 struct Formatting 00078 { 00079 int minWidth; 00080 int maxWidth; 00081 EJustificationFlag justification; 00082 00083 static const int NO_MIN_WIDTH = -1; 00084 static const int NO_MAX_WIDTH = 0x7FFFFFFF; 00085 00086 Formatting() 00087 : minWidth(NO_MIN_WIDTH) 00088 , maxWidth(NO_MAX_WIDTH) 00089 , justification(E_RIGHT_JUSTIFY) 00090 {} 00091 }; 00092 00093 } // end namespace LogMessagePatternFormatterImpl 00094 00095 using namespace LogMessagePatternFormatterImpl; 00096 00098 class LogMessagePatternFormatter::Converter : public IntrusiveCountableBase 00099 { 00100 public: 00101 Converter() 00102 {} 00103 00104 Converter(const Formatting& formatting) 00105 : m_formatting(formatting) 00106 {} 00107 00108 virtual ~Converter() {} 00109 00110 virtual void formatMessage(const LogMessage& message, StringBuffer& output) const 00111 { 00112 if ((m_formatting.minWidth == Formatting::NO_MIN_WIDTH) && (m_formatting.maxWidth == Formatting::NO_MAX_WIDTH)) 00113 { 00114 convert(message, output); 00115 } 00116 else 00117 { 00118 StringBuffer buf; 00119 convert(message, buf); 00120 00121 if (buf.length() == 0) 00122 { 00123 if (m_formatting.minWidth > 0) 00124 { 00125 output.append(&(std::vector<char>(size_t(m_formatting.minWidth), ' ')[0]), m_formatting.minWidth); 00126 } 00127 return; 00128 } 00129 00130 int len = buf.length(); 00131 if (len > m_formatting.maxWidth) 00132 { 00133 if (m_formatting.justification == E_LEFT_JUSTIFY) 00134 { 00135 buf.truncate(m_formatting.maxWidth); 00136 output += buf; 00137 } 00138 else 00139 { 00140 output += buf.releaseString().substring(len - m_formatting.maxWidth); 00141 } 00142 } 00143 else if (len < m_formatting.minWidth) 00144 { 00145 if (m_formatting.justification == E_LEFT_JUSTIFY) 00146 { 00147 output += buf; 00148 output.append(&(std::vector<char>(size_t(m_formatting.minWidth - len), ' ')[0]), m_formatting.minWidth - len); 00149 } 00150 else 00151 { 00152 output.append(&(std::vector<char>(size_t(m_formatting.minWidth - len), ' ')[0]), m_formatting.minWidth - len); 00153 output += buf; 00154 } 00155 } 00156 else 00157 { 00158 output += buf; 00159 } 00160 } 00161 } 00162 00163 virtual void convert(const LogMessage& message, StringBuffer& output) const = 0; 00164 00165 private: 00166 Formatting m_formatting; 00167 00168 }; 00169 00171 const GlobalString LogMessagePatternFormatter::STR_DEFAULT_MESSAGE_PATTERN = BLOCXX_GLOBAL_STRING_INIT("%r [%t] %p %c - %m"); 00172 00174 LogMessagePatternFormatter::~LogMessagePatternFormatter() 00175 { 00176 } 00177 00179 void 00180 LogMessagePatternFormatter::formatMessage(const LogMessage& message, StringBuffer& output) const 00181 { 00182 typedef Array<ConverterRef>::const_iterator iter_t; 00183 iter_t end(m_patternConverters.end()); 00184 for (iter_t i(m_patternConverters.begin()); i != end; ++i) 00185 { 00186 (*i)->formatMessage(message, output); 00187 } 00188 } 00189 00191 namespace 00192 { 00193 00194 typedef LogMessagePatternFormatter::Converter Converter; 00195 typedef LogMessagePatternFormatter::ConverterRef ConverterRef; 00196 00198 class MessageConverter : public Converter 00199 { 00200 public: 00201 MessageConverter(const Formatting& formatting) 00202 : Converter(formatting) 00203 {} 00204 00205 virtual void convert(const LogMessage &message, StringBuffer &output) const 00206 { 00207 output += message.message; 00208 } 00209 }; 00210 00211 #define CDATA_START_DEF "<![CDATA[" 00212 #define CDATA_END_DEF "]]>" 00213 #define CDATA_PSEUDO_END_DEF "]]>" 00214 00215 GlobalString CDATA_START = BLOCXX_GLOBAL_STRING_INIT(CDATA_START_DEF); 00216 GlobalString CDATA_END = BLOCXX_GLOBAL_STRING_INIT(CDATA_END_DEF); 00217 GlobalString CDATA_PSEUDO_END = BLOCXX_GLOBAL_STRING_INIT(CDATA_PSEUDO_END_DEF); 00218 GlobalString CDATA_EMBEDDED_END = BLOCXX_GLOBAL_STRING_INIT(CDATA_END_DEF CDATA_PSEUDO_END_DEF CDATA_START_DEF); 00219 00221 class XMLMessageConverter : public Converter 00222 { 00223 public: 00224 XMLMessageConverter(const Formatting& formatting) 00225 : Converter(formatting) 00226 {} 00227 00228 virtual void convert(const LogMessage &message, StringBuffer &output) const 00229 { 00230 output += CDATA_START; 00231 const String& msg(message.message); 00232 if (!msg.empty()) 00233 { 00234 size_t end = msg.indexOf(CDATA_END); 00235 if (end == String::npos) 00236 { 00237 output += msg; 00238 } 00239 00240 size_t start(0); 00241 while (end != String::npos) 00242 { 00243 output.append(&msg[start], end - start); 00244 output += CDATA_EMBEDDED_END; 00245 start = end + static_cast<String>(CDATA_END).length(); 00246 if (start < msg.length()) 00247 { 00248 end = msg.indexOf(CDATA_END, start); 00249 } 00250 else 00251 { 00252 break; 00253 } 00254 } 00255 } 00256 output += CDATA_END; 00257 } 00258 }; 00259 00261 class LiteralConverter : public Converter 00262 { 00263 public: 00264 LiteralConverter(const String& literal) 00265 : m_literal(literal) 00266 {} 00267 00268 virtual void convert(const LogMessage &message, StringBuffer &output) const 00269 { 00270 output += m_literal; 00271 } 00272 00273 private: 00274 String m_literal; 00275 }; 00276 00278 class ThreadConverter : public Converter 00279 { 00280 public: 00281 ThreadConverter(const Formatting& formatting) 00282 : Converter(formatting) 00283 {} 00284 00285 virtual void convert(const LogMessage &message, StringBuffer &output) const 00286 { 00287 output += ThreadImpl::thread_t_ToUInt64(ThreadImpl::currentThread()); 00288 } 00289 }; 00290 00292 class PidConverter : public Converter 00293 { 00294 public: 00295 PidConverter(const Formatting& formatting) 00296 : Converter(formatting) 00297 {} 00298 00299 virtual void convert(const LogMessage &message, StringBuffer &output) const 00300 { 00301 #ifdef BLOCXX_WIN32 00302 output += ::GetCurrentProcessId(); 00303 #else 00304 output += ::getpid(); 00305 #endif 00306 } 00307 }; 00308 00310 class ComponentConverter : public Converter 00311 { 00312 public: 00313 ComponentConverter(const Formatting& formatting, int precision) 00314 : Converter(formatting) 00315 , m_precision(precision) 00316 {} 00317 00318 virtual void convert(const LogMessage &message, StringBuffer &output) const 00319 { 00320 if (m_precision <= 0) 00321 { 00322 output += message.component; 00323 } 00324 else 00325 { 00326 const String& component(message.component); 00327 size_t len(component.length()); 00328 size_t end(len - 1); 00329 for (int i = m_precision; i > 0; --i) 00330 { 00331 end = component.lastIndexOf('.', end - 1); 00332 if (end == String::npos) 00333 { 00334 output += component; 00335 return; 00336 } 00337 } 00338 output += component.substring(end + 1, len - (end + 1)); 00339 } 00340 } 00341 00342 private: 00343 int m_precision; 00344 }; 00345 00347 class FileLocationConverter : public Converter 00348 { 00349 public: 00350 FileLocationConverter(const Formatting& formatting) 00351 : Converter(formatting) 00352 {} 00353 00354 virtual void convert(const LogMessage &message, StringBuffer &output) const 00355 { 00356 if (message.filename != 0) 00357 { 00358 output += message.filename; 00359 } 00360 } 00361 }; 00362 00364 class FullLocationConverter : public Converter 00365 { 00366 public: 00367 FullLocationConverter(const Formatting& formatting) 00368 : Converter(formatting) 00369 {} 00370 00371 virtual void convert(const LogMessage &message, StringBuffer &output) const 00372 { 00373 if (message.filename != 0) 00374 { 00375 output += message.filename; 00376 output += '('; 00377 output += message.fileline; 00378 output += ')'; 00379 } 00380 } 00381 }; 00382 00384 class LineLocationConverter : public Converter 00385 { 00386 public: 00387 LineLocationConverter(const Formatting& formatting) 00388 : Converter(formatting) 00389 {} 00390 00391 virtual void convert(const LogMessage &message, StringBuffer &output) const 00392 { 00393 output += message.fileline; 00394 } 00395 }; 00396 00398 class MethodLocationConverter : public Converter 00399 { 00400 public: 00401 MethodLocationConverter(const Formatting& formatting) 00402 : Converter(formatting) 00403 {} 00404 00405 virtual void convert(const LogMessage &message, StringBuffer &output) const 00406 { 00407 if (message.methodname != 0) 00408 { 00409 output += message.methodname; 00410 } 00411 } 00412 }; 00413 00415 class CategoryConverter : public Converter 00416 { 00417 public: 00418 CategoryConverter(const Formatting& formatting) 00419 : Converter(formatting) 00420 {} 00421 00422 virtual void convert(const LogMessage &message, StringBuffer &output) const 00423 { 00424 output += message.category; 00425 } 00426 }; 00427 00429 class RelativeTimeConverter : public Converter 00430 { 00431 public: 00432 RelativeTimeConverter(const Formatting& formatting) 00433 : Converter(formatting) 00434 {} 00435 00436 virtual void convert(const LogMessage &message, StringBuffer &output) const 00437 { 00438 output += getRelativeTime(); 00439 } 00440 00441 private: 00442 static UInt64 getRelativeTime() 00443 { 00444 return getNowMillis() - startMillis; 00445 } 00446 00447 static UInt64 startMillis; 00448 public: 00449 static UInt64 getNowMillis() 00450 { 00451 DateTime now; 00452 now.setToCurrent(); 00453 return UInt64(now.get()) * 1000 + (now.getMicrosecond() / 1000); 00454 } 00455 }; 00456 00457 UInt64 RelativeTimeConverter::startMillis(RelativeTimeConverter::getNowMillis()); 00458 00460 enum EParserState 00461 { 00462 E_LITERAL_STATE, 00463 E_CONVERTER_STATE, 00464 E_DOT_STATE, 00465 E_MIN_STATE, 00466 E_MAX_STATE 00467 }; 00468 00470 class DateConverter : public Converter 00471 { 00472 public: 00473 DateConverter(const Formatting& formatting, const String& format) 00474 : Converter(formatting) 00475 , m_format(format) 00476 { 00477 size_t pos = m_format.indexOf("%Q"); 00478 if (pos != String::npos) 00479 { 00480 // escape the %Q, since strftime doesn't know about it. 00481 m_format = m_format.substring(0, pos) + '%' + m_format.substring(pos); 00482 } 00483 } 00484 00485 virtual void convert(const LogMessage &message, StringBuffer &output) const 00486 { 00487 char buf[255]; 00488 00489 DateTime now; 00490 now.setToCurrent(); 00491 struct tm nowTm; 00492 now.toLocal(nowTm); 00493 00494 size_t len = ::strftime(buf, sizeof(buf), m_format.c_str(), &nowTm); 00495 00496 buf[len] = '\0'; 00497 00498 // handle %Q special case 00499 char* p = strstr(buf, "%Q"); 00500 if (p != NULL) 00501 { 00502 *p = '\0'; 00503 output += buf; 00504 long deciMillis = now.getMicrosecond() / 1000; 00505 String strMillis(deciMillis); 00506 // output 3 chars 00507 switch (strMillis.length()) 00508 { 00509 case 1: 00510 output += '0'; 00511 case 2: 00512 output += '0'; 00513 } 00514 output += strMillis; 00515 output += p+2; 00516 } 00517 else 00518 { 00519 output += buf; 00520 } 00521 } 00522 00523 static const char* const ISO8601_DATE_FORMAT; 00524 static const char* const ISO8601_PATTERN; 00525 static const char* const ABSOLUTE_DATE_FORMAT; 00526 static const char* const ABSOLUTE_PATTERN; 00527 static const char* const DATE_DATE_FORMAT; 00528 static const char* const DATE_PATTERN; 00529 00530 private: 00531 String m_format; 00532 }; 00533 00534 const char* const DateConverter::ISO8601_DATE_FORMAT = "ISO8601"; 00535 const char* const DateConverter::ISO8601_PATTERN = "%Y-%m-%d %H:%M:%S,%Q"; 00536 const char* const DateConverter::ABSOLUTE_DATE_FORMAT = "ABSOLUTE"; 00537 const char* const DateConverter::ABSOLUTE_PATTERN = "%H:%M:%S,%Q"; 00538 const char* const DateConverter::DATE_DATE_FORMAT = "DATE"; 00539 const char* const DateConverter::DATE_PATTERN = "%d %b %Y %H:%M:%S,%Q"; 00540 00542 class Parser 00543 { 00544 public: 00545 Parser(const String& pattern_) 00546 : i(0) 00547 , state(E_LITERAL_STATE) 00548 , pattern(pattern_) 00549 {} 00550 00552 void parse(Array<ConverterRef>& converters) 00553 { 00554 char c; 00555 size_t patternLength(pattern.length()); 00556 00557 while (i < patternLength) 00558 { 00559 c = pattern[i]; 00560 ++i; 00561 switch (state) 00562 { 00563 case E_LITERAL_STATE: 00564 { 00565 if (i == patternLength) 00566 { 00567 literal += c; 00568 continue; 00569 } 00570 // handle %% -> % and %n -> \n or move to the CONVERTER_STATE 00571 else if (c == '%') 00572 { 00573 switch (pattern[i]) 00574 { 00575 case '%': 00576 literal += c; 00577 ++i; 00578 break; 00579 case 'n': 00580 literal += '\n'; 00581 ++i; 00582 break; 00583 default: 00584 if (literal.length() > 0) 00585 { 00586 converters.push_back(ConverterRef(new LiteralConverter(literal.toString()))); 00587 literal.reset(); 00588 } 00589 literal += c; 00590 state = E_CONVERTER_STATE; 00591 formatting = Formatting(); 00592 } 00593 } 00594 // handle \n, \\, \r, \t, \x<hexDigits> 00595 else if (c == '\\') 00596 { 00597 switch (pattern[i]) 00598 { 00599 case 'n': 00600 literal += '\n'; 00601 ++i; 00602 break; 00603 00604 case '\\': 00605 literal += '\\'; 00606 ++i; 00607 break; 00608 00609 case 'r': 00610 literal += '\r'; 00611 ++i; 00612 break; 00613 00614 case 't': 00615 literal += '\t'; 00616 ++i; 00617 break; 00618 00619 case 'x': 00620 { 00621 if (i + 1 > patternLength) 00622 { 00623 literal += "\\x"; 00624 ++i; 00625 break; 00626 } 00627 00628 char* begin = &pattern[i+1]; 00629 char* end(0); 00630 errno = 0; 00631 int hexNumber = std::strtol(begin, &end, 16); 00632 if (end == begin || errno == ERANGE || hexNumber > CHAR_MAX) 00633 { 00634 literal += "\\x"; 00635 ++i; 00636 break; 00637 } 00638 literal += static_cast<char>(hexNumber); 00639 i += (end - begin) + 1; 00640 } 00641 break; 00642 00643 default: 00644 literal += '\\'; 00645 break; 00646 } 00647 } 00648 else 00649 { 00650 literal += c; 00651 } 00652 } 00653 break; 00654 // handle converter stuff after a % 00655 case E_CONVERTER_STATE: 00656 { 00657 literal += c; 00658 switch (c) 00659 { 00660 case '-': 00661 formatting.justification = E_LEFT_JUSTIFY; 00662 break; 00663 case '.': 00664 state = E_DOT_STATE; 00665 break; 00666 default: 00667 if (isdigit(c)) 00668 { 00669 formatting.minWidth = c - '0'; 00670 state = E_MIN_STATE; 00671 } 00672 else 00673 { 00674 converters.push_back(finalizeConverter(c)); 00675 } 00676 } 00677 } 00678 break; 00679 case E_MIN_STATE: 00680 { 00681 literal += c; 00682 if (isdigit(c)) 00683 { 00684 formatting.minWidth = formatting.minWidth * 10 + (c - '0'); 00685 } 00686 else if (c == '.') 00687 { 00688 state = E_DOT_STATE; 00689 } 00690 else 00691 { 00692 converters.push_back(finalizeConverter(c)); 00693 } 00694 } 00695 break; 00696 case E_DOT_STATE: 00697 { 00698 literal += c; 00699 if (isdigit(c)) 00700 { 00701 formatting.maxWidth = c - '0'; 00702 state = E_MAX_STATE; 00703 } 00704 else 00705 { 00706 BLOCXX_THROW_ERR(LogMessagePatternFormatterException, 00707 Format("Invalid pattern \"%1\" in position %2. Was expecting a digit, instead got char %3.", 00708 pattern, i, c).c_str(), 00709 LogMessagePatternFormatter::E_INVALID_PATTERN_NO_DIGIT_AFTER_DOT); 00710 } 00711 } 00712 break; 00713 case E_MAX_STATE: 00714 { 00715 literal += c; 00716 if (isdigit(c)) 00717 { 00718 formatting.maxWidth = formatting.maxWidth * 10 + (c - '0'); 00719 } 00720 else 00721 { 00722 converters.push_back(finalizeConverter(c)); 00723 state = E_LITERAL_STATE; 00724 } 00725 } 00726 break; 00727 } // switch 00728 } // while 00729 00730 // hanlde whatever is left 00731 if (literal.length() > 0) 00732 { 00733 converters.push_back(ConverterRef(new LiteralConverter(literal.toString()))); 00734 } 00735 } 00736 00738 String getOption() 00739 { 00740 // retrieves the contents of a { }, like in a %d{ISO8601} 00741 if ((i < pattern.length()) && (pattern[i] == '{')) 00742 { 00743 size_t end = pattern.indexOf('}', i); 00744 if (end > i) 00745 { 00746 String rv = pattern.substring(i + 1, end - (i + 1)); 00747 i = end + 1; 00748 return rv; 00749 } 00750 } 00751 00752 return String(); 00753 } 00754 00756 int getPrecision() 00757 { 00758 // retrieves the numeric contents of a { }, like in a %c{2} 00759 String opt = getOption(); 00760 int rv = 0; 00761 if (!opt.empty()) 00762 { 00763 try 00764 { 00765 rv = opt.toUInt32(); 00766 } 00767 catch (StringConversionException& e) 00768 { 00769 BLOCXX_THROW_ERR(LogMessagePatternFormatterException, 00770 Format("Invalid pattern \"%1\" in position %2. A positive integer is required for precision option (%3).", 00771 pattern, i, opt).c_str(), 00772 LogMessagePatternFormatter::E_INVALID_PATTERN_PRECISION_NOT_AN_INTEGER); 00773 } 00774 } 00775 return rv; 00776 } 00777 00779 ConverterRef finalizeConverter(char c) 00780 { 00781 // handle the actual type of converter 00782 ConverterRef rv; 00783 switch (c) 00784 { 00785 case 'c': 00786 { 00787 rv = new ComponentConverter(formatting, getPrecision()); 00788 } 00789 break; 00790 00791 case 'd': 00792 { 00793 String dateFormat; 00794 String dateOpt = getOption(); 00795 if (dateOpt.empty()) 00796 { 00797 dateFormat = DateConverter::ISO8601_DATE_FORMAT; 00798 } 00799 else 00800 { 00801 dateFormat = dateOpt; 00802 } 00803 00804 // take care of the predefined date formats 00805 if (dateFormat.equalsIgnoreCase(DateConverter::ISO8601_DATE_FORMAT)) 00806 { 00807 dateFormat = DateConverter::ISO8601_PATTERN; 00808 } 00809 else if (dateFormat.equalsIgnoreCase(DateConverter::ABSOLUTE_DATE_FORMAT)) 00810 { 00811 dateFormat = DateConverter::ABSOLUTE_PATTERN; 00812 } 00813 else if (dateFormat.equalsIgnoreCase(DateConverter::DATE_DATE_FORMAT)) 00814 { 00815 dateFormat = DateConverter::DATE_PATTERN; 00816 } 00817 00818 rv = new DateConverter(formatting, dateFormat); 00819 } 00820 break; 00821 00822 case 'F': 00823 { 00824 rv = new FileLocationConverter(formatting); 00825 } 00826 break; 00827 00828 case 'l': 00829 { 00830 rv = new FullLocationConverter(formatting); 00831 } 00832 break; 00833 00834 case 'L': 00835 { 00836 rv = new LineLocationConverter(formatting); 00837 } 00838 break; 00839 00840 case 'M': 00841 { 00842 rv = new MethodLocationConverter(formatting); 00843 } 00844 break; 00845 00846 case 'm': 00847 { 00848 rv = new MessageConverter(formatting); 00849 } 00850 break; 00851 00852 case 'e': 00853 { 00854 rv = new XMLMessageConverter(formatting); 00855 } 00856 break; 00857 00858 case 'p': 00859 { 00860 rv = new CategoryConverter(formatting); 00861 } 00862 break; 00863 00864 case 'r': 00865 { 00866 rv = new RelativeTimeConverter(formatting); 00867 } 00868 break; 00869 00870 case 't': 00871 { 00872 rv = new ThreadConverter(formatting); 00873 } 00874 break; 00875 00876 case 'P': 00877 { 00878 rv = new PidConverter(formatting); 00879 } 00880 break; 00881 #if 0 // don't support these for now. 00882 case 'x': 00883 { 00884 00885 } 00886 break; 00887 00888 case 'X': 00889 { 00890 00891 } 00892 break; 00893 #endif 00894 default: 00895 { 00896 BLOCXX_THROW_ERR(LogMessagePatternFormatterException, 00897 Format("Invalid pattern \"%1\" in position %2. Unsupported conversion (%3).", 00898 pattern, i, c).c_str(), 00899 LogMessagePatternFormatter::E_INVALID_PATTERN_UNSUPPORTED_CONVERSION); 00900 00901 } 00902 break; 00903 } 00904 00905 literal.reset(); 00906 state = E_LITERAL_STATE; 00907 formatting = Formatting(); 00908 return rv; 00909 } 00910 00911 private: 00912 size_t i; 00913 EParserState state; 00914 StringBuffer literal; 00915 Formatting formatting; 00916 String pattern; 00917 }; 00918 00919 00920 } // end unnamed namespace 00921 00923 LogMessagePatternFormatter::LogMessagePatternFormatter(const String& pattern) 00924 { 00925 Parser parser(pattern); 00926 parser.parse(m_patternConverters); 00927 } 00928 00929 } // end namespace BLOCXX_NAMESPACE 00930 00931 00932 00933 00934