~ubuntu-branches/ubuntu/trusty/log4shib/trusty

« back to all changes in this revision

Viewing changes to src/PatternLayout.cpp

  • Committer: Package Import Robot
  • Author(s): Russ Allbery
  • Date: 2012-06-05 21:20:25 UTC
  • Revision ID: package-import@ubuntu.com-20120605212025-uyigtav7dqwvnf41
Tags: upstream-1.0.4
ImportĀ upstreamĀ versionĀ 1.0.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * PatternLayout.cpp
 
3
 *
 
4
 * Copyright 2002, Bastiaan Bakker. All rights reserved.
 
5
 *
 
6
 * See the COPYING file for the terms of usage and distribution.
 
7
 */
 
8
 
 
9
#include "PortabilityImpl.hh"
 
10
 
 
11
#include <log4shib/PatternLayout.hh>
 
12
#include <log4shib/Priority.hh>
 
13
#include <log4shib/NDC.hh>
 
14
#include <log4shib/TimeStamp.hh>
 
15
 
 
16
#ifdef LOG4SHIB_HAVE_SSTREAM
 
17
#include <sstream>
 
18
#else
 
19
#include <strstream>
 
20
#endif
 
21
 
 
22
#include <cstdlib>
 
23
#include <iomanip>
 
24
#include <ctime>
 
25
#include <cmath>
 
26
 
 
27
#ifdef LOG4SHIB_HAVE_INT64_T
 
28
#ifdef LOG4SHIB_HAVE_STDINT_H
 
29
#include <stdint.h>
 
30
#endif // LOG4SHIB_HAVE_STDINT_H
 
31
 
 
32
#ifdef LOG4SHIB_MISSING_INT64_OSTREAM_OP
 
33
/* workaround suggested at:
 
34
   http://support.microsoft.com/default.aspx?scid=kb;EN-US;q168440
 
35
*/
 
36
 
 
37
#include <stdio.h>
 
38
 
 
39
std::ostream& operator<<(std::ostream& os, int64_t i) {
 
40
    char buf[20];
 
41
    ::sprintf(buf,"%I64d", i);
 
42
    return os << buf;
 
43
}
 
44
#endif // LOG4SHIB_MISSING_INT64_OSTREAM_OP
 
45
#endif // LOG4SHIB_HAVE_INT64_T
 
