Name: js-handler/node_modules/restify/node_modules/bunyan/lib/bunyan.js 
1:
/*
2:
 * Copyright (c) 2013 Trent Mick. All rights reserved.
3:
 *
4:
 * The bunyan logging library for node.js.
5:
 */
6:
 
7:
var VERSION = '0.21.1';
8:
 
9:
// Bunyan log format version. This becomes the 'v' field on all log records.
10:
// `0` is until I release a version '1.0.0' of node-bunyan. Thereafter,
11:
// starting with `1`, this will be incremented if there is any backward
12:
// incompatible change to the log record format. Details will be in
13:
// 'CHANGES.md' (the change log).
14:
var LOG_VERSION = 0;
15:
 
16:
 
17:
var xxx = function xxx(s) {     // internal dev/debug logging
18:
    var args = ['XX' + 'X: '+s].concat(
19:
        Array.prototype.slice.call(arguments, 1));
20:
    console.error.apply(this, args);
21:
};
22:
var xxx = function xxx() {};  // comment out to turn on debug logging
23:
 
24:
 
25:
var os = require('os');
26:
var fs = require('fs');
27:
var util = require('util');
28:
var assert = require('assert');
29:
try {
30:
    var dtrace = require('dtrace-provider');
31:
} catch (e) {
32:
    dtrace = null;
33:
}
34:
var EventEmitter = require('events').EventEmitter;
35:
 
36:
// The 'mv' module is required for rotating-file stream support.
37:
try {
38:
    var mv = require('mv');
39:
} catch (e) {
40:
    mv = null;
41:
}
42:
 
43:
 
44:
 
45:
//---- Internal support stuff
46:
 
47:
function objCopy(obj) {
48:
    if (obj === null) {
49:
        return null;
50:
    } else if (Array.isArray(obj)) {
51:
        return obj.slice();
52:
    } else {
53:
        var copy = {};
54:
        Object.keys(obj).forEach(function (k) {
55:
            copy[k] = obj[k];
56:
        });
57:
        return copy;
58:
    }
59:
}
60:
 
61:
var format = util.format;
62:
if (!format) {
63:
    // If node < 0.6, then use its `util.format`:
64:
    // <https://github.com/joyent/node/blob/master/lib/util.js#L22>:
65:
    var inspect = util.inspect;
66:
    var formatRegExp = /%[sdj%]/g;
67:
    format = function format(f) {
68:
        if (typeof (f) !== 'string') {
69:
            var objects = [];
70:
            for (var i = 0; i < arguments.length; i++) {
71:
                objects.push(inspect(arguments[i]));
72:
            }
73:
            return objects.join(' ');
74:
        }
75:
 
76:
        var i = 1;
77:
        var args = arguments;
78:
        var len = args.length;
79:
        var str = String(f).replace(formatRegExp, function (x) {
80:
            if (i >= len)
81:
                return x;
82:
            switch (x) {
83:
                case '%s': return String(args[i++]);
84:
                case '%d': return Number(args[i++]);
85:
                case '%j': return JSON.stringify(args[i++], safeCycles());
86:
                case '%%': return '%';
87:
                default:
88:
                    return x;
89:
            }
90:
        });
91:
        for (var x = args[i]; i < len; x = args[++i]) {
92:
            if (x === null || typeof (x) !== 'object') {
93:
                str += ' ' + x;
94:
            } else {
95:
                str += ' ' + inspect(x);
96:
            }
97:
        }
98:
        return str;
99:
    };
100:
}
101:
 
102:
 
103:
/**
104:
 * Gather some caller info 3 stack levels up.
105:
 * See <http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi>.
106:
 */
107:
function getCaller3Info() {
108:
    var obj = {};
109:
    var saveLimit = Error.stackTraceLimit;
110:
    var savePrepare = Error.prepareStackTrace;
111:
    Error.stackTraceLimit = 3;
112:
    Error.captureStackTrace(this, getCaller3Info);
113:
    Error.prepareStackTrace = function (_, stack) {
114:
        var caller = stack[2];
115:
        obj.file = caller.getFileName();
116:
        obj.line = caller.getLineNumber();
117:
        var func = caller.getFunctionName();
118:
        if (func)
119:
            obj.func = func;
120:
    };
121:
    this.stack;
122:
    Error.stackTraceLimit = saveLimit;
123:
    Error.prepareStackTrace = savePrepare;
124:
    return obj;
125:
}
126:
 
127:
 
128:
/**
129:
 * Warn about an bunyan processing error.
130:
 *
131:
 * If file/line are given, this makes an attempt to warn on stderr only once.
132:
 *
133:
 * @param msg {String} Message with which to warn.
134:
 * @param file {String} Optional. File path relevant for the warning.
135:
 * @param line {String} Optional. Line number in `file` path relevant for
136:
 *    the warning.
137:
 */
138:
function _warn(msg, file, line) {
139:
    assert.ok(msg);
140:
    var key;
141:
    if (file && line) {
142:
        key = file + ':' + line;
143:
        if (_warned[key]) {
144:
            return;
145:
        }
146:
        _warned[key] = true;
147:
    }
148:
    process.stderr.write(msg + '\n');
149:
}
150:
var _warned = {};
151:
 
152:
 
153:
 
154:
//---- Levels
155:
 
156:
var TRACE = 10;
157:
var DEBUG = 20;
158:
var INFO = 30;
159:
var WARN = 40;
160:
var ERROR = 50;
161:
var FATAL = 60;
162:
 
163:
var levelFromName = {
164:
    'trace': TRACE,
165:
    'debug': DEBUG,
166:
    'info': INFO,
167:
    'warn': WARN,
168:
    'error': ERROR,
169:
    'fatal': FATAL
170:
};
171:
 
