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                         // want milliseconds?
00144             std::string::size_type pos = timeFormat.find("%l");
00145             if (pos == std::string::npos) {
00146 
00147                                 // want microseconds?
00148                                 std::string::size_type pos = timeFormat.find("%L");
00149                                 if (pos == std::string::npos) {
00150                                         _printMillis = false;
00151                                         _printMicros = false;
00152                                         _timeFormat1 = timeFormat;
00153                                 } else {
00154                                         _printMillis = false;
00155                                         _printMicros = true;
00156                                         _timeFormat1 = timeFormat.substr(0, pos);
00157                                         _timeFormat2 = timeFormat.substr(pos + 2);
00158                                 }
00159 
00160             } else {
00161                 _printMillis = true;
00162                                 _printMicros = false;
00163                 _timeFormat1 = timeFormat.substr(0, pos);
00164                 _timeFormat2 = timeFormat.substr(pos + 2);
00165             }
00166         }
00167 
00168         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00169             struct std::tm currentTime;
00170             std::time_t t = event.timeStamp.getSeconds();
00171             localtime(&t, &currentTime);
00172             char formatted[103];
00173             std::string timeFormat;
00174             if (_printMillis) {
00175                 std::ostringstream formatStream;
00176                 formatStream << _timeFormat1 
00177                              << std::setw(3) << std::setfill('0')
00178                              << event.timeStamp.getMilliSeconds()
00179                              << _timeFormat2;
00180                 timeFormat = formatStream.str();
00181                         } else if (_printMicros) {
00182                 std::ostringstream formatStream;
00183                 formatStream << _timeFormat1
00184                              << std::setw(6) << std::setfill('0')
00185                              << event.timeStamp.getMicroSeconds()
00186                              << _timeFormat2;
00187                 timeFormat = formatStream.str();
00188             } else {
00189                 timeFormat = _timeFormat1;
00190             }
00191             std::strftime(formatted, sizeof(formatted), timeFormat.c_str(), &currentTime);
00192             out << formatted;
00193         }
00194 
00195         private:
00196         std::string _timeFormat1;
00197         std::string _timeFormat2;
00198         bool _printMillis;
00199         bool _printMicros;
00200     };
00201 
00202     const char* const TimeStampComponent::FORMAT_ISO8601 = "%Y-%m-%d %H:%M:%S,%l";
00203     const char* const TimeStampComponent::FORMAT_ABSOLUTE = "%H:%M:%S,%l";
00204     const char* const TimeStampComponent::FORMAT_DATE = "%d %b %Y %H:%M:%S,%l";
00205 
00206     struct SecondsSinceEpochComponent : public PatternLayout::PatternComponent {
00207         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00208             out << event.timeStamp.getSeconds();
00209         }
00210     };
00211 
00212     struct MillisSinceEpochComponent : public PatternLayout::PatternComponent {
00213         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00214 #ifdef LOG4CPP_HAVE_INT64_T
00215             int64_t t = event.timeStamp.getSeconds() -
00216                 TimeStamp::getStartTime().getSeconds();
00217             t *= 1000;
00218             t += event.timeStamp.getMilliSeconds() -
00219                 TimeStamp::getStartTime().getMilliSeconds();
00220             
00221             out << t;
00222 #else
00223             double t = event.timeStamp.getSeconds() -
00224                 TimeStamp::getStartTime().getSeconds();
00225             t *= 1000;
00226             t += event.timeStamp.getMilliSeconds() -
00227                 TimeStamp::getStartTime().getMilliSeconds();
00228             
00229             out << std::setiosflags(std::ios::fixed)
00230                 << std::setprecision(0) << t;
00231 #endif
00232         }
00233     };
00234 
00235     struct FormatModifierComponent : public PatternLayout::PatternComponent {
00236         FormatModifierComponent(PatternLayout::PatternComponent* component,
00237                                 size_t minWidth, size_t maxWidth, bool alignLeft) :
00238             _component(component) , 
00239             _minWidth(minWidth),
00240             _maxWidth(maxWidth),
00241             _alignLeft(alignLeft) {
00242         }
00243 
00244         virtual ~FormatModifierComponent() {
00245             delete _component;
00246         }
00247 
00248         virtual void append(std::ostringstream& out, const LoggingEvent& event) {
00249             std::ostringstream s;
00250             _component->append(s, event);
00251             std::string msg = s.str();
00252             if (_maxWidth > 0 && _maxWidth < msg.length()) {
00253                 msg.erase(_maxWidth);
00254             }
00255             size_t fillCount = _minWidth - msg.length();
00256             if (_minWidth > msg.length()) {
00257                 if (_alignLeft) {
00258                     out << msg << std::string(fillCount, ' ');
00259                 } else {
00260                     out << std::string(fillCount, ' ') << msg;
00261                 }
00262             } else {
00263                 out << msg;
00264             }
00265         }
00266 
00267         private:
00268         PatternLayout::PatternComponent* _component;
00269         size_t _minWidth;
00270         size_t _maxWidth;
00271         bool _alignLeft;
00272     };
00273 
00274     const char* PatternLayout::DEFAULT_CONVERSION_PATTERN = "%m%n";
00275     const char* PatternLayout::SIMPLE_CONVERSION_PATTERN = "%p - %m%n";
00276     const char* PatternLayout::BASIC_CONVERSION_PATTERN = "%R %p %c %x: %m%n";
00277     const char* PatternLayout::TTCC_CONVERSION_PATTERN = "%r [%t] %p %c %x - %m%n";
00278 
00279     PatternLayout::PatternLayout() {
00280         try {
00281             setConversionPattern(DEFAULT_CONVERSION_PATTERN);
00282         } catch(ConfigureFailure&) {
00283         }
00284     }
00285 
00286     PatternLayout::~PatternLayout() {
00287         clearConversionPattern();
00288     }
00289 
00290     void PatternLayout::clearConversionPattern() {
00291         for(ComponentVector::const_iterator i = _components.begin();
00292             i != _components.end(); ++i) {
00293             delete (*i);
00294         }
00295         _components.clear();
00296         _conversionPattern = "";
00297     }
00298 
00299     void PatternLayout::setConversionPattern(const std::string& conversionPattern) throw(ConfigureFailure) {
00300 #ifdef LOG4CPP_HAVE_SSTREAM 
00301         std::istringstream conversionStream(conversionPattern);
00302 #else
00303         std::istrstream conversionStream(conversionPattern.c_str());
00304 #endif
00305         std::string literal;
00306 
00307         char ch;
00308         PatternLayout::PatternComponent* component = NULL;
00309         int minWidth = 0;
00310         size_t maxWidth = 0;
00311         clearConversionPattern();
00312         while (conversionStream.get(ch)) {
00313             if (ch == '%') {
00314                 // readPrefix;
00315                 {
00316                     char ch2;
00317                     conversionStream.get(ch2);
00318                     if ((ch2 == '-') || ((ch2 >= '0') && (ch2 <= '9'))) {
00319                         conversionStream.putback(ch2);
00320                         conversionStream >> minWidth;
00321                         conversionStream.get(ch2);
00322                     } 
00323                     if (ch2 == '.') {
00324                         conversionStream >> maxWidth;
00325                     } else {
00326                         conversionStream.putback(ch2);
00327                     }                        
00328                 }
00329                 if (!conversionStream.get(ch)) {
00330                     std::ostringstream msg;
00331                     msg << "unterminated conversion specifier in '" << conversionPattern << "' at index " << conversionStream.tellg();
00332                     throw ConfigureFailure(msg.str());
00333                 }
00334                 std::string specPostfix = "";
00335                 // read postfix
00336                 {
00337                     char ch2;
00338                     if (conversionStream.get(ch2)) {
00339                         if (ch2 == '{') {
00340                             while(conversionStream.get(ch2) && (ch2 != '}'))
00341                                 specPostfix += ch2;
00342                         } else {
00343                             conversionStream.putback(ch2);
00344                         }
00345                     }
00346                 }
00347                 switch (ch) {
00348                 case '%':
00349                     literal += ch;
00350                     break;
00351                 case 'm':
00352                     component = new MessageComponent();
00353                     break;
00354                 case 'n':
00355                     {
00356                         std::ostringstream endline;
00357                         endline << std::endl;
00358                         literal += endline.str();
00359                     }
00360                     break;
00361                 case 'c':
00362                     component = new CategoryNameComponent(specPostfix);
00363                     break;
00364                 case 'd':
00365                     component = new TimeStampComponent(specPostfix);
00366                     break;
00367                 case 'p':
00368                     component = new PriorityComponent();
00369                     break;
00370                 case 'r':
00371                     component = new MillisSinceEpochComponent();
00372                     break;
00373                 case 'R':
00374                     component = new SecondsSinceEpochComponent();
00375                     break;
00376                 case 't':
00377                     component = new ThreadNameComponent();
00378                     break;
00379                 case 'u':
00380                     component = new ProcessorTimeComponent();
00381                     break;
00382                 case 'x':
00383                     component = new NDCComponent();
00384                     break;
00385                 default:
00386                     std::ostringstream msg;
00387                     msg << "unknown conversion specifier '" << ch << "' in '" << conversionPattern << "' at index " << conversionStream.tellg();
00388                     throw ConfigureFailure(msg.str());                    
00389                 }
00390                 if (component) {
00391                     if (!literal.empty()) {
00392                         _components.push_back(new StringLiteralComponent(literal));
00393                         literal = "";
00394                     }
00395                     if ((minWidth != 0) || (maxWidth != 0)) {
00396                         component = new FormatModifierComponent(component, ::abs(minWidth), maxWidth, minWidth < 0);
00397                         minWidth = maxWidth = 0;
00398                     }
00399                     _components.push_back(component);
00400                     component = NULL;
00401                 }
00402             } else {
00403                 literal += ch;
00404             }
00405         }
00406         if (!literal.empty()) {
00407             _components.push_back(new StringLiteralComponent(literal));
00408         }
00409 
00410         _conversionPattern = conversionPattern;
00411     }
00412 
00413     std::string PatternLayout::getConversionPattern() const {
00414         return _conversionPattern;
00415     }
00416 
00417     std::string PatternLayout::format(const LoggingEvent& event) {
00418         std::ostringstream message;
00419 
00420         for(ComponentVector::const_iterator i = _components.begin();
00421             i != _components.end(); ++i) {
00422             (*i)->append(message, event);
00423         }
00424 
00425         return message.str();
00426     }
00427 
00428     std::auto_ptr<Layout> create_pattern_layout(const FactoryParams& params)
00429     {
00430        std::string pattern;
00431        params.get_for("pattern layout").optional("pattern", pattern);
00432        std::auto_ptr<Layout> result(new PatternLayout);
00433        PatternLayout* l = static_cast<PatternLayout*>(result.get());
00434        if (pattern.empty() || pattern == "default")
00435           return result;
00436 
00437        if (pattern == "simple")
00438        {
00439           l->setConversionPattern(PatternLayout::SIMPLE_CONVERSION_PATTERN);
00440           return result;
00441        }
00442 
00443        if (pattern == "basic")
00444        {
00445           l->setConversionPattern(PatternLayout::BASIC_CONVERSION_PATTERN);
00446           return result;
00447        }
00448 
00449        if (pattern == "ttcc")
00450        {
00451           l->setConversionPattern(PatternLayout::TTCC_CONVERSION_PATTERN);
00452           return result;
00453        }
00454        
00455        l->setConversionPattern(pattern);
00456        return result;
00457    }
00458 }


log4cpp
Author(s): Stephen Roderick, Bastiaan Bakker, Cedric Le Goater, Steve Ostlind, Marcel Harkema, Walter Stroebel, Glenn Scott and Tony Cheung.
autogenerated on Wed Sep 16 2015 10:27:14