46
 
 
47
namespace log4shib {
 
48
 
 
49
    struct StringLiteralComponent : public PatternLayout::PatternComponent {
 
50
        StringLiteralComponent(const std::string& literal) :
 
51
            _literal(literal) {
 
52
        }
 
53
 
 
54
        virtual void append(std::ostringstream& out, const LoggingEvent& event) {
 
55
            out << _literal;
 
56
        }
 
57
 
 
58
        private:
 
59
        std::string _literal;
 
60
    };
 
61
 
 
62
    struct CategoryNameComponent : public PatternLayout::PatternComponent {
 
63
        CategoryNameComponent(std::string specifier) {
 
64
            if (specifier == "") {
 
65
                _precision = -1;
 
66
            } else {
 
67
#ifdef LOG4SHIB_HAVE_SSTREAM 
 
68
                std::istringstream s(specifier);
 
69
#else
 
70
                std::istrstream s(specifier.c_str());
 
71
#endif
 
72
                s >> _precision;
 
73
            }
 
74
        }
 
75
 
 
76
        virtual void append(std::ostringstream& out, const LoggingEvent& event) {
 
77
            if (_precision == -1) {
 
78
                out << event.categoryName;
 
79
            } else {
 
80
                std::string::size_type begin = std::string::npos;
 
81
                for(int i = 0; i < _precision; i++) {
 
82
                    begin = event.categoryName.rfind('.', begin - 2);
 
83
                    if (begin == std::string::npos) {
 
84
                        begin = 0;
 
85
                        break;
 
86
                    }
 
87
                    begin++;
 
88
                }
 
89
                out << event.categoryName.substr(begin);
 
90
            }
 
91
        }
 
92
 
 
93
        private:
 
94
        int _precision;
 
95
    };
 
96
 
 
97
    struct MessageComponent : public PatternLayout::PatternComponent {
 
98
        virtual void append(std::ostringstream& out, const LoggingEvent& event) {
 
99
            out << event.message;
 
100
        }
 
101
    };
 
102
 
 
103
    struct NDCComponent : public PatternLayout::PatternComponent {
 
104
        virtual void append(std::ostringstream& out, const LoggingEvent& event) {
 
105
            out << event.ndc;
 
106
        }
 
107
    };
 
108
 
 
109
    struct PriorityComponent : public PatternLayout::PatternComponent {
 
110
        virtual void append(std::ostringstream& out, const LoggingEvent& event) {
 
111
            out << Priority::getPriorityName(event.priority);
 
112
        }
 
113
    };
 
114
 
 
115
    struct ThreadNameComponent : public PatternLayout::PatternComponent {
 
116
        virtual void append(std::ostringstream& out, const LoggingEvent& event) {
 
117
            out << event.threadName;
 
118
        }
 
119
    };
 
120
 
 
121
    struct ProcessorTimeComponent : public PatternLayout::PatternComponent {
 
122
        virtual void append(std::ostringstream& out, const LoggingEvent& event) {
 
123
            out << ::clock();
 
124
        }
 
125
    };
 
126
 
 
127
    struct TimeStampComponent : public PatternLayout::PatternComponent {
 
128
        static const char* const FORMAT_ISO8601;
 
129
        static const char* const FORMAT_ABSOLUTE;
 
130
        static const char* const FORMAT_DATE;
 
131
 
 
132
        TimeStampComponent(std::string timeFormat) {
 
133
            if ((timeFormat == "") || (timeFormat == "ISO8601")) {
 
134
                timeFormat = FORMAT_ISO8601;
 
135
            } else if (timeFormat == "ABSOLUTE") {
 
136
                timeFormat = FORMAT_ABSOLUTE;
 
137
            } else if (timeFormat == "DATE") {
 
138
                timeFormat = FORMAT_DATE;
 
139
            }
 
140
            std::string::size_type pos = timeFormat.find("%l");
 
141
            if (pos == std::string::npos) {
 
142
                _printMillis = false;
 
143
                _timeFormat1 = timeFormat; 
 
144
            } else {
 
145
                _printMillis = true;
 
146
                _timeFormat1 = timeFormat.substr(0, pos);
 
147
                _timeFormat2 = timeFormat.substr(pos + 2);
 
148
            }
 
149
        }
 
150
 
 
151
        virtual void append(std::ostringstream& out, const LoggingEvent& event) {
 
152
            struct tm *currentTime;
 
153
            time_t t = event.timeStamp.getSeconds();
 
154
#ifdef LOG4SHIB_HAVE_LOCALTIME_R
 
155
            struct tm currentTime_var;
 
156
            currentTime = ::localtime_r(&t, &currentTime_var);
 
157
#else
 
158
            currentTime = std::localtime(&t);
 
159
#endif
 
160
            char formatted[100];
 
161
            std::string timeFormat;
 
162
            if (_printMillis) {
 
163
                std::ostringstream formatStream;
 
164
                formatStream << _timeFormat1 
 
165
                             << std::setw(3) << std::setfill('0')
 
166
                             << event.timeStamp.getMilliSeconds()
 
167
                             << _timeFormat2;
 
168
                timeFormat = formatStream.str();
 
169
            } else {
 
170
                timeFormat = _timeFormat1;
 
171
            }
 
172
            std::strftime(formatted, sizeof(formatted), timeFormat.c_str(), currentTime);
 
173
            out << formatted;
 
174
        }
 
175
 
 
176
        private:
 
177
        std::string _timeFormat1;
 
178
        std::string _timeFormat2;
 
179
        bool _printMillis;
 
180
    };
 
181
 
 
182
    const char* const TimeStampComponent::FORMAT_ISO8601 = "%Y-%m-%d %H:%M:%S,%l";
 
183
    const char* const TimeStampComponent::FORMAT_ABSOLUTE = "%H:%M:%S,%l";
 
184
    const char* const TimeStampComponent::FORMAT_DATE = "%d %b %Y %H:%M:%S,%l";
 
185
 
 
186
    struct SecondsSinceEpochComponent : public PatternLayout::PatternComponent {
 
187
        virtual void append(std::ostringstream& out, const LoggingEvent& event) {
 
188
            out << event.timeStamp.getSeconds();
 
189
        }
 
190
    };
 
191
 
 
192
    struct MillisSinceEpochComponent : public PatternLayout::PatternComponent {
 
193
        virtual void append(std::ostringstream& out, const LoggingEvent& event) {
 
194
#ifdef LOG4SHIB_HAVE_INT64_T
 
195
            int64_t t = event.timeStamp.getSeconds() -
 
196
                TimeStamp::getStartTime().getSeconds();
 
197
            t *= 1000;
 
198
            t += event.timeStamp.getMilliSeconds() -
 
199
                TimeStamp::getStartTime().getMilliSeconds();
 
200
            
 
201
            out << t;
 
202
#else
 
203
            double t = event.timeStamp.getSeconds() -
 
204
                TimeStamp::getStartTime().getSeconds();
 
205
            t *= 1000;
 
206
            t += event.timeStamp.getMilliSeconds() -
 
207
                TimeStamp::getStartTime().getMilliSeconds();
 
208
            
 
209
            out << std::setiosflags(std::ios::fixed)
 
210
                << std::setprecision(0) << t;
 
211
#endif
 
212
        }
 
213
    };
 
214
 
 
215
    struct FormatModifierComponent : public PatternLayout::PatternComponent {
 
216
        FormatModifierComponent(PatternLayout::PatternComponent* component,
 
217
                                size_t minWidth, size_t maxWidth, bool alignLeft) :
 
218
            _component(component) , 
 
219
            _minWidth(minWidth),
 
220
            _maxWidth(maxWidth),
 
221
            _alignLeft(alignLeft) {
 
222
        }
 
223
 
 
224
        virtual ~FormatModifierComponent() {
 
225
            delete _component;
 
226
        }
 
227
 
 
228
        virtual void append(std::ostringstream& out, const LoggingEvent& event) {
 
229
            std::ostringstream s;
 
230
            _component->append(s, event);
 
231
            std::string msg = s.str();
 
232
            if (_maxWidth > 0 && _maxWidth < msg.length()) {
 
233
                msg.erase(_maxWidth);
 
234
            }
 
235
            std::string::size_type fillCount = _minWidth - msg.length();
 
236
            if (_minWidth > msg.length()) {
 
237
                if (_alignLeft) {
 
238
                    out << msg << std::string(fillCount, ' ');
 
239
                } else {
 
240
                    out << std::string(fillCount, ' ') << msg;
 
241
                }
 
242
            } else {
 
243
                out << msg;
 
244
            }
 
245
        }
 
246
 
 
247
        private:
 
248
        PatternLayout::PatternComponent* _component;
 
249
        size_t _minWidth;
 
250
        size_t _maxWidth;
 
251
        bool _alignLeft;
 
252
    };
 
253
 
 
254
    const char* PatternLayout::DEFAULT_CONVERSION_PATTERN = "%m%n";
 
255
    const char* PatternLayout::SIMPLE_CONVERSION_PATTERN = "%p - %m%n";
 
256
    const char* PatternLayout::BASIC_CONVERSION_PATTERN = "%R %p %c %x: %m%n";
 
257
    const char* PatternLayout::TTCC_CONVERSION_PATTERN = "%r [%t] %p %c %x - %m%n";
 
258
 
 
259
    PatternLayout::PatternLayout() {
 
260
        try {
 
261
            setConversionPattern(DEFAULT_CONVERSION_PATTERN);
 
262
        } catch(ConfigureFailure&) {
 
263
        }
 
264
    }
 
265
 
 
266
    PatternLayout::~PatternLayout() {
 
267
        clearConversionPattern();
 
268
    }
 
269
 
 
270
    void PatternLayout::clearConversionPattern() {
 
271
        for(ComponentVector::const_iterator i = _components.begin();
 
272
            i != _components.end(); ++i) {
 
273
            delete (*i);
 
274
        }
 
275
        _components.clear();
 
276
        _conversionPattern = "";
 
277
    }
 
278
 
 
279
    void PatternLayout::setConversionPattern(const std::string& conversionPattern) throw(ConfigureFailure) {
 
280
#ifdef LOG4SHIB_HAVE_SSTREAM 
 
281
        std::istringstream conversionStream(conversionPattern);
 
282
#else
 
283
        std::istrstream conversionStream(conversionPattern.c_str());
 
284
#endif
 
285
        std::string literal;
 
286
 
 
287
        char ch;
 
288
        PatternLayout::PatternComponent* component = NULL;
 
289
        int minWidth = 0;
 
290
        size_t maxWidth = 0;
 
291
        clearConversionPattern();
 
292
        while (conversionStream.get(ch)) {
 
293
            if (ch == '%') {
 
294
                // readPrefix;
 
295
                {
 
296
                    char ch2;
 
297
                    conversionStream.get(ch2);
 
298
                    if ((ch2 == '-') || ((ch2 >= '0') && (ch2 <= '9'))) {
 
299
                        conversionStream.putback(ch2);
 
300
                        conversionStream >> minWidth;
 
301
                        conversionStream.get(ch2);
 
302
                    } 
 
303
                    if (ch2 == '.') {
 
304
                        conversionStream >> maxWidth;
 
305
                    } else {
 
306
                        conversionStream.putback(ch2);
 
307
                    }                        
 
308
                }
 
309
                if (!conversionStream.get(ch)) {
 
310
                    std::ostringstream msg;
 
311
                    msg << "unterminated conversion specifier in '" << conversionPattern << "' at index " << conversionStream.tellg();
 
312
                    throw ConfigureFailure(msg.str());
 
313
                }
 
314
                std::string specPostfix = "";
 
315
                // read postfix
 
316
                {
 
317
                    char ch2;
 
318
                    if (conversionStream.get(ch2)) {
 
319
                        if (ch2 == '{') {
 
320
                            while(conversionStream.get(ch2) && (ch2 != '}'))
 
321
                                specPostfix += ch2;
 
322
                        } else {
 
323
                            conversionStream.putback(ch2);
 
324
                        }
 
325
                    }
 
326
                }
 
327
                switch (ch) {
 
328
                case '%':
 
329
                    literal += ch;
 
330
                    break;
 
331
                case 'm':
 
332
                    component = new MessageComponent();
 
333
                    break;
 
334
                case 'n':
 
335
                    {
 
336
                        std::ostringstream endline;
 
337
                        endline << std::endl;
 
338
                        literal += endline.str();
 
339
                    }
 
340
                    break;
 
341
                case 'c':
 
342
                    component = new CategoryNameComponent(specPostfix);
 
343
                    break;
 
344
                case 'd':
 
345
                    component = new TimeStampComponent(specPostfix);
 
346
                    break;
 
347
                case 'p':
 
348
                    component = new PriorityComponent();
 
349
                    break;
 
350
                case 'r':
 
351
                    component = new MillisSinceEpochComponent();
 
352
                    break;
 
353
                case 'R':
 
354
                    component = new SecondsSinceEpochComponent();
 
355
                    break;
 
356
                case 't':
 
357
                    component = new ThreadNameComponent();
 
358
                    break;
 
359
                case 'u':
 
360
                    component = new ProcessorTimeComponent();
 
361
                    break;
 
362
                case 'x':
 
363
                    component = new NDCComponent();
 
364
                    break;
 
365
                default:
 
366
                    std::ostringstream msg;
 
367
                    msg << "unknown conversion specifier '" << ch << "' in '" << conversionPattern << "' at index " << conversionStream.tellg();
 
368
                    throw ConfigureFailure(msg.str());                    
 
369
                }
 
370
                if (component) {
 
371
                    if (!literal.empty()) {
 
372
                        _components.push_back(new StringLiteralComponent(literal));
 
373
                        literal = "";
 
374
                    }
 
375
                    if ((minWidth != 0) || (maxWidth != 0)) {
 
376
                        component = new FormatModifierComponent(component, std::abs(minWidth), maxWidth, minWidth < 0);
 
377
                        minWidth = 0;
 
378
                        maxWidth = 0;
 
379
                    }
 
380
                    _components.push_back(component);
 
381
                    component = NULL;
 
382
                }
 
383
            } else {
 
384
                literal += ch;
 
385
            }
 
386
        }
 
387
        if (!literal.empty()) {
 
388
            _components.push_back(new StringLiteralComponent(literal));
 
389
        }
 
390
 
 
391
        _conversionPattern = conversionPattern;
 
392
    }
 
393
 
 
394
    std::string PatternLayout::getConversionPattern() const {
 
395
        return _conversionPattern;
 
396
    }
 
397
 
 
398
    std::string PatternLayout::format(const LoggingEvent& event) {
 
399
        std::ostringstream message;
 
400
 
 
401
        for(ComponentVector::const_iterator i = _components.begin();
 
402
            i != _components.end(); ++i) {
 
403
            (*i)->append(message, event);
 
404
        }
 
405
 
 
406
        return message.str();
 
407
    }
 
408
}