172:
// Dtrace probes.
173:
var dtp = undefined;
174:
var probes = dtrace && {};
175:
 
176:
/**
177:
 * Resolve a level number, name (upper or lowercase) to a level number value.
178:
 *
179:
 * @api public
180:
 */
181:
function resolveLevel(nameOrNum) {
182:
    var level = (typeof (nameOrNum) === 'string'
183:
            ? levelFromName[nameOrNum.toLowerCase()]
184:
            : nameOrNum);
185:
    if (! (TRACE <= level && level <= FATAL)) {
186:
        throw new Error('invalid level: ' + nameOrNum);
187:
    }
188:
    return level;
189:
}
190:
 
191:
 
192:
 
193:
//---- Logger class
194:
 
195:
/**
196:
 * Create a Logger instance.
197:
 *
198:
 * @param options {Object} See documentation for full details. At minimum
199:
 *    this must include a 'name' string key. Configuration keys:
200:
 *      - `streams`: specify the logger output streams. This is an array of
201:
 *        objects with these fields:
202:
 *          - `type`: The stream type. See README.md for full details.
203:
 *            Often this is implied by the other fields. Examples are
204:
 *            'file', 'stream' and "raw".
205:
 *          - `level`: Defaults to 'info'.
206:
 *          - `path` or `stream`: The specify the file path or writeable
207:
 *            stream to which log records are written. E.g.
208:
 *            `stream: process.stdout`.
209:
 *          - `closeOnExit` (boolean): Optional. Default is true for a
210:
 *            'file' stream when `path` is given, false otherwise.
211:
 *        See README.md for full details.
212:
 *      - `level`: set the level for a single output stream (cannot be used
213:
 *        with `streams`)
214:
 *      - `stream`: the output stream for a logger with just one, e.g.
215:
 *        `process.stdout` (cannot be used with `streams`)
216:
 *      - `serializers`: object mapping log record field names to
217:
 *        serializing functions. See README.md for details.
218:
 *      - `src`: Boolean (default false). Set true to enable 'src' automatic
219:
 *        field with log call source info.
220:
 *    All other keys are log record fields.
221:
 *
222:
 * An alternative *internal* call signature is used for creating a child:
223:
 *    new Logger(<parent logger>, <child options>[, <child opts are simple>]);
224:
 *
225:
 * @param _childSimple (Boolean) An assertion that the given `_childOptions`
226:
 *    (a) only add fields (no config) and (b) no serialization handling is
227:
 *    required for them. IOW, this is a fast path for frequent child
228:
 *    creation.
229:
 */
