Skip to content

Commit d628222

Browse files
authored
feat: customize log levels and downgrade common errors to info (#9156)
### What? Allows configuration of the log level based on the error being thrown and also downgrades common errors to be info instead of error by default. ### Why? Currently all errors result in logger.error being called which can polute the logs with junk that is normal and doesn't need attention. ### How? Adds a config property called `loggingLevels` that is used to override the default log levels based on the name of the error being thrown. Sanitize config will provide the defaulted 'info' level errors which can be overriden in the config. Before ![Screenshot 2024-11-12 144459](https://github.com/user-attachments/assets/47318329-23b7-4627-afc4-a0bcf4dc3d58) After ![image](https://github.com/user-attachments/assets/85b06be4-0ab8-4ca2-b237-d6a4d54add3a)
1 parent f264c80 commit d628222

File tree

5 files changed

+56
-2
lines changed

5 files changed

+56
-2
lines changed

docs/configuration/overview.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ The following options are available:
7676
| **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More details](#cors). |
7777
| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). |
7878
| **`logger`** | Logger options, logger options with a destination stream, or an instantiated logger instance. [More details](https://getpino.io/#/docs/api?id=options). |
79+
| **`loggingLevels`** | An object to override the level to use in the logger for Payload's errors. |
7980
| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). |
8081
| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. |
8182
| **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/overview#csrf-protection). |

packages/next/src/routes/rest/routeError.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ export const routeError = async ({
4747

4848
let status = err.status || httpStatus.INTERNAL_SERVER_ERROR
4949

50-
logger.error(err.stack)
50+
const level = payload.config.loggingLevels[err.name] ?? 'error'
51+
if (level) {
52+
logger[level](level === 'info' ? { msg: err.message } : { err })
53+
}
5154

5255
// Internal server errors can contain anything, including potentially sensitive data.
5356
// Therefore, error details will be hidden from the response unless `config.debug` is `true`

packages/payload/src/config/sanitize.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ import { defaults } from './defaults.js'
2424
const sanitizeAdminConfig = (configToSanitize: Config): Partial<SanitizedConfig> => {
2525
const sanitizedConfig = { ...configToSanitize }
2626

27+
// default logging level will be 'error' if not provided
28+
sanitizedConfig.loggingLevels = {
29+
Forbidden: 'info',
30+
Locked: 'info',
31+
MissingFile: 'info',
32+
NotFound: 'info',
33+
ValidationError: 'info',
34+
...(sanitizedConfig.loggingLevels || {}),
35+
}
36+
2737
// add default user collection if none provided
2838
if (!sanitizedConfig?.admin?.user) {
2939
const firstCollectionWithAuth = sanitizedConfig.collections.find(({ auth }) => Boolean(auth))

packages/payload/src/config/types.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { BusboyConfig } from 'busboy'
88
import type GraphQL from 'graphql'
99
import type { GraphQLFormattedError } from 'graphql'
1010
import type { JSONSchema4 } from 'json-schema'
11-
import type { DestinationStream, pino } from 'pino'
11+
import type { DestinationStream, Level, pino } from 'pino'
1212
import type React from 'react'
1313
import type { default as sharp } from 'sharp'
1414
import type { DeepRequired } from 'ts-essentials'
@@ -34,6 +34,7 @@ import type {
3434
} from '../collections/config/types.js'
3535
import type { DatabaseAdapterResult } from '../database/types.js'
3636
import type { EmailAdapter, SendEmailOptions } from '../email/types.js'
37+
import type { ErrorName } from '../errors/types.js'
3738
import type { GlobalConfig, Globals, SanitizedGlobalConfig } from '../globals/config/types.js'
3839
import type { JobsConfig, Payload, RequestContext, TypedUser } from '../index.js'
3940
import type { PayloadRequest, Where } from '../types/index.js'
@@ -980,6 +981,28 @@ export type Config = {
980981
*/
981982
logger?: 'sync' | { destination?: DestinationStream; options: pino.LoggerOptions } | PayloadLogger
982983

984+
/**
985+
* Override the log level of errors for Payload's error handler or disable logging with `false`.
986+
* Levels can be any of the following: 'trace', 'debug', 'info', 'warn', 'error', 'fatal' or false.
987+
*
988+
* Default levels:
989+
* {
990+
`* APIError: 'error',
991+
`* AuthenticationError: 'error',
992+
`* ErrorDeletingFile: 'error',
993+
`* FileRetrievalError: 'error',
994+
`* FileUploadError: 'error',
995+
`* Forbidden: 'info',
996+
`* Locked: 'info',
997+
`* LockedAuth: 'error',
998+
`* MissingFile: 'info',
999+
`* NotFound: 'info',
1000+
`* QueryError: 'error',
1001+
`* ValidationError: 'info',
1002+
* }
1003+
*/
1004+
loggingLevels?: Partial<Record<ErrorName, false | Level>>
1005+
9831006
/**
9841007
* The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries.
9851008
*

packages/payload/src/errors/types.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,18 @@
11
export * from './index.js'
2+
3+
/**
4+
* Error names that can be thrown by Payload during runtime
5+
*/
6+
export type ErrorName =
7+
| 'APIError'
8+
| 'AuthenticationError'
9+
| 'ErrorDeletingFile'
10+
| 'FileRetrievalError'
11+
| 'FileUploadError'
12+
| 'Forbidden'
13+
| 'Locked'
14+
| 'LockedAuth'
15+
| 'MissingFile'
16+
| 'NotFound'
17+
| 'QueryError'
18+
| 'ValidationError'

0 commit comments

Comments
 (0)