issue #48: fix a couple issues with dtrace support

- before this, if there were no non-raw streams on the logger the
  `str` for the dtrace probe.fire would not be created
- ensure that with no non-raw streams we only render a record's
  JSON string if the dtrace probe is enabled
This commit is contained in:
Trent Mick 2012-10-31 22:17:44 -07:00
parent af5a3d4873
commit 2438b0b01c
2 changed files with 46 additions and 44 deletions

View file

@ -308,7 +308,7 @@ function Logger(options, _childOptions, _childSimple) {
for (var level in levelFromName) { for (var level in levelFromName) {
var probe; var probe;
probes[levelFromName[level]] = probe = probes[levelFromName[level]] = probe =
dtp.addProbe('log-' + level, 'char *'); dtp.addProbe('log-' + level, 'char *');
// Explicitly add a reference to dtp to prevent it from being GC'd // Explicitly add a reference to dtp to prevent it from being GC'd
@ -660,33 +660,12 @@ Logger.prototype._mkRecord = function (fields, level, msgArgs) {
* Emit a log record. * Emit a log record.
* *
* @param rec {log record} * @param rec {log record}
* @param noemit {Boolean} Optional. Set to true to only return the string. * @param noemit {Boolean} Optional. Set to true to skip emission
* and just return the JSON string.
*/ */
Logger.prototype._emit = function (rec, noemit) { Logger.prototype._emit = function (rec, noemit) {
var i; var i;
var obj = objCopy(rec[0]);
var level = obj.level = rec[2];
var recFields = rec[1];
if (recFields) {
if (this.serializers) {
this._applySerializers(recFields);
}
Object.keys(recFields).forEach(function (k) {
obj[k] = recFields[k];
});
}
xxx('Record:', rec)
obj.msg = format.apply(this, rec[3]);
if (!obj.time) {
obj.time = (new Date());
}
// Get call source info
if (this.src && !obj.src) {
obj.src = getCaller3Info()
}
obj.v = LOG_VERSION;
// Lazily determine if this Logger has non-"raw" streams. If there are // Lazily determine if this Logger has non-"raw" streams. If there are
// any, then we need to stringify the log record. // any, then we need to stringify the log record.
if (this.haveNonRawStreams === undefined) { if (this.haveNonRawStreams === undefined) {
@ -701,19 +680,20 @@ Logger.prototype._emit = function (rec, noemit) {
// Stringify the object. Attempt to warn/recover on error. // Stringify the object. Attempt to warn/recover on error.
var str; var str;
if (this.haveNonRawStreams) { if (noemit || this.haveNonRawStreams) {
str = JSON.stringify(obj, safeCycles()) + '\n'; str = JSON.stringify(rec, safeCycles()) + '\n';
} }
if (noemit) if (noemit)
return str; return str;
var level = rec.level;
for (i = 0; i < this.streams.length; i++) { for (i = 0; i < this.streams.length; i++) {
var s = this.streams[i]; var s = this.streams[i];
if (s.level <= level) { if (s.level <= level) {
xxx('writing log rec "%s" to "%s" stream (%d <= %d): %j', xxx('writing log rec "%s" to "%s" stream (%d <= %d): %j',
obj.msg, s.type, s.level, level, obj); rec.msg, s.type, s.level, level, rec);
s.stream.write(s.raw ? obj : str); s.stream.write(s.raw ? rec : str);
} }
}; };
@ -729,7 +709,7 @@ function mkLogEmitter(minLevel) {
return function () { return function () {
var log = this; var log = this;
var mkRecord = function (args) { function mkRecord(args) {
if (args[0] instanceof Error) { if (args[0] instanceof Error) {
// `log.<level>(err, ...)` // `log.<level>(err, ...)`
fields = {err: errSerializer(args[0])}; fields = {err: errSerializer(args[0])};
@ -750,27 +730,49 @@ function mkLogEmitter(minLevel) {
fields = args[0]; fields = args[0];
msgArgs = Array.prototype.slice.call(args, 1); msgArgs = Array.prototype.slice.call(args, 1);
} }
return log._mkRecord(fields, minLevel, msgArgs);
// Build up the record object.
var rec = objCopy(log.fields);
var level = rec.level = minLevel;
var recFields = (fields ? objCopy(fields) : null);
if (recFields) {
if (log.serializers) {
log._applySerializers(recFields);
}
Object.keys(recFields).forEach(function (k) {
rec[k] = recFields[k];
});
}
rec.msg = format.apply(log, msgArgs);
if (!rec.time) {
rec.time = (new Date());
}
// Get call source info
if (log.src && !rec.src) {
rec.src = getCaller3Info()
}
rec.v = LOG_VERSION;
return rec;
}; };
var fields = null, msgArgs = null; var fields = null;
var msgArgs = arguments;
var str = null;
var rec = null;
if (arguments.length === 0) { // `log.<level>()` if (arguments.length === 0) { // `log.<level>()`
return (this._level <= minLevel); return (this._level <= minLevel);
} else if (this._level > minLevel) { } else if (this._level > minLevel) {
/* /* pass through */
* Even if our level is such that we will not emit the record, we want
* to fire the DTrace probe associated with the level -- but we only
* assemble the string representation if the probe is in fact enabled.
*/
msgArgs = arguments;
probes[minLevel].fire(function () {
return [ log._emit(mkRecord(msgArgs), true) ];
});
} else { } else {
var str = this._emit(mkRecord(arguments)); rec = mkRecord(msgArgs);
probes[minLevel].fire(function () { return [ str ]; }); str = this._emit(rec);
} }
probes[minLevel].fire(function () {
return [ str ||
(rec && log._emit(rec, true)) ||
log._emit(mkRecord(msgArgs), true) ];
});
} }
} }

View file

@ -16,7 +16,7 @@
"keywords": ["log", "logging", "log4j", "json"], "keywords": ["log", "logging", "log4j", "json"],
"dependencies": { "dependencies": {
"dtrace-provider": "0.2.2" "dtrace-provider": "0.2.3"
}, },
"devDependencies": { "devDependencies": {
"tap": "0.2.0", "tap": "0.2.0",