OW_LogMessagePatternFormatter.cpp

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

Generated on Thu Feb 9 08:48:03 2006 for openwbem by  doxygen 1.4.6