Comparing version 0.1.0 to 0.2.0
169
lib/log.js
"use strict"; | ||
var colors = require( "colors" ); | ||
var Type = require( "type-of-is" ); | ||
var util = require( "util" ); | ||
@@ -20,3 +20,3 @@ /** | ||
* The last message that was logged. | ||
* @type {String} | ||
* @type {Object} | ||
*/ | ||
@@ -32,2 +32,14 @@ var lastMessage; | ||
/** | ||
* An object that will not have its source traced when it's logged. | ||
* @param {String} message The message to log | ||
* @constructor | ||
*/ | ||
function Untraceable( message ) { | ||
this.message = message; | ||
} | ||
Untraceable.prototype.toString = function() { | ||
return this.message; | ||
} | ||
/** | ||
* Determines if a given message should be logged. The purpose is to avoid logging the same message continously. | ||
@@ -37,4 +49,4 @@ * @param {String} message The message being logged. | ||
*/ | ||
var shouldLog = function( message ) { | ||
if( message == lastMessage ) { | ||
var shouldLog = function( level, logger, message ) { | ||
if( lastMessage&& message == lastMessage.message && level == lastMessage.level && logger == lastMessage.logger ) { | ||
++lastMessageRepeated; | ||
@@ -45,7 +57,7 @@ return false; | ||
lastMessage = undefined; | ||
lastLogger( "Last message repeated " + lastMessageRepeated + " times." ); | ||
lastLogger( new Untraceable( "Last message repeated " + lastMessageRepeated + " times." ) ); | ||
lastMessageRepeated = 0; | ||
} else { | ||
lastMessage = message; | ||
lastMessage = {level : level, logger : logger, message : message}; | ||
} | ||
@@ -111,19 +123,2 @@ return true; | ||
var generateLogStack = function( level, prefix, subject, colorizer ) { | ||
var lines = subject.split( "\n" ); | ||
// Most common case, a single line. | ||
if( lines.count == 1 ) { | ||
return colorizer( level + " " + prefixMessage( prefix, subject ) ); | ||
} | ||
// Multiple lines, prepare them all nice like. | ||
for( var lineIndex = 0, lineCount = lines.length; lineIndex < lineCount; ++lineIndex ) { | ||
lines[lineIndex] = colorizer( level + " " + prefixMessage( prefix, lines[ lineIndex ], lineIndex > 0 ) ); | ||
// Replace the level prefix with whitespace for further lines | ||
if( 0 == lineIndex ) { | ||
level = pad( "", level.length, " " ); | ||
} | ||
} | ||
return 1 < lines.length ? lines : lines[ 0 ]; | ||
}; | ||
/** | ||
@@ -134,3 +129,3 @@ * Log a debug message. | ||
Logger.prototype.debug = function( message ) { | ||
preLog( "[DEBUG ]", this.prefix, colors.grey, this.debug.bind( this ), message ); | ||
preLog( "[DEBUG ]", this, colors.grey, this.debug.bind( this ), message ); | ||
}; | ||
@@ -142,3 +137,3 @@ /** | ||
Logger.prototype.info = function( message ) { | ||
preLog( "[INFO ]", this.prefix, colors.cyan, this.info.bind( this ), message ); | ||
preLog( "[INFO ]", this, colors.cyan, this.info.bind( this ), message ); | ||
}; | ||
@@ -150,3 +145,3 @@ /** | ||
Logger.prototype.notice = function( message ) { | ||
preLog( "[NOTICE]", this.prefix, colors.green, this.notice.bind( this ), message ); | ||
preLog( "[NOTICE]", this, colors.green, this.notice.bind( this ), message ); | ||
}; | ||
@@ -158,3 +153,3 @@ /** | ||
Logger.prototype.warn = function( message ) { | ||
preLog( "[WARN ]", this.prefix, colors.yellow, this.warn.bind( this ), message ); | ||
preLog( "[WARN ]", this, colors.yellow, this.warn.bind( this ), message ); | ||
}; | ||
@@ -166,3 +161,3 @@ /** | ||
Logger.prototype.error = function( message ) { | ||
preLog( "[ERROR ]", this.prefix, colors.red, this.error.bind( this ), message ); | ||
preLog( "[ERROR ]", this, colors.red, this.error.bind( this ), message ); | ||
}; | ||
@@ -174,3 +169,3 @@ /** | ||
Logger.prototype.critical = function( message ) { | ||
preLog( "[CRITIC]", this.prefix, function( str ) {return colors.bold( colors.red( str ) ); }, this.critical.bind( this ), message ); | ||
preLog( "[CRITIC]", this, function( str ) {return colors.bold( colors.red( str ) ); }, this.critical.bind( this ), message ); | ||
}; | ||
@@ -183,5 +178,18 @@ | ||
/** | ||
* Pre-processes a logging subject. Like breaking it into further subjects or grabbing stacks from Errors. | ||
* @param {String} level The log level indicator. | ||
* @param {Logger} logger The logger that called this function. | ||
* @param {Function} colorizer A function to be used to colorize the output. | ||
* @param {Function} more A callback to use when further output needs to be logged. | ||
* @param {String} message The subject that should be logged. | ||
*/ | ||
var preLog = function( level, logger, colorizer, more, message ) { | ||
if( !shouldLog( level, logger, message ) ) { | ||
return; | ||
} | ||
lastLogger = more; | ||
var preLog = function( level, prefix, colorizer, more, message ) { | ||
if( Type.is( message, Error ) ) { | ||
// If the supplied subject is an Error instance, grab the call stack and log that instead. | ||
if( util.isError( message ) ) { | ||
/** @type {Error} */ | ||
@@ -192,18 +200,83 @@ var error = message; | ||
} | ||
var toLog = generateLogStack( level, prefix, message, colorizer ); | ||
log( toLog, more ); | ||
} | ||
// Break up the logging subject into multiple lines as appropriate. | ||
var toLog = generateLogStack( level, logger, message, colorizer ); | ||
log( toLog ); | ||
}; | ||
var analyzeStack = function( stack ) { | ||
/** | ||
* Group 1: Function name (optional) | ||
* Group 2: File name | ||
* Group 3: Line | ||
* Group 4: Column | ||
*/ | ||
var callSitePattern = new RegExp( /at (?:(.*) )?\(?(.*):(\d+):(\d+)\)?/g ); | ||
var sites = stack.match( callSitePattern ); | ||
// The method that invoked the logger is located at index 3 of the stack | ||
if( sites && 3 <= sites.length ) { | ||
var callSiteElementPattern = new RegExp( /at (?:(.*) )?\(?(.*):(\d+):(\d+)\)?/ ); | ||
// Pick apart | ||
var callSiteElements = sites[ 3 ].match( callSiteElementPattern ); | ||
var functionName, fileName, line, column; | ||
// Assume either 4 (no function name) or 5 elements. | ||
if( callSiteElements.length == 5 ) { | ||
functionName = callSiteElements[ 1 ]; | ||
fileName = callSiteElements[ 2 ]; | ||
line = callSiteElements[ 3 ]; | ||
column = callSiteElements[ 4 ]; | ||
} else { | ||
functionName = "(unnamed)"; | ||
fileName = callSiteElements[ 1 ]; | ||
line = callSiteElements[ 2 ]; | ||
column = callSiteElements[ 3 ]; | ||
} | ||
return functionName + "@" + fileName + ":" + line + ":" + column; | ||
} | ||
return null; | ||
}; | ||
/** | ||
* For a given input, generates a stack of lines that should be logged. | ||
* @param {String} level The log level indicator. | ||
* @param {Logger} logger The logger that invoked this function. | ||
* @param {String} subject The subject that should be logged. | ||
* @param {Function} colorizer A function to be used to colorize the output. | ||
* @returns {Array|String} Either a single string to log, or an array of strings to log. | ||
*/ | ||
var generateLogStack = function( level, logger, subject, colorizer ) { | ||
var lines = subject.toString().split( "\n" ); | ||
// If we're supposed to trace the call sites, grab the location here. | ||
if( logger.traceLoggingCalls && !( subject instanceof Untraceable ) ) { | ||
var stack = new Error().stack; | ||
var location = analyzeStack( stack ); | ||
lines.push( " " + location ); | ||
} | ||
// Most common case, a single line. | ||
if( lines.count == 1 ) { | ||
return colorizer( level + " " + prefixMessage( logger.prefix, subject ) ); | ||
} | ||
// Multiple lines, prepare them all nice like. | ||
for( var lineIndex = 0, lineCount = lines.length; lineIndex < lineCount; ++lineIndex ) { | ||
lines[lineIndex] = colorizer( level + " " + prefixMessage( logger.prefix, lines[ lineIndex ], lineIndex > 0 ) ); | ||
// Replace the level prefix with whitespace for lines other than the first | ||
if( 0 == lineIndex ) { | ||
level = pad( "", level.length, " " ); | ||
} | ||
} | ||
return 1 < lines.length ? lines : lines[ 0 ]; | ||
}; | ||
/** | ||
* Log a message. | ||
* @param {String} message The message to log. | ||
*/ | ||
var log = function( message, more ) { | ||
if( !shouldLog( message ) ) { | ||
return; | ||
} | ||
lastLogger = more; | ||
var log = function( message ) { | ||
var time = new Date(); | ||
var timestamp = formatDate( time ); | ||
if( Type.is( message, Array ) ) { | ||
if( util.isArray( message ) ) { | ||
for( var messageIndex = 0, messageCount = message.length; messageIndex < messageCount; ++messageIndex ) { | ||
@@ -228,2 +301,11 @@ console.log( timestamp + " " + message[ messageIndex ] ); | ||
/** | ||
* Enable or disable debug output. | ||
* @param {Boolean} [enable=true] Should debug output be enabled? | ||
*/ | ||
Logger.prototype.withSource = function( enable ) { | ||
this.traceLoggingCalls = !!!enable; | ||
return this; | ||
} | ||
/** | ||
* Construct a new Logger instance for a module with the given name. | ||
@@ -234,2 +316,9 @@ * @param {String} [moduleName] The name of the module. | ||
Logger.fromModule = function( moduleName ) { | ||
if( !moduleName ) { | ||
var error = new Error().stack; | ||
var matches = error.match( /at Object.<anonymous> .*[\\/](.*?):/ ); | ||
if( matches && matches.length >= 2 ) { | ||
moduleName = matches[ 1 ]; | ||
} | ||
} | ||
if( moduleName ) { | ||
@@ -236,0 +325,0 @@ moduleMaxLength = Math.max( moduleMaxLength, moduleName.length ); |
{ | ||
"name": "fm-log", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "Console logging facility for Node", | ||
@@ -31,5 +31,4 @@ "main": "lib/log.js", | ||
"dependencies": { | ||
"colors": "^0.6.2", | ||
"type-of-is": "^3.2.0" | ||
"colors": "^0.6.2" | ||
} | ||
} |
@@ -21,6 +21,11 @@ fm-log | ||
- displays the source of the logging call when included like: | ||
var log = require().withSource(); | ||
var log = require().module().withSource(); | ||
Example | ||
------- | ||
var log = require( "fm-log" ).module( path.basename( __filename ) ); | ||
var log = require( "fm-log" ).module(); | ||
log.info( "Initializing application..." ); | ||
@@ -45,3 +50,3 @@ | ||
var log = require( "fm-log" ).module( path.basename( __filename ) ); | ||
var log = require( "fm-log" ).module(); | ||
@@ -48,0 +53,0 @@ Then just use `log.info` or one of the other logging levels shown above. |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
73769
1
419
56
0
- Removedtype-of-is@^3.2.0
- Removedtype-of-is@3.5.1(transitive)