230:
function Logger(options, _childOptions, _childSimple) {
231:
    xxx('Logger start:', options)
232:
    if (! this instanceof Logger) {
233:
        return new Logger(options, _childOptions);
234:
    }
235:
 
236:
    // Input arg validation.
237:
    var parent;
238:
    if (_childOptions !== undefined) {
239:
        parent = options;
240:
        options = _childOptions;
241:
        if (! parent instanceof Logger) {
242:
            throw new TypeError(
243:
                'invalid Logger creation: do not pass a second arg');
244:
        }
245:
    }
246:
    if (!options) {
247:
        throw new TypeError('options (object) is required');
248:
    }
249:
    if (!parent) {
250:
        if (!options.name) {
251:
            throw new TypeError('options.name (string) is required');
252:
        }
253:
    } else {
254:
        if (options.name) {
255:
            throw new TypeError(
256:
                'invalid options.name: child cannot set logger name');
257:
        }
258:
    }
259:
    if (options.stream && options.streams) {
260:
        throw new TypeError('cannot mix "streams" and "stream" options');
261:
    }
262:
    if (options.streams && !Array.isArray(options.streams)) {
263:
        throw new TypeError('invalid options.streams: must be an array')
264:
    }
265:
    if (options.serializers && (typeof (options.serializers) !== 'object' ||
266:
            Array.isArray(options.serializers))) {
267:
        throw new TypeError('invalid options.serializers: must be an object')
268:
    }
269:
 
270:
    EventEmitter.call(this);
271:
 
272:
    // Fast path for simple child creation.
273:
    if (parent && _childSimple) {
274:
        // `_isSimpleChild` is a signal to stream close handling that this child
275:
        // owns none of its streams.
276:
        this._isSimpleChild = true;
277:
 
278:
        this._level = parent._level;
279:
        this.streams = parent.streams;
280:
        this.serializers = parent.serializers;
281:
        this.src = parent.src;
282:
        var fields = this.fields = {};
283:
        var parentFieldNames = Object.keys(parent.fields);
284:
        for (var i = 0; i < parentFieldNames.length; i++) {
285:
            var name = parentFieldNames[i];
286:
            fields[name] = parent.fields[name];
287:
        }
288:
        var names = Object.keys(options);
289:
        for (var i = 0; i < names.length; i++) {
290:
            var name = names[i];
291:
            fields[name] = options[name];
292:
        }
293:
        return;
294:
    }
295:
 
296:
    // Null values.
297:
    var self = this;
298:
    if (parent) {
299:
        this._level = parent._level;
300:
        this.streams = [];
301:
        for (var i = 0; i < parent.streams.length; i++) {
302:
            var s = objCopy(parent.streams[i]);
303:
            s.closeOnExit = false; // Don't own parent stream.
304:
            this.streams.push(s);
305:
        }
306:
        this.serializers = objCopy(parent.serializers);
307:
        this.src = parent.src;
308:
        this.fields = objCopy(parent.fields);
309:
        if (options.level) {
310:
            this.level(options.level);
311:
        }
312:
    } else {
313:
        this._level = Number.POSITIVE_INFINITY;
314:
        this.streams = [];
315:
        this.serializers = null;
316:
        this.src = false;
317:
        this.fields = {};
318:
    }
319:
 
320:
    if (!dtp && dtrace) {
321:
        dtp = dtrace.createDTraceProvider('bunyan');
322:
 
323:
        for (var level in levelFromName) {
324:
            var probe;
325:
 
326:
            probes[levelFromName[level]] = probe =
327:
                dtp.addProbe('log-' + level, 'char *');
328:
 
329:
            // Explicitly add a reference to dtp to prevent it from being GC'd
330:
            probe.dtp = dtp;
331:
        }
332:
 
333:
        dtp.enable();
334:
    }
335:
 
336:
    // Helpers
337:
    function addStream(s) {
338:
        s = objCopy(s);
339:
 
340:
        // Implicit 'type' from other args.
341:
        var type = s.type;
342:
        if (!s.type) {
343:
            if (s.stream) {
344:
                s.type = 'stream';
345:
            } else if (s.path) {
346:
                s.type = 'file'
347:
            }
348:
        }
349:
        s.raw = (s.type === 'raw');  // PERF: Allow for faster check in `_emit`.
350:
 
351:
        if (s.level) {
352:
            s.level = resolveLevel(s.level);
353:
        } else if (options.level) {
354:
            s.level = resolveLevel(options.level);
355:
        } else {
356:
            s.level = INFO;
357:
        }
358:
        if (s.level < self._level) {
359:
            self._level = s.level;
360:
        }
361:
 
362:
        switch (s.type) {
363:
        case 'stream':
364:
            if (!s.closeOnExit) {
365:
                s.closeOnExit = false;
366:
            }
367:
            break;
368:
        case 'file':
369:
            if (!s.stream) {
370:
                s.stream = fs.createWriteStream(s.path,
371:
                    {flags: 'a', encoding: 'utf8'});
372:
                s.stream.on('error', function (err) {
373:
                    self.emit('error', err, s);
374:
                });
375:
                if (!s.closeOnExit) {
376:
                    s.closeOnExit = true;
377:
                }
378:
            } else {
379:
                if (!s.closeOnExit) {
380:
                    s.closeOnExit = false;
381:
                }
382:
            }
383:
            break;
384:
        case 'rotating-file':
385:
            assert.ok(!s.stream,
386:
                '"rotating-file" stream should not give a "stream"');
387:
            assert.ok(s.path);
388:
            assert.ok(mv, '"rotating-file" stream type is not supported: '
389:
                + 'missing "mv" module');
390:
            s.stream = new RotatingFileStream(s);
391:
            if (!s.closeOnExit) {
392:
                s.closeOnExit = true;
393:
            }
394:
            break;
395:
        case 'raw':
396:
            if (!s.closeOnExit) {
397:
                s.closeOnExit = false;
398:
            }
399:
            break;
400:
        default:
401:
            throw new TypeError('unknown stream type "' + s.type + '"');
402:
        }
403:
 
404:
        self.streams.push(s);
405:
    }
406:
 
407:
    function addSerializers(serializers) {
408:
        if (!self.serializers) {
409:
            self.serializers = {};
410:
        }
411:
        Object.keys(serializers).forEach(function (field) {
412:
            var serializer = serializers[field];
413:
            if (typeof (serializer) !== 'function') {
414:
                throw new TypeError(format(
415:
                    'invalid serializer for "%s" field: must be a function',
416:
                    field));
417:
            } else {
418:
                self.serializers[field] = serializer;
419:
            }
420:
        });
421:
    }
422:
 
423:
    // Handle *config* options (i.e. options that are not just plain data
424:
    // for log records).
425:
    if (options.stream) {
426:
        addStream({
427:
            type: 'stream',
428:
            stream: options.stream,
429:
            closeOnExit: false,
430:
            level: (options.level ? resolveLevel(options.level) : INFO)
431:
        });
432:
    } else if (options.streams) {
433:
        options.streams.forEach(addStream);
434:
    } else if (parent && options.level) {
435:
        this.level(options.level);
436:
    } else if (!parent) {
437:
        addStream({
438:
            type: 'stream',
439:
            stream: process.stdout,
440:
            closeOnExit: false,
441:
            level: (options.level ? resolveLevel(options.level) : INFO)
442:
        });
443:
    }
444:
    if (options.serializers) {
445:
        addSerializers(options.serializers);
446:
    }
447:
    if (options.src) {
448:
        this.src = true;
449:
    }
450:
    xxx('Logger: ', self)
451:
 
452:
    // Fields.
453:
    // These are the default fields for log records (minus the attributes
454:
    // removed in this constructor). To allow storing raw log records
455:
    // (unrendered), `this.fields` must never be mutated. Create a copy for
456:
    // any changes.
457:
    var fields = objCopy(options);
458:
    delete fields.stream;
459:
    delete fields.level;
460:
    delete fields.streams;
461:
    delete fields.serializers;
462:
    delete fields.src;
463:
    if (this.serializers) {
464:
        this._applySerializers(fields);
465:
    }
466:
    if (!fields.hostname) {
467:
        fields.hostname = os.hostname();
468:
    }
469:
    if (!fields.pid) {
470:
        fields.pid = process.pid;
471:
    }
472:
    Object.keys(fields).forEach(function (k) {
473:
        self.fields[k] = fields[k];
474:
    });
475:
}
476:
 
477:
util.inherits(Logger, EventEmitter);
478:
 
479:
 
