PatternLayout.cpp
Go to the documentation of this file.
00001 /*
00002  * PatternLayout.cpp
00003  *
00004  * Copyright 2002, Bastiaan Bakker. All rights reserved.
00005  *
00006  * See the COPYING file for the terms of usage and distribution.
00007  */
00008 
00009 #include "PortabilityImpl.hh"
00010 
00011 #include <log4cpp/PatternLayout.hh>
00012 #include <log4cpp/Priority.hh>
00013 #include <log4cpp/NDC.hh>
00014 #include <log4cpp/TimeStamp.hh>
00015 #include <log4cpp/FactoryParams.hh>
00016 #include <memory>
00017 #include <stdlib.h>
00018 
00019 #ifdef LOG4CPP_HAVE_SSTREAM
00020 #include <sstream>
00021 #else
00022 #include <strstream>
00023 #endif
00024 
00025 #include <iomanip>
00026 #include <ctime>
00027 #include <cmath>
00028 #include "Localtime.hh"
00029 
00030 #ifdef LOG4CPP_HAVE_INT64_T
00031 #ifdef LOG4CPP_HAVE_STDINT_H
00032 #include <stdint.h>
00033 #endif // LOG4CPP_HAVE_STDINT_H
00034 
00035 #ifdef LOG4CPP_MISSING_INT64_OSTREAM_OP
00036 /* workaround suggested at:
00037    http://support.microsoft.com/default.aspx?scid=kb;EN-US;q168440
00038 */
00039 
00040 #include <stdio.h>
00041  
00042 std::ostream& operator<<(std::ostream& os, int64_t i) {
00043     char buf[20];
00044     ::sprintf(buf,"%I64d", i);
00045     return os << buf;
00046 }
00047 #endif // LOG4CPP_MISSING_INT64_OSTREAM_OP
00048 #endif // LOG4CPP_HAVE_INT64_T
00049 
00050 namespace log4cpp {
00051 
00052     struct StringLiteralComponent : public PatternLayout::PatternComponent {
00053         StringLiteralComponent(const std::string& literal) :
00054             _literal(literal) {
00055         }
00056 
00057         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00058             out << _literal;
00059         }
00060 
00061         private:
00062         std::string _literal;
00063     };
00064 
00065     struct CategoryNameComponent : public PatternLayout::PatternComponent {
00066         CategoryNameComponent(std::string specifier) {
00067             if (specifier == "") {
00068                 _precision = -1;
00069             } else {
00070 #ifdef LOG4CPP_HAVE_SSTREAM 
00071                 std::istringstream s(specifier);
00072 #else
00073                 std::istrstream s(specifier.c_str());
00074 #endif
00075                 s >> _precision;
00076             }
00077         }
00078 
00079         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00080             if (_precision == -1) {
00081                 out << event.categoryName;
00082             } else {
00083                 std::string::size_type begin = std::string::npos;
00084                 for(int i = 0; i < _precision; i++) {
00085                     begin = event.categoryName.rfind('.', begin - 2);
00086                     if (begin == std::string::npos) {
00087                         begin = 0;
00088                         break;
00089                     }
00090                     begin++;
00091                 }
00092                 out << event.categoryName.substr(begin);
00093             }
00094         }
00095 
00096         private:
00097         int _precision;
00098     };
00099 
00100     struct MessageComponent : public PatternLayout::PatternComponent {
00101         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00102             out << event.message;
00103         }
00104     };
00105 
00106     struct NDCComponent : public PatternLayout::PatternComponent {
00107         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00108             out << event.ndc;
00109         }
00110     };
00111 
00112     struct PriorityComponent : public PatternLayout::PatternComponent {
00113         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00114             out << Priority::getPriorityName(event.priority);
00115         }
00116     };
00117 
00118     struct ThreadNameComponent : public PatternLayout::PatternComponent {
00119         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00120             out << event.threadName;
00121         }
00122     };
00123 
00124     struct ProcessorTimeComponent : public PatternLayout::PatternComponent {
00125         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00126             out << std::clock();
00127         }
00128     };
00129 
00130     struct TimeStampComponent : public PatternLayout::PatternComponent {
00131         static const char* const FORMAT_ISO8601;
00132         static const char* const FORMAT_ABSOLUTE;
00133         static const char* const FORMAT_DATE;
00134 
00135         TimeStampComponent(std::string timeFormat) {
00136             if ((timeFormat == "") || (timeFormat == "ISO8601")) {
00137                 timeFormat = FORMAT_ISO8601;
00138             } else if (timeFormat == "ABSOLUTE") {
00139                 timeFormat = FORMAT_ABSOLUTE;
00140             } else if (timeFormat == "DATE") {
00141                 timeFormat = FORMAT_DATE;
00142             }
00143             std::string::size_type pos = timeFormat.find("%l");
00144             if (pos == std::string::npos) {
00145                 _printMillis = false;
00146                 _timeFormat1 = timeFormat; 
00147             } else {
00148                 _printMillis = true;
00149                 _timeFormat1 = timeFormat.substr(0, pos);
00150                 _timeFormat2 = timeFormat.substr(pos + 2);
00151             }
00152         }
00153 
00154         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00155             struct std::tm currentTime;
00156             std::time_t t = event.timeStamp.getSeconds();
00157             localtime(&t, &currentTime);
00158             char formatted[100];
00159             std::string timeFormat;
00160             if (_printMillis) {
00161                 std::ostringstream formatStream;
00162                 formatStream << _timeFormat1 
00163                              << std::setw(3) << std::setfill('0')
00164                              << event.timeStamp.getMilliSeconds()
00165                              << _timeFormat2;
00166                 timeFormat = formatStream.str();
00167             } else {
00168                 timeFormat = _timeFormat1;
00169             }
00170             std::strftime(formatted, sizeof(formatted), timeFormat.c_str(), &currentTime);
00171             out << formatted;
00172         }
00173 
00174         private:
00175         std::string _timeFormat1;
00176         std::string _timeFormat2;
00177         bool _printMillis;
00178     };
00179 
00180     const char* const TimeStampComponent::FORMAT_ISO8601 = "%Y-%m-%d %H:%M:%S,%l";
00181     const char* const TimeStampComponent::FORMAT_ABSOLUTE = "%H:%M:%S,%l";
00182     const char* const TimeStampComponent::FORMAT_DATE = "%d %b %Y %H:%M:%S,%l";
00183 
00184     struct SecondsSinceEpochComponent : public PatternLayout::PatternComponent {
00185         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00186             out << event.timeStamp.getSeconds();
00187         }
00188     };
00189 
00190     struct MillisSinceEpochComponent : public PatternLayout::PatternComponent {
00191         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00192 #ifdef LOG4CPP_HAVE_INT64_T
00193             int64_t t = event.timeStamp.getSeconds() -
00194                 TimeStamp::getStartTime().getSeconds();
00195             t *= 1000;
00196             t += event.timeStamp.getMilliSeconds() -
00197                 TimeStamp::getStartTime().getMilliSeconds();
00198             
00199             out << t;
00200 #else
00201             double t = event.timeStamp.getSeconds() -
00202                 TimeStamp::getStartTime().getSeconds();
00203             t *= 1000;
00204             t += event.timeStamp.getMilliSeconds() -
00205                 TimeStamp::getStartTime().getMilliSeconds();
00206             
00207             out << std::setiosflags(std::ios::fixed)
00208                 << std::setprecision(0) << t;
00209 #endif
00210         }
00211     };
00212 
00213     struct FormatModifierComponent : public PatternLayout::PatternComponent {
00214         FormatModifierComponent(PatternLayout::PatternComponent* component,
00215                                 size_t minWidth, size_t maxWidth, bool alignLeft) :
00216             _component(component) , 
00217             _minWidth(minWidth),
00218             _maxWidth(maxWidth),
00219             _alignLeft(alignLeft) {
00220         }
00221 
00222         virtual ~FormatModifierComponent() {
00223             delete _component;
00224         }
00225 
00226         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00227             std::ostringstream s;
00228             _component->append(s, event);
00229             std::string msg = s.str();
00230             if (_maxWidth > 0 && _maxWidth < msg.length()) {
00231                 msg.erase(_maxWidth);
00232             }
00233             size_t fillCount = _minWidth - msg.length();
00234             if (_minWidth > msg.length()) {
00235                 if (_alignLeft) {
00236                     out << msg << std::string(fillCount, ' ');
00237                 } else {
00238                     out << std::string(fillCount, ' ') << msg;
00239                 }
00240             } else {
00241                 out << msg;
00242             }
00243         }
00244 
00245         private:
00246         PatternLayout::PatternComponent* _component;
00247         size_t _minWidth;
00248         size_t _maxWidth;
00249         bool _alignLeft;
00250     };
00251 
00252     const char* PatternLayout::DEFAULT_CONVERSION_PATTERN = "%m%n";
00253     const char* PatternLayout::SIMPLE_CONVERSION_PATTERN = "%p - %m%n";
00254     const char* PatternLayout::BASIC_CONVERSION_PATTERN = "%R %p %c %x: %m%n";
00255     const char* PatternLayout::TTCC_CONVERSION_PATTERN = "%r [%t] %p %c %x - %m%n";
00256 
00257     PatternLayout::PatternLayout() {
00258         try {
00259             setConversionPattern(DEFAULT_CONVERSION_PATTERN);
00260         } catch(ConfigureFailure&) {
00261         }
00262     }
00263 
00264     PatternLayout::~PatternLayout() {
00265         clearConversionPattern();
00266     }
00267 
00268     void PatternLayout::clearConversionPattern() {
00269         for(ComponentVector::const_iterator i = _components.begin();
00270             i != _components.end(); ++i) {
00271             delete (*i);
00272         }
00273         _components.clear();
00274         _conversionPattern = "";
00275     }
00276 
00277     void PatternLayout::setConversionPattern(const std::string& conversionPattern) throw(ConfigureFailure) {
00278 #ifdef LOG4CPP_HAVE_SSTREAM 
00279         std::istringstream conversionStream(conversionPattern);
00280 #else
00281         std::istrstream conversionStream(conversionPattern.c_str());
00282 #endif
00283         std::string literal;
00284 
00285         char ch;
00286         PatternLayout::PatternComponent* component = NULL;
00287         int minWidth = 0;
00288         size_t maxWidth = 0;
00289         clearConversionPattern();
00290         while (conversionStream.get(ch)) {
00291             if (ch == '%') {
00292                 // readPrefix;
00293                 {
00294                     char ch2;
00295                     conversionStream.get(ch2);
00296                     if ((ch2 == '-') || ((ch2 >= '0') && (ch2 <= '9'))) {
00297                         conversionStream.putback(ch2);
00298                         conversionStream >> minWidth;
00299                         conversionStream.get(ch2);
00300                     } 
00301                     if (ch2 == '.') {
00302                         conversionStream >> maxWidth;
00303                     } else {
00304                         conversionStream.putback(ch2);
00305                     }                        
00306                 }
00307                 if (!conversionStream.get(ch)) {
00308                     std::ostringstream msg;
00309                     msg << "unterminated conversion specifier in '" << conversionPattern << "' at index " << conversionStream.tellg();
00310                     throw ConfigureFailure(msg.str());
00311                 }
00312                 std::string specPostfix = "";
00313                 // read postfix
00314                 {
00315                     char ch2;
00316                     if (conversionStream.get(ch2)) {
00317                         if (ch2 == '{') {
00318                             while(conversionStream.get(ch2) && (ch2 != '}'))
00319                                 specPostfix += ch2;
00320                         } else {
00321                             conversionStream.putback(ch2);
00322                         }
00323                     }
00324                 }
00325                 switch (ch) {
00326                 case '%':
00327                     literal += ch;
00328                     break;
00329                 case 'm':
00330                     component = new MessageComponent();
00331                     break;
00332                 case 'n':
00333                     {
00334                         std::ostringstream endline;
00335                         endline << std::endl;
00336                         literal += endline.str();
00337                     }
00338                     break;
00339                 case 'c':
00340                     component = new CategoryNameComponent(specPostfix);
00341                     break;
00342                 case 'd':
00343                     component = new TimeStampComponent(specPostfix);
00344                     break;
00345                 case 'p':
00346                     component = new PriorityComponent();
00347                     break;
00348                 case 'r':
00349                     component = new MillisSinceEpochComponent();
00350                     break;
00351                 case 'R':
00352                     component = new SecondsSinceEpochComponent();
00353                     break;
00354                 case 't':
00355                     component = new ThreadNameComponent();
00356                     break;
00357                 case 'u':
00358                     component = new ProcessorTimeComponent();
00359                     break;
00360                 case 'x':
00361                     component = new NDCComponent();
00362                     break;
00363                 default:
00364                     std::ostringstream msg;
00365                     msg << "unknown conversion specifier '" << ch << "' in '" << conversionPattern << "' at index " << conversionStream.tellg();
00366                     throw ConfigureFailure(msg.str());                    
00367                 }
00368                 if (component) {
00369                     if (!literal.empty()) {
00370                         _components.push_back(new StringLiteralComponent(literal));
00371                         literal = "";
00372                     }
00373                     if ((minWidth != 0) || (maxWidth != 0)) {
00374                         component = new FormatModifierComponent(component, ::abs(minWidth), maxWidth, minWidth < 0);
00375                         minWidth = maxWidth = 0;
00376                     }
00377                     _components.push_back(component);
00378                     component = NULL;
00379                 }
00380             } else {
00381                 literal += ch;
00382             }
00383         }
00384         if (!literal.empty()) {
00385             _components.push_back(new StringLiteralComponent(literal));
00386         }
00387 
00388         _conversionPattern = conversionPattern;
00389     }
00390 
00391     std::string PatternLayout::getConversionPattern() const {
00392         return _conversionPattern;
00393     }
00394 
00395     std::string PatternLayout::format(const LoggingEvent& event) {
00396         std::ostringstream message;
00397 
00398         for(ComponentVector::const_iterator i = _components.begin();
00399             i != _components.end(); ++i) {
00400             (*i)->append(message, event);
00401         }
00402 
00403         return message.str();
00404     }
00405 
00406     std::auto_ptr<Layout> create_pattern_layout(const FactoryParams& params)
00407     {
00408        std::string pattern;
00409        params.get_for("pattern layout").optional("pattern", pattern);
00410        std::auto_ptr<Layout> result(new PatternLayout);
00411        PatternLayout* l = static_cast<PatternLayout*>(result.get());
00412        if (pattern.empty() || pattern == "default")
00413           return result;
00414 
00415        if (pattern == "simple")
00416        {
00417           l->setConversionPattern(PatternLayout::SIMPLE_CONVERSION_PATTERN);
00418           return result;
00419        }
00420 
00421        if (pattern == "basic")
00422        {
00423           l->setConversionPattern(PatternLayout::BASIC_CONVERSION_PATTERN);
00424           return result;
00425        }
00426 
00427        if (pattern == "ttcc")
00428        {
00429           l->setConversionPattern(PatternLayout::TTCC_CONVERSION_PATTERN);
00430           return result;
00431        }
00432        
00433        l->setConversionPattern(pattern);
00434        return result;
00435    }
00436 }


log4cpp
Author(s): Stephen Roderick, Bastiaan Bakker, Cedric Le Goater, Steve Ostlind, Marcel Harkema, Walter Stroebel, Glenn Scott and Tony Cheung.
autogenerated on Thu Jan 2 2014 11:35:02