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

feat: disable request logging #5435

Merged
merged 10 commits into from
May 2, 2024
12 changes: 9 additions & 3 deletions docs/Reference/Server.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,15 @@ been sent. By setting this option to `true`, these log messages will be
disabled. This allows for more flexible request start and end logging by
attaching custom `onRequest` and `onResponse` hooks.

Please note that this option will also disable an error log written by the
default `onResponse` hook on reply callback errors. Other log messages
emitted by Fastify will stay enabled, like deprecation warnings and messages
The other log entries that will be disabled are:
- an error log written by the default `onResponse` hook on reply callback errors
- the error and info logs written by the `defaultErrorHandler`
on error management
- the info log written by the `fourOhFour` handler when a
non existent route is requested

Other log messages emitted by Fastify will stay enabled,
like deprecation warnings and messages
emitted when requests are received while the server is closing.

```js
Expand Down
39 changes: 24 additions & 15 deletions lib/error-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ const {
kReplyNextErrorHandler,
kReplyIsRunningOnErrorHook,
kReplyHasStatusCode,
kRouteContext
kRouteContext,
kDisableRequestLogging
} = require('./symbols.js')

const {
Expand Down Expand Up @@ -35,10 +36,12 @@ function handleError (reply, error, cb) {
try {
reply.raw.writeHead(reply.raw.statusCode, reply[kReplyHeaders])
} catch (error) {
reply.log.warn(
{ req: reply.request, res: reply, err: error },
error && error.message
)
if (!reply.log[kDisableRequestLogging]) {
reply.log.warn(
{ req: reply.request, res: reply, err: error },
error && error.message
)
}
reply.raw.writeHead(reply.raw.statusCode)
}
reply.raw.end(payload)
Expand Down Expand Up @@ -79,15 +82,19 @@ function defaultErrorHandler (error, request, reply) {
reply.code(statusCode >= 400 ? statusCode : 500)
}
if (reply.statusCode < 500) {
reply.log.info(
{ res: reply, err: error },
error && error.message
)
if (!reply.log[kDisableRequestLogging]) {
reply.log.info(
{ res: reply, err: error },
error && error.message
)
}
} else {
reply.log.error(
{ req: request, res: reply, err: error },
error && error.message
)
if (!reply.log[kDisableRequestLogging]) {
reply.log.error(
{ req: request, res: reply, err: error },
error && error.message
)
}
}
reply.send(error)
}
Expand All @@ -112,8 +119,10 @@ function fallbackErrorHandler (error, reply, cb) {
statusCode: { value: statusCode }
}))
} catch (err) {
// error is always FST_ERR_SCH_SERIALIZATION_BUILD because this is called from route/compileSchemasForSerialization
reply.log.error({ err, statusCode: res.statusCode }, 'The serializer for the given status code failed')
if (!reply.log[kDisableRequestLogging]) {
// error is always FST_ERR_SCH_SERIALIZATION_BUILD because this is called from route/compileSchemasForSerialization
reply.log.error({ err, statusCode: res.statusCode }, 'The serializer for the given status code failed')
}
reply.code(500)
payload = serializeError(new FST_ERR_FAILED_ERROR_SERIALIZATION(err.message, error.message))
}
Expand Down
6 changes: 4 additions & 2 deletions lib/fourOhFour.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const { getGenReqId } = require('./reqIdGenFactory.js')
* kFourOhFourContext: the context in the reply object where the handler will be executed
*/
function fourOhFour (options) {
const { logger } = options
const { logger, disableRequestLogging } = options

// 404 router, used for handling encapsulated 404 handlers
const router = FindMyWay({ onBadUrl: createOnBadUrl(), defaultRoute: fourOhFourFallBack })
Expand All @@ -49,7 +49,9 @@ function fourOhFour (options) {
function basic404 (request, reply) {
const { url, method } = request.raw
const message = `Route ${method}:${url} not found`
request.log.info(message)
if (!disableRequestLogging) {
request.log.info(message)
}
reply.code(404).send({
message,
error: 'Not Found',
Expand Down
53 changes: 37 additions & 16 deletions test/logger/logging.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ t.test('logging', (t) => {
let localhost
let localhostForURL

t.plan(12)
t.plan(13)

t.before(async function () {
[localhost, localhostForURL] = await helper.getLoopbackHost()
Expand Down Expand Up @@ -253,7 +253,7 @@ t.test('logging', (t) => {
})

t.test('should not log incoming request and outgoing response when disabled', async (t) => {
t.plan(3)
t.plan(1)
const stream = split(JSON.parse)
const fastify = Fastify({ disableRequestLogging: true, logger: { level: 'info', stream } })
t.teardown(fastify.close.bind(fastify))
Expand All @@ -266,18 +266,12 @@ t.test('logging', (t) => {

await fastify.inject({ method: 'GET', url: '/500' })

{
const [line] = await once(stream, 'data')
t.ok(line.reqId, 'reqId is defined')
t.equal(line.msg, '500 error', 'message is set')
}

// no more readable data
t.equal(stream.readableLength, 0)
})

t.test('should not log incoming request and outgoing response for 404 onBadUrl when disabled', async (t) => {
t.plan(3)
t.test('should not log incoming request, outgoing response and route not found for 404 onBadUrl when disabled', async (t) => {
t.plan(1)
const stream = split(JSON.parse)
const fastify = Fastify({ disableRequestLogging: true, logger: { level: 'info', stream } })
t.teardown(fastify.close.bind(fastify))
Expand All @@ -286,12 +280,6 @@ t.test('logging', (t) => {

await fastify.inject({ method: 'GET', url: '/%c0' })

{
const [line] = await once(stream, 'data')
t.ok(line.reqId, 'reqId is defined')
t.equal(line.msg, 'Route GET:/%c0 not found', 'message is set')
}

// no more readable data
t.equal(stream.readableLength, 0)
})
Expand Down Expand Up @@ -403,4 +391,37 @@ t.test('logging', (t) => {
if (lines.length === 0) break
}
})

t.test('should not log the error if request logging is disabled', async (t) => {
t.plan(4)

const stream = split(JSON.parse)
const fastify = Fastify({
logger: {
stream,
level: 'info'
},
disableRequestLogging: true
})
t.teardown(fastify.close.bind(fastify))

fastify.get('/error', function (req, reply) {
t.ok(req.log)
reply.send(new Error('a generic error'))
})

await fastify.ready()
await fastify.listen({ port: 0, host: localhost })

await request(`http://${localhostForURL}:` + fastify.server.address().port + '/error')

{
const [line] = await once(stream, 'data')
t.type(line.msg, 'string')
t.ok(line.msg.startsWith('Server listening at'), 'message is set')
}

// no more readable data
t.equal(stream.readableLength, 0)
})
})