480:
/**
481:
 * Create a child logger, typically to add a few log record fields.
482:
 *
483:
 * This can be useful when passing a logger to a sub-component, e.g. a
484:
 * 'wuzzle' component of your service:
485:
 *
486:
 *    var wuzzleLog = log.child({component: 'wuzzle'})
487:
 *    var wuzzle = new Wuzzle({..., log: wuzzleLog})
488:
 *
489:
 * Then log records from the wuzzle code will have the same structure as
490:
 * the app log, *plus the component='wuzzle' field*.
491:
 *
492:
 * @param options {Object} Optional. Set of options to apply to the child.
493:
 *    All of the same options for a new Logger apply here. Notes:
494:
 *      - The parent's streams are inherited and cannot be removed in this
495:
 *        call. Any given `streams` are *added* to the set inherited from
496:
 *        the parent.
497:
 *      - The parent's serializers are inherited, though can effectively be
498:
 *        overwritten by using duplicate keys.
499:
 *      - Can use `level` to set the level of the streams inherited from
500:
 *        the parent. The level for the parent is NOT affected.
501:
 * @param simple {Boolean} Optional. Set to true to assert that `options`
502:
 *    (a) only add fields (no config) and (b) no serialization handling is
503:
 *    required for them. IOW, this is a fast path for frequent child
504:
 *    creation. See 'tools/timechild.js' for numbers.
505:
 */
506:
Logger.prototype.child = function (options, simple) {
507:
    return new Logger(this, options || {}, simple);
508:
}
509:
 
510:
 
511:
/* BEGIN JSSTYLED */
512:
/**
513:
 * Close this logger.
514:
 *
515:
 * This closes streams (that it owns, as per 'endOnClose' attributes on
516:
 * streams), etc. Typically you **don't** need to bother calling this.
517:
Logger.prototype.close = function () {
518:
    if (this._closed) {
519:
        return;
520:
    }
521:
    if (!this._isSimpleChild) {
522:
        self.streams.forEach(function (s) {
523:
            if (s.endOnClose) {
524:
                xxx('closing stream s:', s);
525:
                s.stream.end();
526:
                s.endOnClose = false;
527:
            }
528:
        });
529:
    }
530:
    this._closed = true;
531:
}
532:
 */
533:
/* END JSSTYLED */
534:
 
535:
 
536:
/**
537:
 * Get/set the level of all streams on this logger.
538:
 *
539:
 * Get Usage:
540:
 *    // Returns the current log level (lowest level of all its streams).
541:
 *    log.level() -> INFO
542:
 *
543:
 * Set Usage:
544:
 *    log.level(INFO)       // set all streams to level INFO
545:
 *    log.level('info')     // can use 'info' et al aliases
546:
 */
547:
Logger.prototype.level = function level(value) {
548:
    if (value === undefined) {
549:
        return this._level;
550:
    }
551:
    var newLevel = resolveLevel(value);
552:
    var len = this.streams.length;
553:
    for (var i = 0; i < len; i++) {
554:
        this.streams[i].level = newLevel;
555:
    }
556:
    this._level = newLevel;
557:
}
558:
 
559:
 
560:
/**
561:
 * Get/set the level of a particular stream on this logger.
562:
 *
563:
 * Get Usage:
564:
 *    // Returns an array of the levels of each stream.
565:
 *    log.levels() -> [TRACE, INFO]
566:
 *
567:
 *    // Returns a level of the identified stream.
568:
 *    log.levels(0) -> TRACE      // level of stream at index 0
569:
 *    log.levels('foo')           // level of stream with name 'foo'
570:
 *
571:
 * Set Usage:
572:
 *    log.levels(0, INFO)         // set level of stream 0 to INFO
573:
 *    log.levels(0, 'info')       // can use 'info' et al aliases
574:
 *    log.levels('foo', WARN)     // set stream named 'foo' to WARN
575:
 *
576:
 * Stream names: When streams are defined, they can optionally be given
577:
 * a name. For example,
578:
 *       log = new Logger({
579:
 *         streams: [
580:
 *           {
581:
 *             name: 'foo',
582:
 *             path: '/var/log/my-service/foo.log'
583:
 *             level: 'trace'
584:
 *           },
585:
 *         ...
586:
 *
587:
 * @param name {String|Number} The stream index or name.
588:
 * @param value {Number|String} The level value (INFO) or alias ('info').
589:
 *    If not given, this is a 'get' operation.
590:
 * @throws {Error} If there is no stream with the given name.
591:
 */
592:
Logger.prototype.levels = function levels(name, value) {
593:
    if (name === undefined) {
594:
        assert.equal(value, undefined);
595:
        return this.streams.map(
596:
            function (s) { return s.level });
597:
    }
598:
    var stream;
599:
    if (typeof (name) === 'number') {
600:
        stream = this.streams[name];
601:
        if (stream === undefined) {
602:
            throw new Error('invalid stream index: ' + name);
603:
        }
604:
    } else {
605:
        var len = this.streams.length;
606:
        for (var i = 0; i < len; i++) {
607:
            var s = this.streams[i];
608:
            if (s.name === name) {
609:
                stream = s;
610:
                break;
611:
            }
612:
        }
613:
        if (!stream) {
614:
            throw new Error(format('no stream with name "%s"', name));
615:
        }
616:
    }
617:
    if (value === undefined) {
618:
        return stream.level;
619:
    } else {
620:
        var newLevel = resolveLevel(value);
621:
        stream.level = newLevel;
622:
        if (newLevel < this._level) {
623:
            this._level = newLevel;
624:
        }
625:
    }
626:
}
627:
 
628:
 
629:
/**
630:
 * Apply registered serializers to the appropriate keys in the given fields.
631:
 *
632:
 * Pre-condition: This is only called if there is at least one serializer.
633:
 *
634:
 * @param fields (Object) The log record fields.
635:
 * @param excludeFields (Object) Optional mapping of keys to `true` for
636:
 *    keys to NOT apply a serializer.
637:
 */
