A universal JSON logger that plugs in to the existing console.log
native function.
A no fuss simple drop-in replacement for console.log()
, console.info()
,
console.error()
to handle anything you throw at it and have the
output be formatted to a consistent format in a single JSON line of text, including stack traces (if passing an error object),
so that it can be easily parsed by tool such as LogDNA.
- The order of parameters or number of parameters don't matter, it figures out how to log it.
- Handles circular references
- Automatically add a date stamp in UTC to every log.
- Automatically parse stack traces and format them into a single line for for easy parsing in log management software such as LogDNA.
- Log extra context if passed in.
- Won't crash out and cause the application to stop, if there is a problem with logger, instead try to fall back to original console.log, output what is possible and continue.
- Logging is done in a non awaiting promise so that we yield to other processing while logging
- Logs via error level when message contains the word "error" to properly flag errors even if a mistake is made using the wrong console.info instead of console.error.
- Install
npm install console-log-json
- At the entry point of the application include the package and run LoggerAdaptToConsole()
This will adapt console.log(), console.error(), etc... to take in any string, or object, in any order or any number of them, and it will log a consistently formatted single line JSON to console. For example:
import { LoggerAdaptToConsole } from "console-log-json"; LoggerAdaptToConsole();
will produce:console.warn('this is a message', {'some-extra-data': 'hello'});
{"level":"warn","message":"this is a message","some-extra-data":"hello","@timestamp":"2019-11-29T21:44:40.463Z"}
To suppress some bits of the log to make it less noisy you can set these environment variables:
- CONSOLE_LOG_JSON_NO_FILE_NAME="true"
- Omits
@filename
in log
- Omits
- CONSOLE_LOG_JSON_NO_PACKAGE_NAME="true"
- Omits
@packageName
in log
- Omits
- CONSOLE_LOG_JSON_NO_TIME_STAMP="true"
- Omits
@timestamp
in log
- Omits
- CONSOLE_LOG_JSON_NO_STACK_FOR_NON_ERROR="true"
- Omits
@logCallStack
in log
- Omits
- CONSOLE_LOG_JSON_NO_LOGGER_DEBUG="true"
- Omits
_loggerDebug
in log
- Omits
- CONSOLE_LOG_JSON_NO_NEW_LINE_CHARACTERS="true"
- Omits
\n
new line characters in the log string. -- the presence of these can help format the log for readability for some log analyzers. But it can cause problems for others. You can turn them off with this.
- Omits
const err = new Error('this is a test');
console.log('hello world', err);
Will produce:
{"level":"error","message":"hello world - this is a test","stack":"Error: this is a test at Context.<anonymous> (console-log-json/test/logger.test.ts:260:17) at callFn (console-log-json/node_modules/mocha/lib/runnable.js:387:21) at Test.Runnable.run (console-log-json/node_modules/mocha/lib/runnable.js:379:7) at Runner.runTest (console-log-json/node_modules/mocha/lib/runner.js:535:10) at console-log-json/node_modules/mocha/lib/runner.js:653:12 at next (console-log-json/node_modules/mocha/lib/runner.js:447:14) at console-log-json/node_modules/mocha/lib/runner.js:457:7 at next (console-log-json/node_modules/mocha/lib/runner.js:362:14) at Immediate._onImmediate (console-log-json/node_modules/mocha/lib/runner.js:425:5) at processImmediate (internal/timers.js:439:21)","@timestamp":"2019-11-29T21:55:33.443Z"}
- Notice the log level
error
is automatically chosen even though we usedconsole.log()
instead ofconsole.error()
this is because we passed in a error object, so it makes sense to log it as log level error. - Notice the stack trace is included and formatted into one line as to not interfere with logging services such as LogDNA. This allows them to interpret the whole thing as a single log event, rather than spread out over multiple lines, possibly even interweaved with other logs.
- The string "hello world" is included together with the same log.
- Any number of additional strings or objects can be included in the console.log() parameters, in any order and it will be handled consistently and sensibly.
const extraInfo = {firstName: 'homer', lastName: 'simpson'};
console.log(extraInfo, 'hello world');
Will produce:
{"level":"info","message":"hello world","age":25,"firstName":"homer","lastName":"simpson","location":"mars","@timestamp":"2019-12-01T04:10:38.861Z"}
- Notice that even though we supplied
hello world
as the last parameter it is still logged out as themessage
property and is always the first thing after the loglevel
- Notice the
extraInnfo
data is split out and included as individual properties at the top level ready for easy parsing and filtering in logging tools such as LogDNA.
const extraInfo1 = {firstName: 'homer', lastName: 'simpson'};
const extraInfo2 = {age: 25, location: 'mars'};
console.log(extraInfo1, 'hello world', extraInfo2);
Will produce:
{"level":"info","message":"hello world","age":25,"firstName":"homer","lastName":"simpson","location":"mars","@timestamp":"2019-12-01T04:10:38.861Z"}
- Again notice that we are not picky about the order in which the parameters are passed in to console.log()
- Notice that properties fo
extraInfo1
andextraInfo2
are extracted and all logged in on line at the top level for easy parsing and filtering in logging tools such as LogDNA. - Notice that properties such as
firstName
andage
etc are sorted alphabetically for consistent appearance of logs in JSON no matter what order they are passed in.