function Logger(options, _childOptions, _childSimple) { xxx('Logger start:', options) if (!(this instanceof Logger)) { return new Logger(options, _childOptions); } // Input arg validation. var parent; if (_childOptions !== undefined) { parent = options; options = _childOptions; if (!(parent instanceof Logger)) { throw new TypeError( 'invalid Logger creation: do not pass a second arg'); } } if (!options) { throw new TypeError('options (object) is required'); } if (!parent) { if (!options.name) { throw new TypeError('options.name (string) is required'); } } else { if (options.name) { throw new TypeError( 'invalid options.name: child cannot set logger name'); } } if (options.stream && options.streams) { throw new TypeError('cannot mix "streams" and "stream" options'); } if (options.streams && !Array.isArray(options.streams)) { throw new TypeError('invalid options.streams: must be an array') } if (options.serializers && (typeof (options.serializers) !== 'object' || Array.isArray(options.serializers))) { throw new TypeError('invalid options.serializers: must be an object') } EventEmitter.call(this); // Fast path for simple child creation. if (parent && _childSimple) { // `_isSimpleChild` is a signal to stream close handling that this child // owns none of its streams. this._isSimpleChild = true; this._level = parent._level; this.streams = parent.streams; this.serializers = parent.serializers; this.src = parent.src; var fields = this.fields = {}; var parentFieldNames = Object.keys(parent.fields); for (var i = 0; i < parentFieldNames.length; i++) { var name = parentFieldNames[i]; fields[name] = parent.fields[name]; } var names = Object.keys(options); for (var i = 0; i < names.length; i++) { var name = names[i]; fields[name] = options[name]; } return; } // Start values. var self = this; if (parent) { this._level = parent._level; this.streams = []; for (var i = 0; i < parent.streams.length; i++) { var s = objCopy(parent.streams[i]); s.closeOnExit = false; // Don't own parent stream. this.streams.push(s); } this.serializers = objCopy(parent.serializers); this.src = parent.src; this.fields = objCopy(parent.fields); if (options.level) { this.level(options.level); } } else { this._level = Number.POSITIVE_INFINITY; this.streams = []; this.serializers = null; this.src = false; this.fields = {}; } if (!dtp && dtrace) { dtp = dtrace.createDTraceProvider('bunyan'); for (var level in levelFromName) { var probe; probes[levelFromName[level]] = probe = dtp.addProbe('log-' + level, 'char *'); // Explicitly add a reference to dtp to prevent it from being GC'd probe.dtp = dtp; } dtp.enable(); } // Handle *config* options (i.e. options that are not just plain data // for log records). if (options.stream) { self.addStream({ type: 'stream', stream: options.stream, closeOnExit: false, level: options.level }); } else if (options.streams) { options.streams.forEach(function (s) { self.addStream(s, options.level); }); } else if (parent && options.level) { this.level(options.level); } else if (!parent) { if (runtimeEnv === 'browser') { /* * In the browser we'll be emitting to console.log by default. * Any console.log worth its salt these days can nicely render ...
n/a
function RingBuffer(options) { this.limit = options && options.limit ? options.limit : 100; this.writable = true; this.records = []; EventEmitter.call(this); }
...
github.com/davepacheco)
Potential uses: Live debugging if a running process could inspect those
messages. One could dump recent log messages at a finer log level than is
typically logged on
[`uncaughtException`](http://nodejs.org/docs/latest/api/all.html#all_event_uncaughtexception).
var ringbuffer = new bunyan.RingBuffer({ limit: 100 });
var log = new bunyan({
name: 'foo',
streams: [{
type: 'raw',
stream: ringbuffer,
level: 'debug'
}]
...
function RotatingFileStream(options) { this.path = options.path; this.count = (options.count == null ? 10 : options.count); assert.equal(typeof (this.count), 'number', format('rotating-file stream "count" is not a number: %j (%s) in %j', this.count, typeof (this.count), this)); assert.ok(this.count >= 0, format('rotating-file stream "count" is not >= 0: %j in %j', this.count, this)); // Parse `options.period`. if (options.period) { // <number><scope> where scope is: // h hours (at the start of the hour) // d days (at the start of the day, i.e. just after midnight) // w weeks (at the start of Sunday) // m months (on the first of the month) // y years (at the start of Jan 1st) // with special values 'hourly' (1h), 'daily' (1d), "weekly" (1w), // 'monthly' (1m) and 'yearly' (1y) var period = { 'hourly': '1h', 'daily': '1d', 'weekly': '1w', 'monthly': '1m', 'yearly': '1y' }[options.period] || options.period; var m = /^([1-9][0-9]*)([hdwmy]|ms)$/.exec(period); if (!m) { throw new Error(format('invalid period: "%s"', options.period)); } this.periodNum = Number(m[1]); this.periodScope = m[2]; } else { this.periodNum = 1; this.periodScope = 'd'; } var lastModified = null; try { var fileInfo = fs.statSync(this.path); lastModified = fileInfo.mtime.getTime(); } catch (err) { // file doesn't exist } var rotateAfterOpen = false; if (lastModified) { var lastRotTime = this._calcRotTime(0); if (lastModified < lastRotTime) { rotateAfterOpen = true; } } // TODO: template support for backup files // template: <path to which to rotate> // default is %P.%n // '/var/log/archive/foo.log' -> foo.log.%n // '/var/log/archive/foo.log.%n' // codes: // XXX support strftime codes (per node version of those) // or whatever module. Pick non-colliding for extra // codes // %P `path` base value // %n integer number of rotated log (1,2,3,...) // %d datetime in YYYY-MM-DD_HH-MM-SS // XXX what should default date format be? // prior art? Want to avoid ':' in // filenames (illegal on Windows for one). this.stream = fs.createWriteStream(this.path, {flags: 'a', encoding: 'utf8'}); this.rotQueue = []; this.rotating = false; if (rotateAfterOpen) { this._debug('rotateAfterOpen -> call rotate()'); this.rotate(); } else { this._setupNextRot(); } }
n/a
function createLogger(options) { return new Logger(options); }
...
running under [NW.js](http://nwjs.io/). Contributions by Adam Lynch, Jeremy
Ruppel, and Aleksey Timchenko.
- [pull #318] Add `reemitErrorEvents` optional boolean for streams added to a
Bunyan logger to control whether an "error" event on the stream will be
re-emitted on the `Logger` instance.
var log = bunyan.createLogger({
name: 'foo',
streams: [
{
type: 'raw',
stream: new MyCustomStream(),
reemitErrorEvents: true
}
...
function resolveLevel(nameOrNum) { var level; var type = typeof (nameOrNum); if (type === 'string') { level = levelFromName[nameOrNum.toLowerCase()]; if (!level) { throw new Error(format('unknown level name: "%s"', nameOrNum)); } } else if (type !== 'number') { throw new TypeError(format('cannot resolve level: invalid arg (%s):', type, nameOrNum)); } else if (nameOrNum < 0 || Math.floor(nameOrNum) !== nameOrNum) { throw new TypeError(format('level is not a positive integer: %s', nameOrNum)); } else { level = nameOrNum; } return level; }
...
- [issue #38] Fix the default `bunyan` CLI output of a `req.body` that is an
object instead of a string.
## 0.13.3
- Export `bunyan.resolveLevel(NAME-OR-NUM)` to resolve a level name or number
to its log level number value:
> bunyan.resolveLevel('INFO')
30
> bunyan.resolveLevel('debug')
20
...
function safeCyclesSet() { var seen = new Set(); return function (key, val) { if (!val || typeof (val) !== 'object') { return val; } if (seen.has(val)) { return '[Circular]'; } seen.add(val); return val; }; }
...
See <https://github.com/trentm/node-bunyan#dtrace-support> for details. By
Bryan Cantrill.
## 0.14.6
- Export `bunyan.safeCycles()`. This may be useful for custom `type == "raw"
;`
streams that may do JSON stringification of log records themselves. Usage:
var str = JSON.stringify(rec, bunyan.safeCycles());
- [issue #49] Allow a `log.child()` to specify the level of inherited streams.
For example:
...
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function RingBuffer(options) { this.limit = options && options.limit ? options.limit : 100; this.writable = true; this.records = []; EventEmitter.call(this); }
...
github.com/davepacheco)
Potential uses: Live debugging if a running process could inspect those
messages. One could dump recent log messages at a finer log level than is
typically logged on
[`uncaughtException`](http://nodejs.org/docs/latest/api/all.html#all_event_uncaughtexception).
var ringbuffer = new bunyan.RingBuffer({ limit: 100 });
var log = new bunyan({
name: 'foo',
streams: [{
type: 'raw',
stream: ringbuffer,
level: 'debug'
}]
...
function EventEmitter() { EventEmitter.init.call(this); }
n/a
destroy = function () { this.writable = false; this.emit('close'); }
...
*/
Logger.prototype.reopenFileStreams = function () {
var self = this;
self.streams.forEach(function (s) {
if (s.type === 'file') {
if (s.stream) {
// Not sure if typically would want this, or more immediate
// `s.stream.destroy()`.
s.stream.end();
s.stream.destroySoon();
delete s.stream;
}
s.stream = fs.createWriteStream(s.path,
{flags: 'a', encoding: 'utf8'});
s.stream.on('error', function (err) {
...
destroySoon = function () { this.destroy(); }
...
var self = this;
self.streams.forEach(function (s) {
if (s.type === 'file') {
if (s.stream) {
// Not sure if typically would want this, or more immediate
// `s.stream.destroy()`.
s.stream.end();
s.stream.destroySoon();
delete s.stream;
}
s.stream = fs.createWriteStream(s.path,
{flags: 'a', encoding: 'utf8'});
s.stream.on('error', function (err) {
self.emit('error', err, s);
});
...
end = function () { if (arguments.length > 0) this.write.apply(this, Array.prototype.slice.call(arguments)); this.writable = false; }
...
- perhaps this would be a "buffered: true" option on the stream object
- then wrap the "stream" with a local class that handles the buffering
- to finish this, need the 'log.close' and `process.on('exit', ...)`
work that Trent has started.
- "canWrite" handling for full streams. Need to buffer a la log4js
- test file log with logadm rotation: does it handle that?
- test suite:
- test for a cloned logger double-`stream.end()` causing problems.
Perhaps the "closeOnExit" for existing streams should be false for
clones.
- test that a `log.clone(...)` adding a new field matching a serializer
works *and* that an existing field in the parent is not *re-serialized*.
- split out `bunyan` cli to a "bunyan" or "bunyan-reader" or "node-bunyan-reader"
as the basis for tools to consume bunyan logs. It can grow indep of node-bunyan
for generating the logs.
...
write = function (record) { if (!this.writable) throw (new Error('RingBuffer has been ended already')); this.records.push(record); if (this.records.length > this.limit) this.records.shift(); return (true); }
...
npm publish
.PHONY: docs
docs: toc
@[[ `which ronn` ]] || (echo "No 'ronn' on your PATH. Install with 'gem install ronn'" &&
; exit 2)
mkdir -p man/man1
ronn --style=toc --manual="bunyan manual" --date=$(shell git log -1 --pretty=format:%cd --date=short) --roff --html docs
/bunyan.1.ronn
python -c 'import sys; h = open("docs/bunyan.1.html").read(); h = h.replace(".mp dt.flush {float:left;width
:8ex}", ""); open("docs/bunyan.1.html", "w").write(
h)'
python -c 'import sys; h = open("docs/bunyan.1.html").read(); h = h.replace("</body>", "
;""<a href="https://github.com/trentm/node-bunyan"><img style="position: absolute; top:
0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="
;Fork me on GitHub"></a></body>"""); open("docs/bunyan.1.html", "w
x22;).write(h)'
@echo "# test with 'man ./docs/bunyan.1' and 'open ./docs/bunyan.1.html'"
# Re-generate the README.md table of contents.
toc:
./node_modules/.bin/markdown-toc -i README.md
...
function RotatingFileStream(options) { this.path = options.path; this.count = (options.count == null ? 10 : options.count); assert.equal(typeof (this.count), 'number', format('rotating-file stream "count" is not a number: %j (%s) in %j', this.count, typeof (this.count), this)); assert.ok(this.count >= 0, format('rotating-file stream "count" is not >= 0: %j in %j', this.count, this)); // Parse `options.period`. if (options.period) { // <number><scope> where scope is: // h hours (at the start of the hour) // d days (at the start of the day, i.e. just after midnight) // w weeks (at the start of Sunday) // m months (on the first of the month) // y years (at the start of Jan 1st) // with special values 'hourly' (1h), 'daily' (1d), "weekly" (1w), // 'monthly' (1m) and 'yearly' (1y) var period = { 'hourly': '1h', 'daily': '1d', 'weekly': '1w', 'monthly': '1m', 'yearly': '1y' }[options.period] || options.period; var m = /^([1-9][0-9]*)([hdwmy]|ms)$/.exec(period); if (!m) { throw new Error(format('invalid period: "%s"', options.period)); } this.periodNum = Number(m[1]); this.periodScope = m[2]; } else { this.periodNum = 1; this.periodScope = 'd'; } var lastModified = null; try { var fileInfo = fs.statSync(this.path); lastModified = fileInfo.mtime.getTime(); } catch (err) { // file doesn't exist } var rotateAfterOpen = false; if (lastModified) { var lastRotTime = this._calcRotTime(0); if (lastModified < lastRotTime) { rotateAfterOpen = true; } } // TODO: template support for backup files // template: <path to which to rotate> // default is %P.%n // '/var/log/archive/foo.log' -> foo.log.%n // '/var/log/archive/foo.log.%n' // codes: // XXX support strftime codes (per node version of those) // or whatever module. Pick non-colliding for extra // codes // %P `path` base value // %n integer number of rotated log (1,2,3,...) // %d datetime in YYYY-MM-DD_HH-MM-SS // XXX what should default date format be? // prior art? Want to avoid ':' in // filenames (illegal on Windows for one). this.stream = fs.createWriteStream(this.path, {flags: 'a', encoding: 'utf8'}); this.rotQueue = []; this.rotating = false; if (rotateAfterOpen) { this._debug('rotateAfterOpen -> call rotate()'); this.rotate(); } else { this._setupNextRot(); } }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function _calcRotTime(periodOffset) { this._debug('_calcRotTime: %s%s', this.periodNum, this.periodScope); var d = new Date(); this._debug(' now local: %s', d); this._debug(' now utc: %s', d.toISOString()); var rotAt; switch (this.periodScope) { case 'ms': // Hidden millisecond period for debugging. if (this.rotAt) { rotAt = this.rotAt + this.periodNum * periodOffset; } else { rotAt = Date.now() + this.periodNum * periodOffset; } break; case 'h': if (this.rotAt) { rotAt = this.rotAt + this.periodNum * 60 * 60 * 1000 * periodOffset; } else { // First time: top of the next hour. rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours() + periodOffset); } break; case 'd': if (this.rotAt) { rotAt = this.rotAt + this.periodNum * 24 * 60 * 60 * 1000 * periodOffset; } else { // First time: start of tomorrow (i.e. at the coming midnight) UTC. rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() + periodOffset); } break; case 'w': // Currently, always on Sunday morning at 00:00:00 (UTC). if (this.rotAt) { rotAt = this.rotAt + this.periodNum * 7 * 24 * 60 * 60 * 1000 * periodOffset; } else { // First time: this coming Sunday. var dayOffset = (7 - d.getUTCDay()); if (periodOffset < 1) { dayOffset = -d.getUTCDay(); } if (periodOffset > 1 || periodOffset < -1) { dayOffset += 7 * periodOffset; } rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() + dayOffset); } break; case 'm': if (this.rotAt) { rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + this.periodNum * periodOffset, 1); } else { // First time: the start of the next month. rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + periodOffset, 1); } break; case 'y': if (this.rotAt) { rotAt = Date.UTC(d.getUTCFullYear() + this.periodNum * periodOffset, 0, 1); } else { // First time: the start of the next year. rotAt = Date.UTC(d.getUTCFullYear() + periodOffset, 0, 1); } break; default: assert.fail(format('invalid period scope: "%s"', this.periodScope)); } if (this._debug()) { this._debug(' **rotAt**: %s (utc: %s)', rotAt, new Date(rotAt).toUTCString()); var now = Date.now(); this._debug(' now: %s (%sms == %smin == %sh to go)', now, rotAt - now, (rotAt-now)/1000/60, (rotAt-now)/1000/60/60); } return rotAt; }
...
lastModified = fileInfo.mtime.getTime();
}
catch (err) {
// file doesn't exist
}
var rotateAfterOpen = false;
if (lastModified) {
var lastRotTime = this._calcRotTime(0);
if (lastModified < lastRotTime) {
rotateAfterOpen = true;
}
}
// TODO: template support for backup files
// template: <path to which to rotate>
...
_debug = function () { // Set this to `true` to add debug logging. if (false) { if (arguments.length === 0) { return true; } var args = Array.prototype.slice.call(arguments); args[0] = '[' + (new Date().toISOString()) + ', ' + this.path + '] ' + args[0]; console.log.apply(this, args); } else { return false; } }
...
this.stream = fs.createWriteStream(this.path,
{flags: 'a', encoding: 'utf8'});
this.rotQueue = [];
this.rotating = false;
if (rotateAfterOpen) {
this._debug('rotateAfterOpen -> call rotate()');
this.rotate();
} else {
this._setupNextRot();
}
}
util.inherits(RotatingFileStream, EventEmitter);
...
_setRotationTimer = function () { var self = this; var delay = this.rotAt - Date.now(); // Cap timeout to Node's max setTimeout, see // <https://github.com/joyent/node/issues/8656>. var TIMEOUT_MAX = 2147483647; // 2^31-1 if (delay > TIMEOUT_MAX) { delay = TIMEOUT_MAX; } this.timeout = setTimeout( function () { self._debug('_setRotationTimer timeout -> call rotate()'); self.rotate(); }, delay); if (typeof (this.timeout.unref) === 'function') { this.timeout.unref(); } }
...
} else {
return false;
}
};
RotatingFileStream.prototype._setupNextRot = function () {
this.rotAt = this._calcRotTime(1);
this._setRotationTimer();
}
RotatingFileStream.prototype._setRotationTimer = function () {
var self = this;
var delay = this.rotAt - Date.now();
// Cap timeout to Node's max setTimeout, see
// <https://github.com/joyent/node/issues/8656>.
...
_setupNextRot = function () { this.rotAt = this._calcRotTime(1); this._setRotationTimer(); }
...
this.rotQueue = [];
this.rotating = false;
if (rotateAfterOpen) {
this._debug('rotateAfterOpen -> call rotate()');
this.rotate();
} else {
this._setupNextRot();
}
}
util.inherits(RotatingFileStream, EventEmitter);
RotatingFileStream.prototype._debug = function () {
// Set this to `true` to add debug logging.
...
function destroy(s) { this.stream.destroy(); }
...
*/
Logger.prototype.reopenFileStreams = function () {
var self = this;
self.streams.forEach(function (s) {
if (s.type === 'file') {
if (s.stream) {
// Not sure if typically would want this, or more immediate
// `s.stream.destroy()`.
s.stream.end();
s.stream.destroySoon();
delete s.stream;
}
s.stream = fs.createWriteStream(s.path,
{flags: 'a', encoding: 'utf8'});
s.stream.on('error', function (err) {
...
function destroySoon(s) { this.stream.destroySoon(); }
...
var self = this;
self.streams.forEach(function (s) {
if (s.type === 'file') {
if (s.stream) {
// Not sure if typically would want this, or more immediate
// `s.stream.destroy()`.
s.stream.end();
s.stream.destroySoon();
delete s.stream;
}
s.stream = fs.createWriteStream(s.path,
{flags: 'a', encoding: 'utf8'});
s.stream.on('error', function (err) {
self.emit('error', err, s);
});
...
function end(s) { this.stream.end(); }
...
- perhaps this would be a "buffered: true" option on the stream object
- then wrap the "stream" with a local class that handles the buffering
- to finish this, need the 'log.close' and `process.on('exit', ...)`
work that Trent has started.
- "canWrite" handling for full streams. Need to buffer a la log4js
- test file log with logadm rotation: does it handle that?
- test suite:
- test for a cloned logger double-`stream.end()` causing problems.
Perhaps the "closeOnExit" for existing streams should be false for
clones.
- test that a `log.clone(...)` adding a new field matching a serializer
works *and* that an existing field in the parent is not *re-serialized*.
- split out `bunyan` cli to a "bunyan" or "bunyan-reader" or "node-bunyan-reader"
as the basis for tools to consume bunyan logs. It can grow indep of node-bunyan
for generating the logs.
...
function rotate() { // XXX What about shutdown? var self = this; // If rotation period is > ~25 days, we have to break into multiple // setTimeout's. See <https://github.com/joyent/node/issues/8656>. if (self.rotAt && self.rotAt > Date.now()) { return self._setRotationTimer(); } this._debug('rotate'); if (self.rotating) { throw new TypeError('cannot start a rotation when already rotating'); } self.rotating = true; self.stream.end(); // XXX can do moves sync after this? test at high rate function del() { var toDel = self.path + '.' + String(n - 1); if (n === 0) { toDel = self.path; } n -= 1; self._debug(' rm %s', toDel); fs.unlink(toDel, function (delErr) { //XXX handle err other than not exists moves(); }); } function moves() { if (self.count === 0 || n < 0) { return finish(); } var before = self.path; var after = self.path + '.' + String(n); if (n > 0) { before += '.' + String(n - 1); } n -= 1; fs.exists(before, function (exists) { if (!exists) { moves(); } else { self._debug(' mv %s %s', before, after); mv(before, after, function (mvErr) { if (mvErr) { self.emit('error', mvErr); finish(); // XXX finish here? } else { moves(); } }); } }) } function finish() { self._debug(' open %s', self.path); self.stream = fs.createWriteStream(self.path, {flags: 'a', encoding: 'utf8'}); var q = self.rotQueue, len = q.length; for (var i = 0; i < len; i++) { self.stream.write(q[i]); } self.rotQueue = []; self.rotating = false; self.emit('drain'); self._setupNextRot(); } var n = this.count; del(); }
...
this.stream = fs.createWriteStream(this.path,
{flags: 'a', encoding: 'utf8'});
this.rotQueue = [];
this.rotating = false;
if (rotateAfterOpen) {
this._debug('rotateAfterOpen -> call rotate()');
this.rotate();
} else {
this._setupNextRot();
}
}
util.inherits(RotatingFileStream, EventEmitter);
...
function write(s) { if (this.rotating) { this.rotQueue.push(s); return false; } else { return this.stream.write(s); } }
...
npm publish
.PHONY: docs
docs: toc
@[[ `which ronn` ]] || (echo "No 'ronn' on your PATH. Install with 'gem install ronn'" &&
; exit 2)
mkdir -p man/man1
ronn --style=toc --manual="bunyan manual" --date=$(shell git log -1 --pretty=format:%cd --date=short) --roff --html docs
/bunyan.1.ronn
python -c 'import sys; h = open("docs/bunyan.1.html").read(); h = h.replace(".mp dt.flush {float:left;width
:8ex}", ""); open("docs/bunyan.1.html", "w").write(
h)'
python -c 'import sys; h = open("docs/bunyan.1.html").read(); h = h.replace("</body>", "
;""<a href="https://github.com/trentm/node-bunyan"><img style="position: absolute; top:
0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="
;Fork me on GitHub"></a></body>"""); open("docs/bunyan.1.html", "w
x22;).write(h)'
@echo "# test with 'man ./docs/bunyan.1' and 'open ./docs/bunyan.1.html'"
# Re-generate the README.md table of contents.
toc:
./node_modules/.bin/markdown-toc -i README.md
...
err = function (err) { if (!err || !err.stack) return err; var obj = { message: err.message, name: err.name, stack: getFullErrorStack(err), code: err.code, signal: err.signal } return obj; }
...
function mkRecord(log, minLevel, args) {
var excludeFields, fields, msgArgs;
if (args[0] instanceof Error) {
// `log.<level>(err, ...)`
fields = {
// Use this Logger's err serializer, if defined.
err: (log.serializers && log.serializers.err
? log.serializers.err(args[0])
: Logger.stdSerializers.err(args[0]))
};
excludeFields = {err: true};
if (args.length === 1) {
msgArgs = [fields.err.message];
} else {
msgArgs = args.slice(1);
...
req = function (req) { if (!req || !req.connection) return req; return { method: req.method, url: req.url, headers: req.headers, remoteAddress: req.connection.remoteAddress, remotePort: req.connection.remotePort }; // Trailers: Skipping for speed. If you need trailers in your app, then // make a custom serializer. //if (Object.keys(trailers).length > 0) { // obj.trailers = req.trailers; //} }
n/a
res = function (res) { if (!res || !res.statusCode) return res; return { statusCode: res.statusCode, header: res._header } }
n/a