638:
Logger.prototype._applySerializers = function (fields, excludeFields) {
639:
    var self = this;
640:
 
641:
    xxx('_applySerializers: excludeFields', excludeFields);
642:
 
643:
    // Check each serializer against these (presuming number of serializers
644:
    // is typically less than number of fields).
645:
    Object.keys(this.serializers).forEach(function (name) {
646:
        if (fields[name] === undefined ||
647:
            (excludeFields && excludeFields[name]))
648:
        {
649:
            return;
650:
        }
651:
        xxx('_applySerializers; apply to "%s" key', name)
652:
        try {
653:
            fields[name] = self.serializers[name](fields[name]);
654:
        } catch (err) {
655:
            _warn(format('bunyan: ERROR: This should never happen. '
656:
                + 'This is a bug in <https://github.com/trentm/node-bunyan> '
657:
                + 'or in this application. Exception from "%s" Logger '
658:
                + 'serializer: %s',
659:
                name, err.stack || err));
660:
            fields[name] = format('(Error in Bunyan log "%s" serializer '
661:
                + 'broke field. See stderr for details.)', name);
662:
        }
663:
    });
664:
}
665:
 
666:
 
667:
/**
668:
 * A log record is a 4-tuple:
669:
 *    [<default fields object>,
670:
 *     <log record fields object>,
671:
 *     <level integer>,
672:
 *     <msg args array>]
673:
 * For Perf reasons, we only render this down to a single object when
674:
 * it is emitted.
675:
 */
676:
Logger.prototype._mkRecord = function (fields, level, msgArgs) {
677:
    var recFields = (fields ? objCopy(fields) : null);
678:
    return [this.fields, recFields, level, msgArgs];
679:
}
680:
 
681:
 
682:
/**
683:
 * Emit a log record.
684:
 *
685:
 * @param rec {log record}
686:
 * @param noemit {Boolean} Optional. Set to true to skip emission
687:
 *      and just return the JSON string.
688:
 */
689:
Logger.prototype._emit = function (rec, noemit) {
690:
    var i;
691:
 
692:
    // Lazily determine if this Logger has non-'raw' streams. If there are
693:
    // any, then we need to stringify the log record.
694:
    if (this.haveNonRawStreams === undefined) {
695:
        this.haveNonRawStreams = false;
696:
        for (i = 0; i < this.streams.length; i++) {
697:
            if (!this.streams[i].raw) {
698:
                this.haveNonRawStreams = true;
699:
                break;
700:
            }
701:
        }
702:
    }
703:
 
704:
    // Stringify the object. Attempt to warn/recover on error.
705:
    var str;
706:
    if (noemit || this.haveNonRawStreams) {
707:
        str = JSON.stringify(rec, safeCycles()) + '\n';
708:
    }
709:
 
710:
    if (noemit)
711:
        return str;
712:
 
713:
    var level = rec.level;
714:
    for (i = 0; i < this.streams.length; i++) {
715:
        var s = this.streams[i];
716:
        if (s.level <= level) {
717:
            xxx('writing log rec "%s" to "%s" stream (%d <= %d): %j',
718:
                rec.msg, s.type, s.level, level, rec);
719:
            s.stream.write(s.raw ? rec : str);
720:
        }
721:
    };
722:
 
723:
    return str;
724:
}
725:
 
726:
 
727:
/**
728:
 * Build a log emitter function for level minLevel. I.e. this is the
729:
 * creator of `log.info`, `log.error`, etc.
730:
 */
731:
function mkLogEmitter(minLevel) {
732:
    return function () {
733:
        var log = this;
734:
 
735:
        function mkRecord(args) {
736:
            var excludeFields;
737:
            if (args[0] instanceof Error) {
738:
                // `log.<level>(err, ...)`
739:
                fields = {err: errSerializer(args[0])};
740:
                excludeFields = {err: true};
741:
                if (args.length === 1) {
742:
                    msgArgs = [fields.err.message];
743:
                } else {
744:
                    msgArgs = Array.prototype.slice.call(args, 1);
745:
                }
746:
            } else if (typeof (args[0]) === 'string') {
747:
                // `log.<level>(msg, ...)`
748:
                fields = null;
749:
                msgArgs = Array.prototype.slice.call(args);
750:
            } else if (Buffer.isBuffer(args[0])) {  // `log.<level>(buf, ...)`
751:
                // Almost certainly an error, show `inspect(buf)`. See bunyan
752:
                // issue #35.
753:
                fields = null;
754:
                msgArgs = Array.prototype.slice.call(args);
755:
                msgArgs[0] = util.inspect(msgArgs[0]);
756:
            } else {  // `log.<level>(fields, msg, ...)`
757:
                fields = args[0];
758:
                msgArgs = Array.prototype.slice.call(args, 1);
759:
            }
760:
 
761:
            // Build up the record object.
762:
            var rec = objCopy(log.fields);
763:
            var level = rec.level = minLevel;
764:
            var recFields = (fields ? objCopy(fields) : null);
765:
            if (recFields) {
766:
                if (log.serializers) {
767:
                    log._applySerializers(recFields, excludeFields);
768:
                }
769:
                Object.keys(recFields).forEach(function (k) {
770:
                    rec[k] = recFields[k];
771:
                });
772:
            }
773:
            rec.msg = format.apply(log, msgArgs);
774:
            if (!rec.time) {
775:
                rec.time = (new Date());
776:
            }
777:
            // Get call source info
778:
            if (log.src && !rec.src) {
779:
                rec.src = getCaller3Info()
780:
            }
781:
            rec.v = LOG_VERSION;
782:
 
783:
            return rec;
784:
        };
785:
 
786:
        var fields = null;
787:
        var msgArgs = arguments;
788:
        var str = null;
789:
        var rec = null;
790:
        if (arguments.length === 0) {   // `log.<level>()`
791:
            return (this._level <= minLevel);
792:
        } else if (this._level > minLevel) {
793:
            /* pass through */
794:
        } else {
795:
            rec = mkRecord(msgArgs);
796:
            str = this._emit(rec);
797:
        }
798:
        probes && probes[minLevel].fire(function () {
799:
                return [ str ||
800:
                    (rec && log._emit(rec, true)) ||
801:
                    log._emit(mkRecord(msgArgs), true) ];
802:
        });
803:
    }
804:
}
805:
 
