0.0.16
prepend pino prettty within the logger with a pretty filter pre processor adds easier filtering of log properties (default) and filtering based on location/where properties support a new env variable UCI_LOG_PRETTY with options like terse,verbose,wheremaster
parent
c2638ea4c1
commit
e9cee9bcd3
|
@ -16,7 +16,7 @@ class LogTest {
|
||||||
appName:'uci-example-logger', //will be used for logging directory name if supplied and will be logged as well
|
appName:'uci-example-logger', //will be used for logging directory name if supplied and will be logged as well
|
||||||
package: '@uci/test', // name of package with scope per package.json
|
package: '@uci/test', // name of package with scope per package.json
|
||||||
// repo: // will use scope-name from package prop if not supplied
|
// repo: // will use scope-name from package prop if not supplied
|
||||||
id: 'built in id', // can pass a unique if for easy later search/filtering
|
id: 'id set in package', // can pass a unique if for easy later search/filtering
|
||||||
// file: 'example/example.js', // path (to repo root) of actual file running this logger, default is ./src/<package without scope>.js
|
// file: 'example/example.js', // path (to repo root) of actual file running this logger, default is ./src/<package without scope>.js
|
||||||
// class: 'LogTest', // The class that created this logger if any
|
// class: 'LogTest', // The class that created this logger if any
|
||||||
|
|
||||||
|
@ -32,8 +32,8 @@ class LogTest {
|
||||||
|
|
||||||
logit() {
|
logit() {
|
||||||
log.trace('this is a trace level logged message')
|
log.trace('this is a trace level logged message')
|
||||||
log.debug('this is a debug level logged message')
|
log.debug({line:343,msg:'this is a debug level logged message with a line number'})
|
||||||
log.info({runtimeprop:'somevalue', msg:'this is a info level logged message'})
|
log.info({runtimeprop:'some propetery in context', msg:'this is a info level logged message'})
|
||||||
log.warn('this is a warn level logged message')
|
log.warn('this is a warn level logged message')
|
||||||
log.error('this is a error level logged message')
|
log.error('this is a error level logged message')
|
||||||
log.fatal('this is a fatal level logged message')
|
log.fatal('this is a fatal level logged message')
|
||||||
|
@ -41,14 +41,17 @@ class LogTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
// let test = new LogTest({id:'id-via new instance', pretty:{include:'all'}})
|
// let test = new LogTest({id:'id-via new instance', pretty:{include:'all'}})
|
||||||
let test = new LogTest({id:'id-via new instance'})
|
let test = new LogTest()
|
||||||
|
|
||||||
log.div(`the default log level based on option or UCI_LOG_LEVEL ${log.default}`)
|
log.div(`the default log level based on option or UCI_LOG_LEVEL ${log.level}`)
|
||||||
test.logit()
|
test.logit()
|
||||||
log.lvlset('fatal')
|
log.lvlset('warn')
|
||||||
log.div(`now changing log level manually in code to ${log.level}`)
|
log.div(`now changing log level manually in code to ${log.level}`)
|
||||||
test.logit()
|
test.logit()
|
||||||
log.div(`reset level back current default ${log.default}`)
|
log.lvlset('trace')
|
||||||
|
log.div(`now changing log level to lowest (view all levels) ${log.level}`)
|
||||||
|
test.logit()
|
||||||
log.lvlset()
|
log.lvlset()
|
||||||
|
log.div(`reset level back current default ${log.level}`)
|
||||||
test.logit()
|
test.logit()
|
||||||
log.clear('This call to log.clear could clear the file log when implemented')
|
log.clear('This call to log.clear could clear the file log when implemented')
|
||||||
|
|
10
package.json
10
package.json
|
@ -1,20 +1,22 @@
|
||||||
{
|
{
|
||||||
"name": "@uci-utils/logger",
|
"name": "@uci-utils/logger",
|
||||||
"version": "0.0.15",
|
"version": "0.0.16",
|
||||||
"description": "Parent Logger for all UCI modules",
|
"description": "Parent Logger for all UCI modules",
|
||||||
"main": "src/logger",
|
"main": "src/logger",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"testd": "./node_modules/.bin/nodemon --exec './node_modules/.bin/mocha -r esm --timeout 30000'",
|
"testd": "./node_modules/.bin/nodemon --exec './node_modules/.bin/mocha -r esm --timeout 30000'",
|
||||||
"test": "./node_modules/.bin/mocha -r esm --timeout 30000 || exit 0",
|
"test": "./node_modules/.bin/mocha -r esm --timeout 30000 || exit 0",
|
||||||
"dev": "UCI_ENV=dev ./node_modules/.bin/nodemon -r esm example/example",
|
"dev": "UCI_ENV=dev ./node_modules/.bin/nodemon -r esm example/example",
|
||||||
"dev:all": "UCI_LOG_PRETTY='{\"include\":\"all\"}' npm run dev",
|
"dev:verbose": "UCI_LOG_PRETTY='verbose' npm run dev",
|
||||||
"dev:includes": "UCI_LOG_PRETTY='{\"include\":\"package,appName\"}' npm run dev",
|
"dev:terse": "UCI_LOG_PRETTY='terse' npm run dev",
|
||||||
|
"dev:where": "UCI_LOG_PRETTY='where' npm run dev",
|
||||||
|
"dev:filter:line": "UCI_LOG_PRETTY='{\"filter\":[\"line\"]}' npm run dev",
|
||||||
|
"dev:include": "UCI_LOG_PRETTY='{\"include\":\"package,appName\"}' npm run dev",
|
||||||
"dev:trace": "UCI_LOG_LEVEL=trace npm run dev",
|
"dev:trace": "UCI_LOG_LEVEL=trace npm run dev",
|
||||||
"dev:warn": "UCI_LOG_LEVEL=warn npm run dev",
|
"dev:warn": "UCI_LOG_LEVEL=warn npm run dev",
|
||||||
"dev:info:only": "UCI_LOG_SEARCH='level==`30`' npm run dev",
|
"dev:info:only": "UCI_LOG_SEARCH='level==`30`' npm run dev",
|
||||||
"dev:fatal:only": "UCI_LOG_SEARCH='level==`60`' npm run dev",
|
"dev:fatal:only": "UCI_LOG_SEARCH='level==`60`' npm run dev",
|
||||||
"dev:json": "UCI_LOG_LEVEL=trace UCI_LOG_JSON=true npm run dev",
|
"dev:json": "UCI_LOG_LEVEL=trace UCI_LOG_JSON=true npm run dev",
|
||||||
"dev:colada": "npm run dev:json | ./node_modules/.bin/pino-colada ",
|
|
||||||
"pro": "UCI_ENV='pro' node -r esm example/example",
|
"pro": "UCI_ENV='pro' node -r esm example/example",
|
||||||
"pro:path": "UCI_LOG_PATH=./example/example.log npm run pro"
|
"pro:path": "UCI_LOG_PATH=./example/example.log npm run pro"
|
||||||
},
|
},
|
||||||
|
|
20
readme.md
20
readme.md
|
@ -37,13 +37,19 @@ then
|
||||||
|
|
||||||
available scripts for example file
|
available scripts for example file
|
||||||
|
|
||||||
- `none`: no logs to console or file
|
"dev": "UCI_ENV=dev ./node_modules/.bin/nodemon -r esm example/example",
|
||||||
- `dev`: all levels pretty printed to console/stdout
|
"dev:verbose": "UCI_LOG_PRETTY='verbose' npm run dev",
|
||||||
- `dev:info`: show/filter only level 30 (info) logs pretty printed to console
|
"dev:terse": "UCI_LOG_PRETTY='terse' npm run dev",
|
||||||
- `dev:fatal`: show/filer only level 60 (fatal) logs pretty printed to console
|
"dev:filter:line": "UCI_LOG_PRETTY='{\"filter\":[\"line\"]}' npm run dev",
|
||||||
- `json`: log to console but as raw json
|
"dev:include": "UCI_LOG_PRETTY='{\"include\":\"package,appName\"}' npm run dev",
|
||||||
- `pro`: log to a file in the userspace default log directory location
|
"dev:trace": "UCI_LOG_LEVEL=trace npm run dev",
|
||||||
- `pro:alt`: log to a supplied/alternate file (path) location in this case `./example/example.log`
|
"dev:warn": "UCI_LOG_LEVEL=warn npm run dev",
|
||||||
|
"dev:info:only": "UCI_LOG_SEARCH='level==`30`' npm run dev",
|
||||||
|
"dev:fatal:only": "UCI_LOG_SEARCH='level==`60`' npm run dev",
|
||||||
|
"dev:json": "UCI_LOG_LEVEL=trace UCI_LOG_JSON=true npm run dev",
|
||||||
|
"dev:colada": "npm run dev:json | ./node_modules/.bin/pino-colada ",
|
||||||
|
"pro": "UCI_ENV='pro' node -r esm example/example",
|
||||||
|
"pro:path": "UCI_LOG_PATH=./example/example.log npm run pro"
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
|
|
|
@ -2,19 +2,22 @@ import pino from 'pino'
|
||||||
import envPaths from 'env-paths'
|
import envPaths from 'env-paths'
|
||||||
import { sync as mkdir } from 'make-dir'
|
import { sync as mkdir } from 'make-dir'
|
||||||
import { dirname, basename } from 'path'
|
import { dirname, basename } from 'path'
|
||||||
|
import pinoPretty from 'pino-pretty'
|
||||||
|
|
||||||
function child (opts) {
|
function child (opts) {
|
||||||
|
|
||||||
const enabled = !!process.env.UCI_ENV
|
const enabled = !!process.env.UCI_ENV
|
||||||
|
|
||||||
let pretty = false; let LOG_PATH; let DATE_TIME
|
let pretty; let filter; let LOG_PATH; let DATE_TIME
|
||||||
|
|
||||||
const PRETTY_DEFAULTS = {translateTime:true, colorize:true, levelFirst:true}
|
const PRETTY_DEFAULTS = {translateTime:true, colorize:true, levelFirst:true}
|
||||||
|
const DEFAULT_FILTER_PROPS = ['level','time','v','pid','msg']
|
||||||
|
const WHERE_FILTER_PROPS = ['package','file','method','function','line']
|
||||||
|
|
||||||
let logOpts = {
|
let logOpts = {
|
||||||
level:opts.level || process.env.UCI_LOG_LEVEL,
|
level:opts.level || process.env.UCI_LOG_LEVEL,
|
||||||
logPath: LOG_PATH, // if logging to file
|
logPath: LOG_PATH, // if logging to file
|
||||||
appName: opts.appName || opts.name,
|
appName: process.env.UCI_LOG_APP || opts.appName || opts.name,
|
||||||
package: opts.package,
|
package: opts.package,
|
||||||
repo: opts.repo || ((typeof opts.package==='string') ? opts.package.replace( /[@]+/g, '' ).replace( /[/]+/g, '-' ) : undefined),
|
repo: opts.repo || ((typeof opts.package==='string') ? opts.package.replace( /[@]+/g, '' ).replace( /[/]+/g, '-' ) : undefined),
|
||||||
file: opts.file || ((typeof opts.package==='string') ? `src/${basename(opts.package)}.js` : undefined),
|
file: opts.file || ((typeof opts.package==='string') ? `src/${basename(opts.package)}.js` : undefined),
|
||||||
|
@ -24,23 +27,35 @@ function child (opts) {
|
||||||
instanceCreated:Date.now()
|
instanceCreated:Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
logOpts = Object.assign(logOpts,opts.additional)
|
// logOpts = Object.assign(logOpts,opts.additional)
|
||||||
|
|
||||||
|
// console.log('log opts', logOpts)
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (opts.env) (opts.envForce) ? (process.env.UCI_ENV = opts.env) : (process.env.UCI_ENV = process.env.UCI_ENV || opts.env)
|
if (opts.env) (opts.envForce) ? (process.env.UCI_ENV = opts.env) : (process.env.UCI_ENV = process.env.UCI_ENV || opts.env)
|
||||||
if (process.env.UCI_ENV === 'node') process.env.UCI_ENV = process.env.NODE_ENV
|
if (process.env.UCI_ENV === 'node') process.env.UCI_ENV = process.env.NODE_ENV
|
||||||
if(process.env.UCI_ENV.indexOf('dev')>-1) {
|
if((process.env.UCI_ENV.indexOf('dev')>-1 || process.env.UCI_LOG_PRETTY) && process.env.UCI_LOG_JSON !=='true' ) { // pretty is on
|
||||||
if (process.env.UCI_LOG_JSON !=='true') {
|
try {
|
||||||
if (process.env.UCI_LOG_PRETTY && process.env.UCI_LOG_PRETTY !=='true') pretty = JSON.parse(process.env.UCI_LOG_PRETTY)
|
pretty = JSON.parse(process.env.UCI_LOG_PRETTY)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
// console.log('LOGGER: could not parse',process.env.UCI_LOG_PRETTY )
|
||||||
|
if (process.env.UCI_LOG_PRETTY==='verbose') pretty ={include:'all'}
|
||||||
|
}
|
||||||
pretty = pretty || opts.pretty || {}
|
pretty = pretty || opts.pretty || {}
|
||||||
pretty = Object.assign({},PRETTY_DEFAULTS,pretty)
|
pretty = Object.assign({},PRETTY_DEFAULTS,pretty)
|
||||||
pretty.search = process.env.UCI_LOG_SEARCH
|
pretty.search = process.env.UCI_LOG_SEARCH
|
||||||
pretty.include = pretty.include === 'all' ? 'all' : `level,${pretty.include}`
|
pretty.include = pretty.include === 'all' ? 'all' : `level${pretty.include ? ','+ pretty.include : ''}`
|
||||||
console.log(pretty.include)
|
|
||||||
pretty.ignore = pretty.include === 'all' ? null : Object.keys(logOpts).filter(key => pretty.include.indexOf(key) === -1 ).join()
|
pretty.ignore = pretty.include === 'all' ? null : Object.keys(logOpts).filter(key => pretty.include.indexOf(key) === -1 ).join()
|
||||||
|
|
||||||
|
|
||||||
|
if (process.env.UCI_LOG_PRETTY === 'terse' || process.env.UCI_LOG_PRETTY === 'where' || pretty.filter ) {
|
||||||
|
filter = filterPretty // only call prefilter if some filter is supplied, otherwise
|
||||||
|
pretty.filter = [...DEFAULT_FILTER_PROPS,...(process.env.UCI_LOG_PRETTY === 'where' ? WHERE_FILTER_PROPS : []),...(pretty.filter||[])]
|
||||||
|
pretty.ignore = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
DATE_TIME = new Date().toString()
|
DATE_TIME = new Date().toString()
|
||||||
LOG_PATH = ( process.env.UCI_ENV.indexOf('pro') > -1 || process.env.UCI_ENV === 'logfile' )
|
LOG_PATH = ( process.env.UCI_ENV.indexOf('pro') > -1 || process.env.UCI_ENV === 'logfile' )
|
||||||
? ( process.env.UCI_LOG_PATH || `${envPaths(opts.appName || opts.name || 'default').log}/${opts.logFileName || DATE_TIME}.log`) : undefined
|
? ( process.env.UCI_LOG_PATH || `${envPaths(opts.appName || opts.name || 'default').log}/${opts.logFileName || DATE_TIME}.log`) : undefined
|
||||||
|
@ -48,8 +63,12 @@ function child (opts) {
|
||||||
try { mkdir(dirname(LOG_PATH)) } // makes recursively for any missing parent directories
|
try { mkdir(dirname(LOG_PATH)) } // makes recursively for any missing parent directories
|
||||||
catch(err) { throw err }
|
catch(err) { throw err }
|
||||||
}
|
}
|
||||||
}
|
} // end enabled
|
||||||
// console.log('making logger (env,json,pretty,pretty-search,path)',process.env.UCI_ENV,process.env.UCI_LOG_JSON,pretty,process.env.UCI_LOG_SEARCH,LOG_PATH)
|
|
||||||
|
|
||||||
|
|
||||||
|
// console.log('pretty terse logger', pretty.terse)
|
||||||
|
// console.log('making logger \n(env,json,pretty,pretty-search,path)\n',process.env.UCI_ENV,process.env.UCI_LOG_JSON,pretty,process.env.UCI_LOG_SEARCH,LOG_PATH)
|
||||||
const logger = pino({
|
const logger = pino({
|
||||||
name: opts.libraryName || process.env.UCI_LOG_NAME || 'UCI',
|
name: opts.libraryName || process.env.UCI_LOG_NAME || 'UCI',
|
||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
|
@ -58,7 +77,8 @@ function child (opts) {
|
||||||
req: pino.stdSerializers.req,
|
req: pino.stdSerializers.req,
|
||||||
res: pino.stdSerializers.res
|
res: pino.stdSerializers.res
|
||||||
},
|
},
|
||||||
prettyPrint: pretty
|
prettyPrint: pretty,
|
||||||
|
prettifier: filter // only call prefilter if some filter is supplied, otherwise see line 53
|
||||||
},
|
},
|
||||||
// if production not enabled then LOG_PATH is empty and logs go to stdout/stderr and can be piped from there
|
// if production not enabled then LOG_PATH is empty and logs go to stdout/stderr and can be piped from there
|
||||||
LOG_PATH
|
LOG_PATH
|
||||||
|
@ -66,7 +86,7 @@ function child (opts) {
|
||||||
|
|
||||||
let child = logger.child(logOpts)
|
let child = logger.child(logOpts)
|
||||||
|
|
||||||
child.default = opts.level || process.env.UCI_LOG_LEVEL
|
child.default = process.env.UCI_LOG_LEVEL || opts.level || 'info'
|
||||||
child.clear = () => {
|
child.clear = () => {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (process.env.UCI_ENV.indexOf('pro') > -1) return null } // enable feature here
|
if (process.env.UCI_ENV.indexOf('pro') > -1) return null } // enable feature here
|
||||||
|
@ -75,7 +95,7 @@ function child (opts) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (process.env.UCI_ENV.indexOf('dev') > -1) console.log(`===== ${value} ========`)}
|
if (process.env.UCI_ENV.indexOf('dev') > -1) console.log(`===== ${value} ========`)}
|
||||||
}
|
}
|
||||||
child.lvlset = (level) => { if (enabled) child.level = level || child.default || 'info' }
|
child.lvlset = (level) => { if (enabled) child.level = level || child.default }
|
||||||
|
|
||||||
return child
|
return child
|
||||||
}
|
}
|
||||||
|
@ -83,3 +103,31 @@ function child (opts) {
|
||||||
export default child
|
export default child
|
||||||
|
|
||||||
function capitalize (s) { return s.charAt(0).toUpperCase() + s.slice(1)}
|
function capitalize (s) { return s.charAt(0).toUpperCase() + s.slice(1)}
|
||||||
|
|
||||||
|
function filterPretty (options) {
|
||||||
|
return function prettifier (inputData) {
|
||||||
|
let log
|
||||||
|
let parsedData
|
||||||
|
if (typeof inputData === 'string') {
|
||||||
|
try { parsedData = JSON.Parse(inputData)}
|
||||||
|
catch(err){ return inputData }
|
||||||
|
log = (isPinoLog(parsedData)) ? parsedData : undefined
|
||||||
|
} else if (isObject(inputData) && isPinoLog(inputData)) {
|
||||||
|
log = inputData
|
||||||
|
}
|
||||||
|
if (!log) return inputData
|
||||||
|
let filteredLog = {}
|
||||||
|
options.filter.forEach(prop => filteredLog[prop]= log[prop])
|
||||||
|
// console.log('filtered',options.filter, filteredLog)
|
||||||
|
// if (options.pid) console.log('pid:',logObject.pid)
|
||||||
|
return pinoPretty(options)(filteredLog)
|
||||||
|
}
|
||||||
|
|
||||||
|
function isObject (input) {
|
||||||
|
return Object.prototype.toString.apply(input) === '[object Object]'
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPinoLog (log) {
|
||||||
|
return log && (log.hasOwnProperty('v') && log.v === 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ describe('JSON Logging Utility Testing ',async ()=> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO this is available from the logger as .levels
|
||||||
let levelName = {
|
let levelName = {
|
||||||
10:'trace',
|
10:'trace',
|
||||||
20:'debug',
|
20:'debug',
|
||||||
|
|
Loading…
Reference in New Issue