blocxx

LogMessagePatternFormatter.cpp

Go to the documentation of this file.
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 "]]&gt;"
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