806:
 
807:
/**
808:
 * The functions below log a record at a specific level.
809:
 *
810:
 * Usages:
811:
 *    log.<level>()  -> boolean is-trace-enabled
812:
 *    log.<level>(<Error> err, [<string> msg, ...])
813:
 *    log.<level>(<string> msg, ...)
814:
 *    log.<level>(<object> fields, <string> msg, ...)
815:
 *
816:
 * where <level> is the lowercase version of the log level. E.g.:
817:
 *
818:
 *    log.info()
819:
 *
820:
 * @params fields {Object} Optional set of additional fields to log.
821:
 * @params msg {String} Log message. This can be followed by additional
822:
 *    arguments that are handled like
823:
 *    [util.format](http://nodejs.org/docs/latest/api/all.html#util.format).
824:
 */
825:
Logger.prototype.trace = mkLogEmitter(TRACE);
826:
Logger.prototype.debug = mkLogEmitter(DEBUG);
827:
Logger.prototype.info = mkLogEmitter(INFO);
828:
Logger.prototype.warn = mkLogEmitter(WARN);
829:
Logger.prototype.error = mkLogEmitter(ERROR);
830:
Logger.prototype.fatal = mkLogEmitter(FATAL);
831:
 
832:
 
833:
 
834:
//---- Standard serializers
835:
// A serializer is a function that serializes a JavaScript object to a
836:
// JSON representation for logging. There is a standard set of presumed
837:
// interesting objects in node.js-land.
838:
 
839:
Logger.stdSerializers = {};
840:
 
841:
// Serialize an HTTP request.
842:
Logger.stdSerializers.req = function req(req) {
843:
    if (!req || !req.connection)
844:
        return req;
845:
    return {
846:
        method: req.method,
847:
        url: req.url,
848:
        headers: req.headers,
849:
        remoteAddress: req.connection.remoteAddress,
850:
        remotePort: req.connection.remotePort
851:
    };
852:
    // Trailers: Skipping for speed. If you need trailers in your app, then
853:
    // make a custom serializer.
854:
    //if (Object.keys(trailers).length > 0) {
855:
    //  obj.trailers = req.trailers;
856:
    //}
857:
};
858:
 
859:
// Serialize an HTTP response.
860:
Logger.stdSerializers.res = function res(res) {
861:
    if (!res || !res.statusCode)
862:
        return res;
863:
    return {
864:
        statusCode: res.statusCode,
865:
        header: res._header
866:
    }
867:
};
868:
 
869:
 
870:
/*
871:
 * This function dumps long stack traces for exceptions having a cause()
872:
 * method. The error classes from
873:
 * [verror](https://github.com/davepacheco/node-verror) and
874:
 * [restify v2.0](https://github.com/mcavage/node-restify) are examples.
875:
 *
876:
 * Based on `dumpException` in
877:
 * https://github.com/davepacheco/node-extsprintf/blob/master/lib/extsprintf.js
878:
 */
879:
function getFullErrorStack(ex)
880:
{
881:
    var ret = ex.stack || ex.toString();
882:
    if (ex.cause && typeof (ex.cause) === 'function') {
883:
        var cex = ex.cause();
884:
        if (cex) {
885:
            ret += '\nCaused by: ' + getFullErrorStack(cex);
886:
        }
887:
    }
888:
    return (ret);
889:
}
890:
 
891:
// Serialize an Error object
892:
// (Core error properties are enumerable in node 0.4, not in 0.6).
893:
var errSerializer = Logger.stdSerializers.err = function err(err) {
894:
    if (!err || !err.stack)
895:
        return err;
896:
    var obj = {
897:
        message: err.message,
898:
        name: err.name,
899:
        stack: getFullErrorStack(err),
900:
        code: err.code,
901:
        signal: err.signal
902:
    }
903:
    return obj;
904:
};
905:
 
906:
 
907:
// A JSON stringifier that handles cycles safely.
908:
// Usage: JSON.stringify(obj, safeCycles())
909:
function safeCycles() {
910:
    var seen = [];
911:
    return function (key, val) {
912:
        if (!val || typeof (val) !== 'object') {
913:
            return val;
914:
        }
915:
        if (seen.indexOf(val) !== -1) {
916:
            return '[Circular]';
917:
        }
918:
        seen.push(val);
919:
        return val;
920:
    };
921:
}
922:
 
923:
 
924:
/**
925:
 * XXX
926:
 */
