00001
00002
00003
00004
00005
00006
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
00037
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
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
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 }