LogMessagePatternFormatter.cpp

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

Generated on Fri Jun 16 15:39:08 2006 for blocxx by  doxygen 1.4.6