927:
if (mv) {
928:
 
929:
function RotatingFileStream(options) {
930:
    this.path = options.path;
931:
    this.stream = fs.createWriteStream(this.path,
932:
        {flags: 'a', encoding: 'utf8'});
933:
    this.count = (options.count == null ? 10 : options.count);
934:
    assert.ok(typeof (this.count) === 'number' && this.count >= 0);
935:
 
936:
    // Parse `options.period`.
937:
    if (options.period) {
938:
        // <number><scope> where scope is:
939:
        //    h   hours (at the start of the hour)
940:
        //    d   days (at the start of the day, i.e. just after midnight)
941:
        //    w   weeks (at the start of Sunday)
942:
        //    m   months (on the first of the month)
943:
        //    y   years (at the start of Jan 1st)
944:
        // with special values 'hourly' (1h), 'daily' (1d), "weekly" (1w),
945:
        // 'monthly' (1m) and 'yearly' (1y)
946:
        var period = {
947:
            'hourly': '1h',
948:
            'daily': '1d',
949:
            'weekly': '1w',
950:
            'monthly': '1m',
951:
            'yearly': '1y'
952:
        }[options.period] || options.period;
953:
        var m = /^([1-9][0-9]*)([hdwmy]|ms)$/.exec(period);
954:
        if (!m) {
955:
            throw new Error(format('invalid period: "%s"', options.period));
956:
        }
957:
        this.periodNum = Number(m[1]);
958:
        this.periodScope = m[2];
959:
    } else {
960:
        this.periodNum = 1;
961:
        this.periodScope = 'd';
962:
    }
963:
 
964:
    // TODO: template support for backup files
965:
    // template: <path to which to rotate>
966:
    //      default is %P.%n
967:
    //      '/var/log/archive/foo.log'  -> foo.log.%n
968:
    //      '/var/log/archive/foo.log.%n'
969:
    //      codes:
970:
    //          XXX support strftime codes (per node version of those)
971:
    //              or whatever module. Pick non-colliding for extra
972:
    //              codes
973:
    //          %P      `path` base value
974:
    //          %n      integer number of rotated log (1,2,3,...)
975:
    //          %d      datetime in YYYY-MM-DD_HH-MM-SS
976:
    //                      XXX what should default date format be?
977:
    //                          prior art? Want to avoid ':' in
978:
    //                          filenames (illegal on Windows for one).
979:
 
980:
    this.rotQueue = [];
981:
    this.rotating = false;
982:
    this._setupNextRot();
983:
}
984:
 
985:
util.inherits(RotatingFileStream, EventEmitter);
986:
 
987:
RotatingFileStream.prototype._setupNextRot = function () {
988:
    var self = this;
989:
    this.rotAt = this._nextRotTime();
990:
    this.timeout = setTimeout(
991:
        function () { self.rotate(); },
992:
        this.rotAt - Date.now());
993:
}
994:
 
995:
RotatingFileStream.prototype._nextRotTime = function _nextRotTime(first) {
996:
    var _DEBUG = false;
997:
    if (_DEBUG)
998:
        console.log('-- _nextRotTime: %s%s', this.periodNum, this.periodScope);
999:
    var d = new Date();
1000:
 
1001:
    if (_DEBUG) console.log('  now local: %s', d);
1002:
    if (_DEBUG) console.log('    now utc: %s', d.toISOString());
1003:
    var rotAt;
1004:
    switch (this.periodScope) {
1005:
    case 'ms':
1006:
        // Hidden millisecond period for debugging.
1007:
        if (this.rotAt) {
1008:
            rotAt = this.rotAt + this.periodNum;
1009:
        } else {
1010:
            rotAt = Date.now() + this.periodNum;
1011:
        }
1012:
        break;
1013:
    case 'h':
1014:
        if (this.rotAt) {
1015:
            rotAt = this.rotAt + this.periodNum * 60 * 60 * 1000;
1016:
        } else {
1017:
            // First time: top of the next hour.
1018:
            rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(),
1019:
                d.getUTCDate(), d.getUTCHours() + 1);
1020:
        }
1021:
        break;
1022:
    case 'd':
1023:
        if (this.rotAt) {
1024:
            rotAt = this.rotAt + this.periodNum * 24 * 60 * 60 * 1000;
1025:
        } else {
1026:
            // First time: start of tomorrow (i.e. at the coming midnight) UTC.
1027:
            rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(),
1028:
                d.getUTCDate() + 1);
1029:
        }
1030:
        break;
1031:
    case 'w':
1032:
        // Currently, always on Sunday morning at 00:00:00 (UTC).
1033:
        if (this.rotAt) {
1034:
            rotAt = this.rotAt + this.periodNum * 7 * 24 * 60 * 60 * 1000;
1035:
        } else {
1036:
            // First time: this coming Sunday.
1037:
            rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(),
1038:
                d.getUTCDate() + (7 - d.getUTCDay()));
1039:
        }
1040:
        break;
1041:
    case 'm':
1042:
        if (this.rotAt) {
1043:
            rotAt = Date.UTC(d.getUTCFullYear(),
1044:
                d.getUTCMonth() + this.periodNum, 1);
1045:
        } else {
1046:
            // First time: the start of the next month.
1047:
            rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 1);
1048:
        }
1049:
        break;
1050:
    case 'y':
1051:
        if (this.rotAt) {
1052:
            rotAt = Date.UTC(d.getUTCFullYear() + this.periodNum, 0, 1);
1053:
        } else {
1054:
            // First time: the start of the next year.
1055:
            rotAt = Date.UTC(d.getUTCFullYear() + 1, 0, 1);
1056:
        }
1057:
        break;
1058:
    default:
1059:
        assert.fail(format('invalid period scope: "%s"', this.periodScope));
1060:
    }
1061:
 
1062:
    if (_DEBUG) {
1063:
        console.log('  **rotAt**: %s (utc: %s)', rotAt,
1064:
            new Date(rotAt).toUTCString());
1065:
        var now = Date.now();
1066:
        console.log('        now: %s (%sms == %smin == %sh to go)',
1067:
            now,
1068:
            rotAt - now,
1069:
            (rotAt-now)/1000/60,
1070:
            (rotAt-now)/1000/60/60);
1071:
    }
1072:
    return rotAt;
1073:
};
1074:
 
