$search
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, ¤tTime); 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(), ¤tTime); 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 }