pixl-logger
Advanced tools
Comparing version 1.0.9 to 1.0.10
// Generic Logger Class for Node.JS | ||
// Copyright (c) 2012, 2014, 2015 Joseph Huckaby | ||
// Copyright (c) 2012 - 2017 Joseph Huckaby and PixlCore.com | ||
// Released under the MIT License | ||
@@ -22,10 +22,15 @@ | ||
pather: null, | ||
filter: null, | ||
serializer: null, | ||
echoer: null, | ||
__construct: function(path, columns, args) { | ||
// create new logger instance | ||
var self = this; | ||
this.path = path; | ||
this.columns = columns; | ||
this.args = args ? Tools.copyHash(args, true) : {}; | ||
if (!this.args.pid) this.args.pid = process.pid; | ||
if (!this.args.debugLevel) this.args.debugLevel = 1; | ||
@@ -35,4 +40,13 @@ if (!this.args.hostname) { | ||
} | ||
if (!this.args.pid) this.args.pid = process.pid; | ||
// pass hooks in args | ||
['pather', 'filter', 'serializer', 'echoer'].forEach( function(key) { | ||
if (self.args[key]) { | ||
self[key] = self.args[key]; | ||
delete self.args[key]; | ||
} | ||
}); | ||
}, | ||
get: function(key) { | ||
@@ -42,13 +56,14 @@ // get one arg, or all of them | ||
}, | ||
set: function() { | ||
// set one or more args, pass in key,value or args obj | ||
if (arguments.length == 2) { | ||
this.args[ arguments[0] ] = arguments[1]; | ||
if (arguments[0].toString().match(/^(pather|filter|serializer|echoer)$/)) this[arguments[0]] = arguments[1]; | ||
else this.args[ arguments[0] ] = arguments[1]; | ||
} | ||
else if (arguments.length == 1) { | ||
for (var key in arguments[0]) this.args[key] = arguments[0][key]; | ||
for (var key in arguments[0]) this.set(key, arguments[0][key]); | ||
} | ||
}, | ||
print: function(args) { | ||
@@ -69,10 +84,2 @@ // setup date/time stuff | ||
// support json 'data' arg | ||
if (this.args.data) { | ||
if (typeof(this.args.data) == 'object') { | ||
this.args.data = JSON.stringify( this.args.data ); | ||
} | ||
} | ||
else this.args.data = ''; | ||
// populate columns | ||
@@ -83,8 +90,16 @@ var cols = []; | ||
var val = this.args[col]; | ||
if ((typeof(val) == 'undefined') || (val === null) || !val.toString) val = ''; | ||
cols.push( val.toString().replace(/[\r\n]/g, ' ').replace(/\]\[/g, '') ); | ||
if (this.filter) { | ||
cols.push( this.filter(val, idx) ); | ||
} | ||
else { | ||
if (typeof(val) == 'object') val = JSON.stringify(val); | ||
cols.push( val.toString().replace(/[\r\n]/g, ' ').replace(/\]\[/g, '') ); | ||
} | ||
} | ||
// compose log row | ||
var line = '[' + cols.join('][') + "]\n"; | ||
var line = this.serializer ? this.serializer(cols, this.args) : ('[' + cols.join('][') + "]\n"); | ||
this.lastRow = line; | ||
@@ -94,3 +109,6 @@ | ||
var path = this.path; | ||
if (path.indexOf('[') > -1) { | ||
if (this.pather) { | ||
path = this.pather( path, this.args ); | ||
} | ||
else if (path.indexOf('[') > -1) { | ||
path = Tools.substitute( path, this.args ); | ||
@@ -105,3 +123,6 @@ } | ||
if (this.args.echo) { | ||
if (this.args.color) { | ||
if (this.echoer) { | ||
this.echoer( line, cols, this.args ); | ||
} | ||
else if (this.args.color) { | ||
var ccols = []; | ||
@@ -123,3 +144,3 @@ var nclrs = this.columnColors.length; | ||
}, | ||
debug: function(level, msg, data) { | ||
@@ -137,3 +158,3 @@ // simple debug log implementation, expects 'code' and 'msg' named columns in log | ||
}, | ||
error: function(code, msg, data) { | ||
@@ -148,3 +169,3 @@ // simple error log implementation, expects 'code' and 'msg' named columns in log | ||
}, | ||
transaction: function(code, msg, data) { | ||
@@ -151,0 +172,0 @@ // simple debug log implementation, expects 'code' and 'msg' named columns in log |
{ | ||
"name": "pixl-logger", | ||
"version": "1.0.9", | ||
"version": "1.0.10", | ||
"description": "A simple logging class which generates [bracket][delimited] log columns.", | ||
@@ -5,0 +5,0 @@ "author": "Joseph Huckaby <jhuckaby@gmail.com>", |
206
README.md
@@ -10,3 +10,3 @@ # Overview | ||
``` | ||
npm install pixl-logger | ||
npm install pixl-logger | ||
``` | ||
@@ -17,3 +17,3 @@ | ||
```javascript | ||
var Logger = require('pixl-logger'); | ||
var Logger = require('pixl-logger'); | ||
``` | ||
@@ -24,12 +24,12 @@ | ||
```javascript | ||
var columns = ['hires_epoch', 'date', 'hostname', 'component', 'category', 'code', 'msg', 'data']; | ||
var logger = new Logger( 'logs/debug.log', columns ); | ||
logger.set('hostname', 'myserver.com'); | ||
logger.print({ | ||
category: 'debug', | ||
component: 'main', | ||
code: 1, | ||
msg: "Hello log!" | ||
}); | ||
var columns = ['hires_epoch', 'date', 'hostname', 'component', 'category', 'code', 'msg', 'data']; | ||
var logger = new Logger( 'logs/debug.log', columns ); | ||
logger.set('hostname', 'myserver.com'); | ||
logger.print({ | ||
category: 'debug', | ||
component: 'main', | ||
code: 1, | ||
msg: "Hello log!" | ||
}); | ||
``` | ||
@@ -40,3 +40,3 @@ | ||
``` | ||
[1423462332.437][2015-02-08 22:12:12][myserver.com][main][debug][1][Hello log!][] | ||
[1423462332.437][2015-02-08 22:12:12][myserver.com][main][debug][1][Hello log!][] | ||
``` | ||
@@ -49,9 +49,9 @@ | ||
```javascript | ||
logger.set('component', 'main'); | ||
logger.set('category', 'debug'); | ||
logger.print({ | ||
code: 1, | ||
msg: "Hello log!" | ||
}); | ||
logger.set('component', 'main'); | ||
logger.set('category', 'debug'); | ||
logger.print({ | ||
code: 1, | ||
msg: "Hello log!" | ||
}); | ||
``` | ||
@@ -66,3 +66,3 @@ | ||
```javascript | ||
logger.debug( 1, "This won't go well\n[Hi][There]\r\nGoodbye.\n" ); | ||
logger.debug( 1, "This won't go well\n[Hi][There]\r\nGoodbye.\n" ); | ||
``` | ||
@@ -73,3 +73,3 @@ | ||
``` | ||
[1423466726.159][2015-02-08 23:25:26][myserver.com][main][debug][1][This won't go well [HiThere] Goodbye. ] | ||
[1423466726.159][2015-02-08 23:25:26][myserver.com][main][debug][1][This won't go well [HiThere] Goodbye. ] | ||
``` | ||
@@ -86,4 +86,4 @@ | ||
```javascript | ||
logger.debug( 1, "Logged at debug level 1" ); | ||
logger.debug( 2, "Logged at debug level 2", {some:"data"} ); | ||
logger.debug( 1, "Logged at debug level 1" ); | ||
logger.debug( 2, "Logged at debug level 2", {some:"data"} ); | ||
``` | ||
@@ -94,7 +94,7 @@ | ||
```javascript | ||
logger.set( 'debugLevel', 2 ); | ||
logger.debug( 1, "Logged at debug level 1" ); | ||
logger.debug( 2, "Logged at debug level 2" ); | ||
logger.debug( 3, "This won't be logged at all!" ); | ||
logger.set( 'debugLevel', 2 ); | ||
logger.debug( 1, "Logged at debug level 1" ); | ||
logger.debug( 2, "Logged at debug level 2" ); | ||
logger.debug( 3, "This won't be logged at all!" ); | ||
``` | ||
@@ -109,3 +109,3 @@ | ||
```javascript | ||
logger.error( 1005, "An error of type 1005 occurred!" ); | ||
logger.error( 1005, "An error of type 1005 occurred!" ); | ||
``` | ||
@@ -116,7 +116,7 @@ | ||
```javascript | ||
logger.print({ | ||
category: 'error', | ||
code: 1005, | ||
msg: "An error of type 1005 occurred!" | ||
}); | ||
logger.print({ | ||
category: 'error', | ||
code: 1005, | ||
msg: "An error of type 1005 occurred!" | ||
}); | ||
``` | ||
@@ -129,3 +129,3 @@ | ||
```javascript | ||
logger.transaction( "user_update", "User jhuckaby was updated", {username:"jhuckaby"} ); | ||
logger.transaction( "user_update", "User jhuckaby was updated", {username:"jhuckaby"} ); | ||
``` | ||
@@ -136,8 +136,8 @@ | ||
```javascript | ||
logger.print({ | ||
category: 'transaction', | ||
code: "user_update", | ||
msg: "User jhuckaby was updated", | ||
data: {username:"jhuckaby"} | ||
}); | ||
logger.print({ | ||
category: 'transaction', | ||
code: "user_update", | ||
msg: "User jhuckaby was updated", | ||
data: {username:"jhuckaby"} | ||
}); | ||
``` | ||
@@ -150,4 +150,4 @@ | ||
```javascript | ||
logger.set( 'echo', true ); | ||
logger.debug( 1, "This will be logged and echoed to the console!" ); | ||
logger.set( 'echo', true ); | ||
logger.debug( 1, "This will be logged and echoed to the console!" ); | ||
``` | ||
@@ -164,5 +164,5 @@ | ||
```javascript | ||
logger.set( 'echo', true ); | ||
logger.set( 'color', true ); | ||
logger.debug( 1, "This will be colored in the console!" ); | ||
logger.set( 'echo', true ); | ||
logger.set( 'color', true ); | ||
logger.debug( 1, "This will be colored in the console!" ); | ||
``` | ||
@@ -177,3 +177,3 @@ | ||
```javascript | ||
var line = logger.lastRow; | ||
var line = logger.lastRow; | ||
``` | ||
@@ -190,3 +190,3 @@ | ||
``` | ||
[1423433821] | ||
[1423433821] | ||
``` | ||
@@ -199,3 +199,3 @@ | ||
``` | ||
[1423433807.277] | ||
[1423433807.277] | ||
``` | ||
@@ -208,11 +208,19 @@ | ||
``` | ||
[2015-02-08 14:16:58] | ||
[2015-02-08 14:16:58] | ||
``` | ||
### hostname | ||
Any column named `hostname` will automatically be populated with the server's hostname, obtained by calling [os.hostname()](https://nodejs.org/api/os.html#os_os_hostname) once at construction. Example: | ||
``` | ||
[host01.mydomain.com] | ||
``` | ||
### pid | ||
Any column named `pid` will automatically be populated with the current Process ID (PID), obtained by calling [process.pid](http://nodejs.org/api/process.html#process_process_pid) once at startup. Example: | ||
Any column named `pid` will automatically be populated with the current Process ID (PID), obtained by calling [process.pid](http://nodejs.org/api/process.html#process_process_pid) once at construction. Example: | ||
``` | ||
[13702] | ||
[13702] | ||
``` | ||
@@ -225,3 +233,3 @@ | ||
``` | ||
[{"code":0,"description":"Success"}] | ||
[{"code":0,"description":"Success"}] | ||
``` | ||
@@ -233,2 +241,58 @@ | ||
## Special Hooks | ||
There are a number of optional hooks available for you to customize your logs even further. These can be specified in the `args` object passed to the constructor, by calling `set()`, or simply by setting them on an instance object. | ||
### pather | ||
The `pather` hook allows you to intercept and alter the log path on disk per each log row, and generate your own path based on the current `args` passed to the logger. Using this you can change the log file per each log row. Your hook function is passed the current path, and the current `args` object containing all the column keys/values. Example: | ||
```js | ||
logger.pather = function(path, args) { | ||
return '/var/log/MyApp-' + args.category + '.log'; | ||
}; | ||
``` | ||
In this example the `category` column is used to dynamically construct the log filename. So if the `category` column was set to `debug`, the log path would be `/var/log/MyApp-debug.log`. This is a great way to generate multiple logs based on any criteria you want. | ||
### filter | ||
The `filter` hook allows you to intercept each log column value as it is being added to the columns array for serialization. This is typically where column values are stripped of any illegal characters, and whitespace compressed. If you specify this hook, the default cleansing operation does not take place, and your function is expected to do all the filtering necessary. Your hook function is called *for each column* in each row, so keep that in mind for performance purposes, and passed the current column value, and its array index. Example: | ||
```js | ||
logger.filter = function(value, idx) { | ||
if (typeof(value) == 'object') value = JSON.stringify(value); | ||
return value.toString().replace(/[\r\n]/g, ' ').replace(/\]\[/g, ''); | ||
}; | ||
``` | ||
Note that it is up to your filter function to convert objects into strings here, if you are trying to log any raw objects. | ||
### serializer | ||
The `serializer` hook allows you to intercept the log columns just as they are being serialized into a string for appending to your log file. Using this you can completely change how your log file is formatted. The default format is `[bracket][delimited][rows]` but you can serialize columns into any format of string you want. Your function is passed the current columns array (filtered) and the `args` object. For example, here is how to produce a CSV (comma-separated) log: | ||
```js | ||
logger.serializer = function(cols, args) { | ||
return cols.join(',') + "\n"; | ||
}; | ||
``` | ||
Your serializer function is expected to return a full formatted log row (line) ending in a EOL character. | ||
### echoer | ||
The `echoer` hook allows you to control exactly how your log is echoed to the console, if [Echo to Console](#echo-to-console) mode is enabled. The default behavior is to simply reprint the formatted log line to STDOUT, in addition to appending it to your log file. However, if you specify the `echoer` hook, this no longer happens, and instead your function is expected to do the echoing. The function is passed the formatted log line string (already appended to the log file), the array of columns that were serialized (these are filtered), and the current `args` object. Example: | ||
```js | ||
logger.echoer = function(line, cols, args) { | ||
console.log( args.category + ": " + args.msg ); | ||
if (args.data) console.dir(args.data); | ||
}; | ||
``` | ||
In this example we are only echoing certain columns to the console (just `category` and `msg`) using the `args` object, and allowing Node.js to serialize the data column via [console.dir()](https://nodejs.org/api/console.html#console_console_dir_obj_options). This way if you are using a debugger, it may be navigable. | ||
Note that your `echoer` hook is only ever called if [Echo to Console](#echo-to-console) mode is enabled. | ||
## Rotating Logs | ||
@@ -239,5 +303,5 @@ | ||
```javascript | ||
logger.rotate( '/logs/pickup/myapp.log', function(err) { | ||
if (err) throw err; | ||
} ); | ||
logger.rotate( '/logs/pickup/myapp.log', function(err) { | ||
if (err) throw err; | ||
} ); | ||
``` | ||
@@ -250,5 +314,5 @@ | ||
```javascript | ||
logger.rotate( '/path/to/logfile.log', '/logs/pickup/otherapp.log', function(err) { | ||
if (err) throw err; | ||
} ); | ||
logger.rotate( '/path/to/logfile.log', '/logs/pickup/otherapp.log', function(err) { | ||
if (err) throw err; | ||
} ); | ||
``` | ||
@@ -261,9 +325,9 @@ | ||
```javascript | ||
var src_spec = '/logs/myapp/*.log'; | ||
var dest_path = '/archives/myapp/[yyyy]/[mm]/[dd]/[filename]-[hh].log.gz'; | ||
var epoch = ((new Date()).getTime() / 1000) - 1800; // 30 minutes ago | ||
logger.archive( src_spec, dest_path, epoch, function(err) { | ||
if (err) throw err; | ||
} ); | ||
var src_spec = '/logs/myapp/*.log'; | ||
var dest_path = '/archives/myapp/[yyyy]/[mm]/[dd]/[filename]-[hh].log.gz'; | ||
var epoch = ((new Date()).getTime() / 1000) - 1800; // 30 minutes ago | ||
logger.archive( src_spec, dest_path, epoch, function(err) { | ||
if (err) throw err; | ||
} ); | ||
``` | ||
@@ -280,5 +344,5 @@ | ||
```javascript | ||
logger.set( 'sync', true ); | ||
logger.debug( 1, "This will be logged synchronously, even if we exit right NOW!" ); | ||
process.exit(0); | ||
logger.set( 'sync', true ); | ||
logger.debug( 1, "This will be logged synchronously, even if we exit right NOW!" ); | ||
process.exit(0); | ||
``` | ||
@@ -290,3 +354,3 @@ | ||
Copyright (c) 2015 Joseph Huckaby | ||
Copyright (c) 2015 - 2017 Joseph Huckaby | ||
@@ -293,0 +357,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
25734
278
348