1075:
RotatingFileStream.prototype.rotate = function rotate() {
1076:
    // XXX What about shutdown?
1077:
    var self = this;
1078:
    var _DEBUG = false;
1079:
 
1080:
    if (_DEBUG) console.log('-- [%s] rotating %s', new Date(), self.path);
1081:
    if (self.rotating) {
1082:
        throw new TypeError('cannot start a rotation when already rotating');
1083:
    }
1084:
    self.rotating = true;
1085:
 
1086:
    self.stream.end();  // XXX can do moves sync after this? test at high rate
1087:
 
1088:
    function del() {
1089:
        var toDel = self.path + '.' + String(n - 1);
1090:
        if (n === 0) {
1091:
            toDel = self.path;
1092:
        }
1093:
        n -= 1;
1094:
        if (_DEBUG) console.log('rm %s', toDel);
1095:
        fs.unlink(toDel, function (delErr) {
1096:
            //XXX handle err other than not exists
1097:
            moves();
1098:
        });
1099:
    }
1100:
 
1101:
    function moves() {
1102:
        if (self.count === 0 || n < 0) {
1103:
            return finish();
1104:
        }
1105:
        var before = self.path;
1106:
        var after = self.path + '.' + String(n);
1107:
        if (n > 0) {
1108:
            before += '.' + String(n - 1);
1109:
        }
1110:
        n -= 1;
1111:
        fs.exists(before, function (exists) {
1112:
            if (!exists) {
1113:
                moves();
1114:
            } else {
1115:
                if (_DEBUG) console.log('mv %s %s', before, after);
1116:
                mv(before, after, function (mvErr) {
1117:
                    if (mvErr) {
1118:
                        self.emit('error', mvErr);
1119:
                        finish(); // XXX finish here?
1120:
                    } else {
1121:
                        moves();
1122:
                    }
1123:
                });
1124:
            }
1125:
        })
1126:
    }
1127:
 
1128:
    function finish() {
1129:
        if (_DEBUG) console.log('open %s', self.path);
1130:
        self.stream = fs.createWriteStream(self.path,
1131:
            {flags: 'a', encoding: 'utf8'});
1132:
        var q = self.rotQueue, len = q.length;
1133:
        for (var i = 0; i < len; i++) {
1134:
            self.stream.write(q[i]);
1135:
        }
1136:
        self.rotQueue = [];
1137:
        self.rotating = false;
1138:
        self.emit('drain');
1139:
        self._setupNextRot();
1140:
    }
1141:
 
1142:
    var n = this.count;
1143:
    del();
1144:
};
1145:
 
1146:
RotatingFileStream.prototype.write = function write(s) {
1147:
    if (this.rotating) {
1148:
        this.rotQueue.push(s);
1149:
        return false;
1150:
    } else {
1151:
        return this.stream.write(s);
1152:
    }
1153:
};
1154:
 
1155:
RotatingFileStream.prototype.end = function end(s) {
1156:
    this.stream.end();
1157:
};
1158:
 
1159:
RotatingFileStream.prototype.destroy = function destroy(s) {
1160:
    this.stream.destroy();
1161:
};
1162:
 
1163:
RotatingFileStream.prototype.destroySoon = function destroySoon(s) {
1164:
    this.stream.destroySoon();
1165:
};
1166:
 
1167:
} /* if (mv) */
1168:
 
1169:
 
1170:
 
1171:
/**
1172:
 * RingBuffer is a Writable Stream that just stores the last N records in
1173:
 * memory.
1174:
 *
1175:
 * @param options {Object}, with the following fields:
1176:
 *
1177:
 *    - limit: number of records to keep in memory
1178:
 */
1179:
function RingBuffer(options) {
1180:
    this.limit = options && options.limit ? options.limit : 100;
1181:
    this.writable = true;
1182:
    this.records = [];
1183:
    EventEmitter.call(this);
1184:
}
1185:
 
1186:
util.inherits(RingBuffer, EventEmitter);
1187:
 
1188:
RingBuffer.prototype.write = function (record) {
1189:
    if (!this.writable)
1190:
        throw (new Error('RingBuffer has been ended already'));
1191:
 
1192:
    this.records.push(record);
1193:
 
1194:
    if (this.records.length > this.limit)
1195:
        this.records.shift();
1196:
 
1197:
    return (true);
1198:
};
1199:
 
1200:
RingBuffer.prototype.end = function () {
1201:
    if (arguments.length > 0)
1202:
        this.write.apply(this, Array.prototype.slice.call(arguments));
1203:
    this.writable = false;
1204:
};
1205:
 
1206:
RingBuffer.prototype.destroy = function () {
1207:
    this.writable = false;
1208:
    this.emit('close');
1209:
};
1210:
 
1211:
RingBuffer.prototype.destroySoon = function () {
1212:
    this.destroy();
1213:
};
1214:
 
1215:
 
1216:
//---- Exports
1217:
 
1218:
module.exports = Logger;
1219:
 
1220:
module.exports.TRACE = TRACE;
1221:
module.exports.DEBUG = DEBUG;
1222:
module.exports.INFO = INFO;
1223:
module.exports.WARN = WARN;
1224:
module.exports.ERROR = ERROR;
1225:
module.exports.FATAL = FATAL;
1226:
module.exports.resolveLevel = resolveLevel;
1227:
 
1228:
module.exports.VERSION = VERSION;
1229:
module.exports.LOG_VERSION = LOG_VERSION;
1230:
 
1231:
module.exports.createLogger = function createLogger(options) {
1232:
    return new Logger(options);
1233:
};
1234:
 
1235:
module.exports.RingBuffer = RingBuffer;
1236:
 
1237:
// Useful for custom `type == 'raw'` streams that may do JSON stringification
1238:
// of log records themselves. Usage:
1239:
//    var str = JSON.stringify(rec, bunyan.safeCycles());
1240:
module.exports.safeCycles = safeCycles;