UNPKG

5.23 kBJavaScriptView Raw
1#!/usr/bin/env node
2
3const fs = require('fs')
4const args = require('args')
5const path = require('path')
6const pump = require('pump')
7const split = require('split2')
8const { Transform } = require('readable-stream')
9const prettyFactory = require('./')
10const CONSTANTS = require('./lib/constants')
11const { isObject } = require('./lib/utils')
12
13const bourne = require('@hapi/bourne')
14const stripJsonComments = require('strip-json-comments')
15const parseJSON = input => {
16 return bourne.parse(stripJsonComments(input), { protoAction: 'remove' })
17}
18
19const JoyCon = require('joycon')
20const joycon = new JoyCon({
21 parseJSON,
22 files: [
23 'pino-pretty.config.js',
24 '.pino-prettyrc',
25 '.pino-prettyrc.json'
26 ],
27 stopDir: path.dirname(process.cwd())
28})
29joycon.addLoader({
30 test: /\.[^.]*rc$/,
31 loadSync: (path) => parseJSON(fs.readFileSync(path, 'utf-8'))
32})
33
34args
35 .option(['c', 'colorize'], 'Force adding color sequences to the output')
36 .option(['f', 'crlf'], 'Append CRLF instead of LF to formatted lines')
37 .option(['e', 'errorProps'], 'Comma separated list of properties on error objects to show (`*` for all properties) (defaults to ``)')
38 .option(['l', 'levelFirst'], 'Display the log level as the first output field')
39 .option(['k', 'errorLikeObjectKeys'], 'Define which keys contain error objects (`-k err,error`) (defaults to `err,error`)')
40 .option(['m', 'messageKey'], 'Highlight the message under the specified key', CONSTANTS.MESSAGE_KEY)
41 .option('levelKey', 'Detect the log level under the specified key', CONSTANTS.LEVEL_KEY)
42 .option(['b', 'levelLabel'], 'Output the log level using the specified label', CONSTANTS.LEVEL_LABEL)
43 .option(['o', 'messageFormat'], 'Format output of message')
44 .option(['a', 'timestampKey'], 'Display the timestamp from the specified key', CONSTANTS.TIMESTAMP_KEY)
45 .option(['t', 'translateTime'], 'Display epoch timestamps as UTC ISO format or according to an optional format string (default ISO 8601)')
46 .option(['s', 'search'], 'Specify a search pattern according to jmespath')
47 .option(['i', 'ignore'], 'Ignore one or several keys: (`-i time,hostname`)')
48 .option(['H', 'hideObject'], 'Hide objects from output (but not error object)')
49 .option('config', 'specify a path to a json file containing the pino-pretty options')
50
51args
52 .example('cat log | pino-pretty', 'To prettify logs, simply pipe a log file through')
53 .example('cat log | pino-pretty -m fooMessage', 'To highlight a string at a key other than \'msg\'')
54 .example('cat log | pino-pretty --levelKey fooLevel', 'To detect the log level at a key other than \'level\'')
55 .example('cat log | pino-pretty --levelLabel LVL -o "{LVL}"', 'To output the log level label using a key other than \'levelLabel\'')
56 .example('cat log | pino-pretty -a fooTimestamp', 'To display timestamp from a key other than \'time\'')
57 .example('cat log | pino-pretty -t', 'To convert Epoch timestamps to ISO timestamps use the -t option')
58 .example('cat log | pino-pretty -t "SYS:yyyy-mm-dd HH:MM:ss"', 'To convert Epoch timestamps to local timezone format use the -t option with "SYS:" prefixed format string')
59 .example('cat log | pino-pretty -l', 'To flip level and time/date in standard output use the -l option')
60 .example('cat log | pino-pretty -s "msg == \'hello world\'"', 'Only prints messages with msg equals to \'hello world\'')
61 .example('cat log | pino-pretty -i pid,hostname', 'Prettify logs but don\'t print pid and hostname')
62 .example('cat log | pino-pretty --config=/path/to/config.json', 'Loads options from a config file')
63
64const DEFAULT_VALUE = '\0default'
65
66let opts = args.parse(process.argv, {
67 mri: {
68 default: {
69 messageKey: DEFAULT_VALUE,
70 levelKey: DEFAULT_VALUE,
71 timestampKey: DEFAULT_VALUE
72 }
73 }
74})
75
76// Remove default values
77opts = filter(opts, value => value !== DEFAULT_VALUE)
78const config = loadConfig(opts.config)
79// Override config with cli options
80opts = Object.assign({}, config, opts)
81// set defaults
82opts.errorLikeObjectKeys = opts.errorLikeObjectKeys || 'err,error'
83opts.errorProps = opts.errorProps || ''
84const pretty = prettyFactory(opts)
85const prettyTransport = new Transform({
86 objectMode: true,
87 transform (chunk, enc, cb) {
88 const line = pretty(chunk.toString())
89 if (line === undefined) return cb()
90 cb(null, line)
91 }
92})
93
94pump(process.stdin, split(), prettyTransport, process.stdout)
95
96// https://github.com/pinojs/pino/pull/358
97/* istanbul ignore next */
98if (!process.stdin.isTTY && !fs.fstatSync(process.stdin.fd).isFile()) {
99 process.once('SIGINT', function noOp () {})
100}
101
102function loadConfig (configPath) {
103 const files = configPath ? [path.resolve(configPath)] : undefined
104 const result = joycon.loadSync(files)
105 if (result.path && !isObject(result.data)) {
106 configPath = configPath || path.basename(result.path)
107 throw new Error(`Invalid runtime configuration file: ${configPath}`)
108 }
109 if (configPath && !result.data) {
110 throw new Error(`Failed to load runtime configuration file: ${configPath}`)
111 }
112 return result.data
113}
114
115function filter (obj, cb) {
116 return Object.keys(obj).reduce((acc, key) => {
117 const value = obj[key]
118 if (cb(value, key)) {
119 acc[key] = value
120 }
121 return acc
122 }, {})
123}