fix: warning about passed level property

refactor!: passed arguments separated into bindings and options
feat: bound properties under meta: key in log
feat: pino key of options argument for pino settings
feat: in dev/pretty can (un)hide properties
feat: add a unique id to each log line (can be loaded by nedb and such)
feat: locate method to easily add line number and file to a log line

BREAKING CHANGE: logger/pino options in second separate argument from bindings
master
Kebler Network System Administrator 2021-07-26 07:46:21 -07:00
parent e776937738
commit 2bb6b65e63
10 changed files with 4406 additions and 157 deletions

View File

@ -1,33 +0,0 @@
module.exports = {
"ecmaFeatures": {
"modules": true,
"spread" : true,
"restParams" : true
},
"env": {
"es6": true,
"node": true,
"mocha": true
},
"parserOptions": {
"ecmaVersion": 2017,
"sourceType": "module"
},
"extends": "eslint:recommended",
"rules": {
"indent": [
"error",
2
],
"no-console": 0,
"semi": ["error", "never"],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
]
}
}

15
.eslintrc.yml Normal file
View File

@ -0,0 +1,15 @@
env:
node: true
es2021: true
mocha: true
extends:
- standard
parserOptions:
ecmaVersion: 12
sourceType: module
rules:
indent: ["error", 2]
no-console: 0
semi: ["error", "never"]
# linebreak-style: ["error", "unix"]
quotes: ["error", "single"]

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/node_modules/ /node_modules/
/coverage/ /coverage/
*.yaml *.yaml
/example/example.log

View File

@ -1,12 +0,0 @@
language: node_js
node_js:
- '7.10'
- 'node'
sudo: false
script: npm test
after_success:
- bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports"

View File

