Skip to content

Commit

Permalink
Add console patches
Browse files Browse the repository at this point in the history
  • Loading branch information
atkinchris committed Apr 30, 2021
1 parent 9b70458 commit cde1af7
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 5 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ This is a library to patch the logging functions used by [Next.js](https://nextj

This works by importing Next.js' inbuilt [logger](https://github.com/vercel/next.js/blob/canary/packages/next/build/output/log.ts) via `require`, and replacing the logging methods with custom ones. It uses [`pino`](https://github.com/pinojs/pino) to output JSON formatted logs, preserving Next.js' message and prefix, but adding timestamp, hostname and more.

From v2.0.0 onwards, this library also patches the global `console` methods, to catch additional logs that Next.js makes directly to `console`. While `pino` logging remains intact, this may cause issues with other libraries which patch or use `console` methods. Use the `next-only` preset to opt-out of this patching.

## Example Logs

Before:
Expand Down
7 changes: 7 additions & 0 deletions lib/patches/console.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const buildJsonLogger = require('../jsonLogger')

const consoleMethods = ['log', 'debug', 'info', 'warn', 'error']
consoleMethods.forEach(method => {
// eslint-disable-next-line no-console
console[method] = buildJsonLogger(method)
})
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next-logger",
"version": "1.3.0",
"version": "2.0.0",
"description": "JSON logging patcher for Next.js",
"main": "index.js",
"scripts": {
Expand Down
1 change: 1 addition & 0 deletions presets/all.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
require('../lib/patches/next')
require('../lib/patches/console')
20 changes: 19 additions & 1 deletion tests/presets.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@ describe('presets', () => {
})

describe('next-only', () => {
scenarioRunner(scenarios.next, 'next-only')
const preset = 'next-only'
scenarioRunner(scenarios.next, preset)

it.each([
['log', `'Message for log'`, 'Message for log', ''],
['log', `{ 'msg': 'log' }`, `{ msg: 'log' }`, ''],
['debug', `'Message for debug'`, 'Message for debug', ''],
['debug', `{ 'msg': 'debug' }`, `{ msg: 'debug' }`, ''],
['info', `'Message for info'`, 'Message for info', ''],
['info', `{ 'msg': 'info' }`, `{ msg: 'info' }`, ''],
['warn', `'Message for warn'`, '', 'Message for warn'],
['warn', `{ 'msg': 'warn' }`, '', `{ msg: 'warn' }`],
['error', `'Message for error'`, '', 'Message for error'],
['error', `{ 'msg': 'error' }`, '', `{ msg: 'error' }`],
])('logs an unpatched output from console."%s"', async (method, payload, stdout, stderr) => {
const result = await scenarioRunner.runScript(`console.${method}(${payload})`, preset)
expect(result.stdout).toBe(stdout)
expect(result.stderr).toBe(stderr)
})
})
})
3 changes: 2 additions & 1 deletion tests/runner.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable jest/no-export */
const { exec } = require('child_process')
const { promisify } = require('util')
const os = require('os')
Expand Down Expand Up @@ -62,5 +63,5 @@ const scenarioRunner = (scenarios, preset) =>
})
})

// eslint-disable-next-line jest/no-export
module.exports = scenarioRunner
module.exports.runScript = runScript
68 changes: 67 additions & 1 deletion tests/scenarios.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ const buildNextJsScript = (method, payload) => `
require('next/dist/build/output/log').${method}(${payload})
`

const buildConsoleScript = (method, payload) => `
console.${method}(${payload})
`

const nextScenarios = [
// Next.js logger - basic messages
[
Expand Down Expand Up @@ -67,5 +71,67 @@ const nextScenarios = [
],
]

module.exports = [...nextScenarios]
const consoleScenarios = [
// Console error - message
[
'console.log - message',
buildConsoleScript('log', "'Message for log'"),
{ level: 30, name: 'next.js', msg: 'Message for log', prefix: 'log' },
],
[
'console.debug - message',
buildConsoleScript('debug', "'Message for debug'"),
{ level: 30, name: 'next.js', msg: 'Message for debug', prefix: 'debug' },
],
[
'console.info - message',
buildConsoleScript('info', "'Message for info'"),
{ level: 30, name: 'next.js', msg: 'Message for info', prefix: 'info' },
],
[
'console.warn - message',
buildConsoleScript('warn', "'Message for warn'"),
{ level: 40, name: 'next.js', msg: 'Message for warn', prefix: 'warn' },
],
[
'console.error - message',
buildConsoleScript('error', "'Message for error'"),
{ level: 50, name: 'next.js', msg: 'Message for error', prefix: 'error' },
],
// Console error - object
[
'console.log - object',
buildConsoleScript('log', "{ foo: 'Message for log' }"),
{ level: 30, name: 'next.js', msg: { foo: 'Message for log' }, prefix: 'log' },
],
[
'console.debug - object',
buildConsoleScript('debug', "{ foo: 'Message for debug' }"),
{ level: 30, name: 'next.js', msg: { foo: 'Message for debug' }, prefix: 'debug' },
],
[
'console.info - object',
buildConsoleScript('info', "{ foo: 'Message for info' }"),
{ level: 30, name: 'next.js', msg: { foo: 'Message for info' }, prefix: 'info' },
],
[
'console.warn - object',
buildConsoleScript('warn', "{ foo: 'Message for warn' }"),
{ level: 40, name: 'next.js', msg: { foo: 'Message for warn' }, prefix: 'warn' },
],
[
'console.error - object',
buildConsoleScript('error', "{ foo: 'Message for error' }"),
{ level: 50, name: 'next.js', msg: { foo: 'Message for error' }, prefix: 'error' },
],
// Sanity checks for Pino to make sure `console.*` isn't broken
[
'pino - sanity check',
`require('pino')({ name: 'default-pino' }).info('Message')`,
{ level: 30, name: 'default-pino', msg: 'Message' },
],
]

module.exports = [...nextScenarios, ...consoleScenarios]
module.exports.next = nextScenarios
module.exports.console = consoleScenarios

0 comments on commit cde1af7

Please sign in to comment.