Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow passing in a custom logger #22587

Open
wants to merge 5 commits into
base: canary
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/next/next-server/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ export type ServerConstructor = {
* Hide error messages containing server information - @default false
*/
quiet?: boolean
/**
* Custom logger for error - @default null
*/
logger?: ((err: Error) => void) | null
/**
* Object what you would use in next.config.js - @default {}
*/
Expand All @@ -132,6 +136,7 @@ export type ServerConstructor = {
export default class Server {
protected dir: string
protected quiet: boolean
protected logger: ((err: Error) => void) | null
protected nextConfig: NextConfig
protected distDir: string
protected pagesDir?: string
Expand Down Expand Up @@ -173,13 +178,15 @@ export default class Server {
public constructor({
dir = '.',
quiet = false,
logger = null,
conf,
dev = false,
minimalMode = false,
customServer = true,
}: ServerConstructor & { conf: NextConfig; minimalMode?: boolean }) {
this.dir = resolve(dir)
this.quiet = quiet
this.logger = logger
loadEnvConfig(this.dir, dev, Log)

this.nextConfig = conf
Expand Down Expand Up @@ -282,6 +289,10 @@ export default class Server {

public logError(err: Error): void {
if (this.quiet) return
if (this.logger) {
this.logger(err)
return
}
console.error(err)
}

Expand Down
12 changes: 12 additions & 0 deletions test/integration/custom-logger/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const getServerSideProps = ({ req }) => {
if (req.url === '/index?error=true') {
throw new Error('error from app')
}
return {
props: {},
}
}

const Page = () => 'hi'

export default Page
33 changes: 33 additions & 0 deletions test/integration/custom-logger/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const http = require('http')
const next = require('next')

const dev = process.env.NODE_ENV !== 'production'
const dir = __dirname
const port = process.env.PORT || 3000

const app = next({
dev,
dir,
logger: (err) => {
console.error('custom logger:', err)
},
})
const handleNextRequests = app.getRequestHandler()

app.prepare().then(() => {
const server = new http.Server(async (req, res) => {
if (/index/.test(req.url)) {
return app.render(req, res, '/index')
}

handleNextRequests(req, res)
})

server.listen(port, (err) => {
if (err) {
throw err
}

console.log(`> Ready on http://localhost:${port}`)
})
})
78 changes: 78 additions & 0 deletions test/integration/custom-logger/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* eslint-env jest */

import { join } from 'path'
import getPort from 'get-port'
import clone from 'clone'
import {
initNextServerScript,
killApp,
renderViaHTTP,
nextBuild,
} from 'next-test-utils'

const appDir = join(__dirname, '../')

let appPort
let server
jest.setTimeout(1000 * 60 * 2)

const context = {}

const startServer = async (optEnv = {}, opts) => {
const scriptPath = join(appDir, 'server.js')
context.appPort = appPort = await getPort()
const env = Object.assign(
{},
clone(process.env),
{ PORT: `${appPort}` },
optEnv
)

server = await initNextServerScript(
scriptPath,
/ready on/i,
env,
/ReferenceError: options is not defined/,
opts
)
}

describe('Custom Logger', () => {
afterEach(() => killApp(server))

it('should not use custom logger in dev mode', async () => {
let stderr = ''
await startServer(
{},
{
onStderr(msg) {
stderr += msg || ''
},
}
)
const html = await renderViaHTTP(appPort, '/index?error=true')
expect(html).toContain('error from app')
expect(stderr).not.toContain('custom logger')
expect(stderr).toContain('error from app')
})

it('should use custom logger in production mode', async () => {
const { code } = await nextBuild(appDir)
expect(code).toBe(0)

let stderr = ''

await startServer(
{ NODE_ENV: 'production' },
{
onStderr(msg) {
stderr += msg || ''
},
}
)

const html = await renderViaHTTP(appPort, '/index?error=true')
expect(html).toContain('Internal Server Error')
expect(stderr).toContain('custom logger: Error: error from app')
})
})