@ -1,47 +1,69 @@
import logger from '../src/logger.js' import logger from '../src/logger.js'
import testsrc from './test.js'
let log = {} let log = {}
class LogTest { const options = {
constructor(opts) { // custom UCI logger options
log = logger( // noID: true,
Object.assign({ // IDKey: '_id' // default
hide: ['meta', 'machine'], // array of properties to hide
// pretty: {translateTime:true, colorize:true, levelFirst:true } // options for pino pretty printer // pretty: {translateTime:true, colorize:true, levelFirst:true } // options for pino pretty printer
// env:'', // 'dev' or 'pro' -- can be use to set/override UCI_ENV environment variable // env:'', // 'dev' or 'pro' -- can be use to set/override UCI_ENV environment variable
// enForce: false, // only used with .evn. if true will override UCI_ENV if it is set, otherwise no // enForce: false, // only used with .evn. if true will override UCI_ENV if it is set, otherwise no
// level:'debug', // info is default level, set level to lowest visible
// clear: false, // true for log files will clear the current log file on restart // clear: false, // true for log files will clear the current log file on restart
// logFileName:'test', // if not supplied log filename will be generated from timestamp // logFileName:'test', // if not supplied log filename will be generated from timestamp
// below are BASE properties which are optional and are passed to child logger instance and will be part of json log entry //
// libraryName: 'UCI', // will be logged as name: can be used to identify logs of related packages, can be set via UCI_LOG_NAME env variable // override logger default and or add any pino options
appName:'uci-example-logger', //will be used for logging directory name if supplied and will be logged as well pino: {
package: '@uci/test', // name of package with scope per package.json // level:'info', // info is default level, overrides UCI_LOG_LEVEL, can be changed at runtime with .level method
// repo: // will use scope-name from package prop if not supplied // name: either libraryName above or UCI_LOG_NAME or default 'UCI',
id: 'id set in package', // can pass a unique if for easy later search/filtering // enabled: only if UCI_ENV is set
file: 'example/example.js', // path (to repo root) of actual file running this logger, default is ./src/<package without scope>.js // nestedKey: 'props' // nest the runtime custom log properties
class: 'LogTest', // The class that created this logger if any // safe: true,
// timestamp: pino.stdTimeFunctions.epochTime,
/*---------------- // serializers: {
Can pass through additional props for every log by including this `additional` property object // req: pino.stdSerializers.req,
should not use any keys above or level,time,msg,pid,hostname, // res: pino.stdSerializers.res
logPath,instanceCreatedHR,instanceCreated as keys in this object will be merged // },
------------------*/ // prettyPrint: pretty,
// additional: {anotherprop:'test'} // prettifier: filter // only call prefilter if some filter is supplied, otherwise see line 53
},opts)
)
} }
}
const meta = {
// meta properties added to all log output
// the following base meta props and will be generated with defaults if not set
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
// library: 'uci', // will be stripped from @ organization of package if not supplied
// repo: // will use scope-name from package prop if not supplied
// file: 'example/example.js', // path (to repo root) of actual file running this logger, default is ./src/<package without scope>.js
// file: import.meta.url // use this to get a dynmic absolute path to the file where logger is created
// class: 'LogTest' // otherwise will be generated from package
// class: false // set to false to disable meta class property
// add any additional properties to meta data here
// an example
// id: // maybe a unique id to make is easier to search and/or filter these logs
}
class LogTest {
constructor () {
log = logger(meta, options)
} // end constructor
logit () { logit () {
log.trace('this is a trace level logged message') log.trace('this is a trace level logged message')
log.debug({line:343,msg:'this is a debug level logged message with a line number'}) log.debug({ line: log.locate(), msg: 'this is a debug level logged message with a line number' })
log.info({runtimeprop:'some propetery in context', msg:'this is a info level logged message'}) log.info({ runtimeprop: 'some propertey 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')
} }
} }
// 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() const test = new LogTest()
log.div(`the default log level based on option or UCI_LOG_LEVEL ${log.level}`) log.div(`the default log level based on option or UCI_LOG_LEVEL ${log.level}`)
test.logit() test.logit()
@ -54,4 +76,22 @@ test.logit()
log.lvlset() log.lvlset()
log.div(`reset level back current default ${log.level}`) 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')
console.log('\n-------- hide props------------')
log.info({ test1: 'test1', test2: 'test2' }, 'testing')
log.hide('test1')
console.log('hiding test1')
log.info({ test1: 'test1', test2: 'test2' }, 'hiding test1')
log.hide('test2')
console.log('hiding test2')
log.info({ test1: 'test1', test2: 'test2' }, 'hiding test2')
log.unhide(['test1', 'test2'])
console.log('unhiding both')
log.info({ test1: 'test1', test2: 'test2' }, 'hiding test2')
console.log('\n-------- include line and file ------------')
log.info({ loc: log.locate() }, 'log line:file')
log.info({ line: log.locate('n') }, 'log line')
log.info({ file: log.locate('f') }, 'log file')
log.info({ file: log.locate(1) }, 'log loc alternate stack')
testsrc(log)

View File

@ -1,18 +0,0 @@
{"level":30,"time":1549418336924,"pid":12697,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-58-56-919Z","instanceCreated":1549418336923,"runtimeprop":"somevalue","msg":"this is a info level logged message","v":1}
{"level":40,"time":1549418336924,"msg":"this is a warn level logged message","pid":12697,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-58-56-919Z","instanceCreated":1549418336923,"v":1}
{"level":50,"time":1549418336924,"msg":"this is a error level logged message","pid":12697,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-58-56-919Z","instanceCreated":1549418336923,"v":1}
{"level":60,"time":1549418336924,"msg":"this is a fatal level logged message","pid":12697,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-58-56-919Z","instanceCreated":1549418336923,"v":1}
{"level":60,"time":1549418336924,"msg":"this is a fatal level logged message","pid":12697,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-58-56-919Z","instanceCreated":1549418336923,"v":1}
{"level":30,"time":1549418336924,"pid":12697,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-58-56-919Z","instanceCreated":1549418336923,"runtimeprop":"somevalue","msg":"this is a info level logged message","v":1}
{"level":40,"time":1549418336924,"msg":"this is a warn level logged message","pid":12697,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-58-56-919Z","instanceCreated":1549418336923,"v":1}
{"level":50,"time":1549418336924,"msg":"this is a error level logged message","pid":12697,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-58-56-919Z","instanceCreated":1549418336923,"v":1}
{"level":60,"time":1549418336924,"msg":"this is a fatal level logged message","pid":12697,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-58-56-919Z","instanceCreated":1549418336923,"v":1}
{"level":30,"time":1549418345373,"pid":12734,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-59-05-370Z","instanceCreated":1549418345372,"runtimeprop":"somevalue","msg":"this is a info level logged message","v":1}
{"level":40,"time":1549418345373,"msg":"this is a warn level logged message","pid":12734,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-59-05-370Z","instanceCreated":1549418345372,"v":1}
{"level":50,"time":1549418345373,"msg":"this is a error level logged message","pid":12734,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-59-05-370Z","instanceCreated":1549418345372,"v":1}
{"level":60,"time":1549418345373,"msg":"this is a fatal level logged message","pid":12734,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-59-05-370Z","instanceCreated":1549418345372,"v":1}
{"level":60,"time":1549418345373,"msg":"this is a fatal level logged message","pid":12734,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-59-05-370Z","instanceCreated":1549418345372,"v":1}
{"level":30,"time":1549418345373,"pid":12734,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-59-05-370Z","instanceCreated":1549418345372,"runtimeprop":"somevalue","msg":"this is a info level logged message","v":1}
{"level":40,"time":1549418345373,"msg":"this is a warn level logged message","pid":12734,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-59-05-370Z","instanceCreated":1549418345372,"v":1}
{"level":50,"time":1549418345373,"msg":"this is a error level logged message","pid":12734,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-59-05-370Z","instanceCreated":1549418345372,"v":1}
{"level":60,"time":1549418345373,"msg":"this is a fatal level logged message","pid":12734,"hostname":"giskard","name":"UCI","logPath":"./example/example.log","appName":"uci-example-logger","repo":"uci-test","package":"@uci/test","file":"src/test.js","class":"Tuci/test","id":"logtest-via-new","instanceCreatedHR":"2019-02-06T01-59-05-370Z","instanceCreated":1549418345372,"v":1}

3
example/test.js Normal file
View File

@ -0,0 +1,3 @@
export default function test (log) {
log.info({ location: log.locate() }, 'testing line from another file')
}

4177
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,11 @@
{ {
"name": "@uci-utils/logger", "name": "@uci-utils/logger",
"version": "0.1.0", "version": "0.2.0",
"description": "Parent Logger for all UCI modules", "description": "Parent Logger for all UCI modules",
"main": "./src/logger.js", "main": "./src/logger.js",
"type": "module", "type": "module",
"scripts": { "scripts": {
"testd": "./node_modules/.bin/nodemon --exec './node_modules/.bin/mocha --timeout 30000' || exit 1", "test:dev": "./node_modules/.bin/nodemon --trace-warnings --exec './node_modules/.bin/mocha --timeout 30000' || exit 1",
"test": "./node_modules/.bin/mocha --timeout 30000 || exit 0", "test": "./node_modules/.bin/mocha --timeout 30000 || exit 0",
"dev": "UCI_ENV=dev ./node_modules/.bin/nodemon example/example", "dev": "UCI_ENV=dev ./node_modules/.bin/nodemon example/example",
"dev:verbose": "UCI_LOG_PRETTY='verbose' npm run dev", "dev:verbose": "UCI_LOG_PRETTY='verbose' npm run dev",
@ -18,7 +18,7 @@
"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",
"pro": "UCI_ENV='pro' node example/example", "pro": "UCI_ENV='pro' nodemon example/example",
"pro:path": "UCI_LOG_PATH=./example/example.log npm run pro" "pro:path": "UCI_LOG_PATH=./example/example.log npm run pro"
}, },
"author": "David Kebler", "author": "David Kebler",
@ -39,13 +39,19 @@
"dependencies": { "dependencies": {
"env-paths": "^2.2.1", "env-paths": "^2.2.1",
"make-dir": "^3.1.0", "make-dir": "^3.1.0",
"pino": "^6.11.3", "pino": "^6.13.0",
"pino-pretty": "^4.7.1" "pino-pretty": "^5.1.2",
"uniqid": "^5.3.0"
}, },
"devDependencies": { "devDependencies": {
"chai": "^4.3.4", "chai": "^4.3.4",
"mocha": "^8.3.2", "eslint": "^7.31.0",
"nodemon": "^2.0.7", "eslint-config-standard": "^16.0.3",
"test-console": "^1.1.0" "eslint-plugin-import": "^2.23.4",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"mocha": "^9.0.3",
"nodemon": "^2.0.12",
"test-console": "^2.0.0"
} }
} }

View File

@ -3,30 +3,26 @@ 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' import pinoPretty from 'pino-pretty'
import uniqid from 'uniqid'
function child (opts) { // TODO add custom levels
// is pro log to file working???
function child (bindings = {}, options = {}) {
const pinoOpts = Object.assign({}, options.pino)
const opts = Object.assign({}, options)
delete opts.pino
const enabled = !!process.env.UCI_ENV const enabled = !!process.env.UCI_ENV
let pretty; let filter; let LOG_PATH; let DATE_TIME let pretty; let filter; let LOG_PATH; let DATE_TIME; let destination; let file
let hidden = Array.isArray(opts.hide) ? opts.hide : [opts.hide]
const PRETTY_DEFAULTS = { translateTime: true, colorize: true, levelFirst: true } const PRETTY_DEFAULTS = { translateTime: true, colorize: true, levelFirst: true }
const DEFAULT_FILTER_PROPS = ['level', 'time', 'pid', 'msg'] const DEFAULT_FILTER_PROPS = ['level', 'time', 'pid', 'msg']
const WHERE_FILTER_PROPS = ['package', 'file', 'class', 'method', 'function', 'line'] const WHERE_FILTER_PROPS = ['package', 'file', 'class', 'method', 'function', 'line']
let logOpts = {
level:opts.level || process.env.UCI_LOG_LEVEL,
logPath: LOG_PATH, // if logging to file
appName: process.env.UCI_LOG_APP || opts.appName || opts.name,
package: opts.package,
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),
class: opts.class || ( (typeof opts.package==='string') ? capitalize(basename(opts.package)) : undefined),
id: opts.id || opts.name || 'none',
instanceCreatedHR:DATE_TIME,
instanceCreated:Date.now()
}
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
@ -34,8 +30,7 @@ function child (opts) {
// process UCI_LOG_PRETTY // process UCI_LOG_PRETTY
try { try {
pretty = JSON.parse(process.env.UCI_LOG_PRETTY) pretty = JSON.parse(process.env.UCI_LOG_PRETTY)
} } catch (error) {
catch (error) {
// console.log('LOGGER: could not JSON parse',process.env.UCI_LOG_PRETTY ) // console.log('LOGGER: could not JSON parse',process.env.UCI_LOG_PRETTY )
} }
if (process.env.UCI_LOG_PRETTY === 'verbose') pretty = { include: 'all' } if (process.env.UCI_LOG_PRETTY === 'verbose') pretty = { include: 'all' }
@ -43,9 +38,7 @@ function child (opts) {
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 = pretty.include === 'all' ? 'all' : `level${pretty.include ? ',' + 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(opts).filter(key => pretty.include.indexOf(key) === -1).join()
if (process.env.UCI_LOG_PRETTY === 'terse' || process.env.UCI_LOG_PRETTY === 'where' || pretty.filter) { 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 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.filter = [...DEFAULT_FILTER_PROPS, ...(process.env.UCI_LOG_PRETTY === 'where' ? WHERE_FILTER_PROPS : []), ...(pretty.filter || [])]
@ -53,70 +46,147 @@ function child (opts) {
} }
} }
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
if (LOG_PATH) { if (LOG_PATH) {
try { mkdir(dirname(LOG_PATH)) } // makes recursively for any missing parent directories mkdir(dirname(LOG_PATH)) // makes recursively for any missing parent directories
catch(err) { throw err } destination = LOG_PATH
} }
} // end enabled } // end enabled
// default bindings
bindings.appName = process.env.UCI_LOG_APP || bindings.appName || bindings.name
bindings.library = bindings.library || typeof bindings.package === 'string' ? (bindings.package.includes('@') ? (bindings.package.replace(/[@]+/g, '')).split('/')[0] : undefined) : undefined
bindings.repo = bindings.repo || ((typeof bindings.package === 'string') ? bindings.package.replace(/[@]+/g, '').replace(/[/]+/g, '-') : undefined)
bindings.file = bindings.file || ((typeof bindings.package === 'string') ? `src/${basename(bindings.package)}.js` : undefined)
bindings.class = bindings.class || (bindings.class !== false && typeof bindings.package === 'string') ? capitalize(basename(bindings.package)) : undefined
bindings.instanceCreatedHR = DATE_TIME
bindings.instanceCreated = Date.now()
// console.dir(pretty) // console.dir(pretty)
// console.dir(logOpts) // console.dir(logOpts)
const logger = pino({ if (pinoOpts.destination) {
name: opts.libraryName || process.env.UCI_LOG_NAME || 'UCI', destination = pinoOpts.destination
delete pinoOpts.destination
}
const defaultLevel = pinoOpts.level || opts.level || process.env.UCI_LOG_LEVEL || 'info'
const defaultOpts = {
enabled: enabled, enabled: enabled,
safe: true, safe: true,
level: defaultLevel,
formatters: {
bindings (obj) {
return { machine: obj }
}
},
timestamp: pino.stdTimeFunctions.epochTime,
serializers: { serializers: {
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 prettifier: filter // only call prefilter if some filter is supplied, otherwise see line 53
}, }
const logger = pino(
Object.assign({}, defaultOpts, pinoOpts),
// 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 destination
) )
let child = logger.child(logOpts) const child = logger.child({ meta: bindings }, {
formatters: {
log (obj) {
// console.log('formatter', obj.level, child.level)
obj.dateTime = new Date().toString()
if (!pretty) {
obj.label = child.level
if (!opts.noID) obj[opts.keyID || '_id'] = uniqid()
} else {
obj.file = obj.file || file
hidden.forEach(prop => {
// console.log('hiding', prop, obj[prop])
obj[prop] = undefined
})
}
return obj
}
}
})
child.default = process.env.UCI_LOG_LEVEL || opts.level || 'info' child.default = defaultLevel
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
} }
child.div = value => { child.div = value => {
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 } child.lvlset = (level) => { if (enabled) child.level = level || child.default }
child.hide = (props) => {
hidden = arraysMerge(props, hidden)
}
child.unhide = (props) => {
hidden = arraysFilter(props, hidden)
}
child.locate = locate
return child return child
} }
export default child export default child
const levels = pino.levels const levels = pino.levels
export {child as logger, levels} export { child as logger, levels, locate, arraysMerge }
function capitalize (s) { return s.charAt(0).toUpperCase() + s.slice(1)}
function filterPretty (options) { function filterPretty (options) {
// console.log('filter options',options) // console.log('filter options',options)
return function prettifier (inputData) { return function prettifier (inputData) {
// console.log('calling filter',inputData) // console.log('calling filter',inputData)
let log let log
let parsedData // let parsedData
if (typeof inputData === 'string') { if (typeof inputData === 'string') {
try { log = JSON.Parse(inputData)} try { log = JSON.Parse(inputData) } catch (err) { return inputData }
catch(err){ return inputData } } else log = inputData
} const filteredLog = {}
else log = inputData options.filter.forEach(prop => { filteredLog[prop] = log[prop] })
let filteredLog = {}
options.filter.forEach(prop => filteredLog[prop]= log[prop])
// console.log('filtered',options.filter, filteredLog) // console.log('filtered',options.filter, filteredLog)
return pinoPretty(options)(filteredLog) return pinoPretty(options)(filteredLog)
} }
} }
// TODO move these to @uci-utils/helpers
function capitalize (s) { return s.charAt(0).toUpperCase() + s.slice(1) }
function locate (frame = 2, ret) {
if (typeof frame === 'string') { ret = frame; frame = 2 }
const e = new Error()
const stack = e.stack.toString().split(/\r\n|\n/)
const RE = /file:\/\/(.*):(\d+):(?:\d+)[^\d]*$/
const reg = RE.exec(stack[frame])
const str = ret ? (ret === 'n' ? reg[2] : reg[1]) : `${reg[2]}:${reg[1]}`
return str // return line#:path
}
function arraysMerge (els, arr) {
els = Array.isArray(els) ? els : [els]
return [...new Set([...arr, ...els])].filter(el => el != null)
}
function arraysFilter (els, arr) {
els = Array.isArray(els) ? els : [els]
return arr.filter(function (item) {
return !els.includes(item)
})
}