From fd3fdd0e33383a704a00aec5044f7e4db6433e46 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 18 Sep 2023 11:12:22 +0200 Subject: [PATCH] backend-common: lazy root logger initialization Signed-off-by: Patrik Oldsberg --- .changeset/friendly-teachers-attend.md | 5 ++ .../src/logging/createRootLogger.ts | 57 ++++++++++++++++--- .../src/logging/globalLoggers.ts | 4 ++ 3 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 .changeset/friendly-teachers-attend.md diff --git a/.changeset/friendly-teachers-attend.md b/.changeset/friendly-teachers-attend.md new file mode 100644 index 0000000000..6d5c3cf745 --- /dev/null +++ b/.changeset/friendly-teachers-attend.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +The root logger is now initialized lazily, fixing a circular dependency issue with `@backstage/backend-app-api` that would result in `Cannot read properties of undefined (reading 'redacter')`. diff --git a/packages/backend-common/src/logging/createRootLogger.ts b/packages/backend-common/src/logging/createRootLogger.ts index 2e6fe20525..f9a3ed4ba0 100644 --- a/packages/backend-common/src/logging/createRootLogger.ts +++ b/packages/backend-common/src/logging/createRootLogger.ts @@ -17,12 +17,26 @@ import { WinstonLogger } from '@backstage/backend-app-api'; import { merge } from 'lodash'; import * as winston from 'winston'; -import { LoggerOptions } from 'winston'; +import { format, LoggerOptions } from 'winston'; import { setRootLogger } from './globalLoggers'; +import { TransformableInfo } from 'logform'; -const redacter = WinstonLogger.redacter(); +const getRedacter = (() => { + let redacter: ReturnType | undefined = + undefined; + return () => { + if (!redacter) { + redacter = WinstonLogger.redacter(); + } + return redacter; + }; +})(); -export const setRootLoggerRedactionList = redacter.add; +export const setRootLoggerRedactionList = ( + redactions: Iterable, +): void => { + getRedacter().add(redactions); +}; /** * A winston formatting function that finds occurrences of filteredKeys @@ -33,15 +47,44 @@ export const setRootLoggerRedactionList = redacter.add; export function redactWinstonLogLine( info: winston.Logform.TransformableInfo, ): winston.Logform.TransformableInfo { - return redacter.format.transform(info) as winston.Logform.TransformableInfo; + return getRedacter().format.transform( + info, + ) as winston.Logform.TransformableInfo; } +const colorizer = format.colorize(); + +// NOTE: This is a copy of the WinstonLogger.colorFormat to avoid a circular dependency /** * Creates a pretty printed winston log formatter. * * @public */ -export const coloredFormat = WinstonLogger.colorFormat(); +export const coloredFormat = format.combine( + format.timestamp(), + format.colorize({ + colors: { + timestamp: 'dim', + prefix: 'blue', + field: 'cyan', + debug: 'grey', + }, + }), + format.printf((info: TransformableInfo) => { + const { timestamp, level, message, plugin, service, ...fields } = info; + const prefix = plugin || service; + const timestampColor = colorizer.colorize('timestamp', timestamp); + const prefixColor = colorizer.colorize('prefix', prefix); + + const extraFields = Object.entries(fields) + .map( + ([key, value]) => `${colorizer.colorize('field', `${key}`)}=${value}`, + ) + .join(' '); + + return `${timestampColor} ${prefixColor} ${level} ${message} ${extraFields}`; + }), +); /** * Creates a default "root" logger. This also calls {@link setRootLogger} under @@ -64,7 +107,7 @@ export function createRootLogger( { level: env.LOG_LEVEL || 'info', format: winston.format.combine( - redacter.format, + getRedacter().format, env.NODE_ENV === 'production' ? winston.format.json() : WinstonLogger.colorFormat(), @@ -84,5 +127,3 @@ export function createRootLogger( return logger; } - -setRootLogger(createRootLogger()); diff --git a/packages/backend-common/src/logging/globalLoggers.ts b/packages/backend-common/src/logging/globalLoggers.ts index 7567deb646..8b473db211 100644 --- a/packages/backend-common/src/logging/globalLoggers.ts +++ b/packages/backend-common/src/logging/globalLoggers.ts @@ -15,6 +15,7 @@ */ import * as winston from 'winston'; +import { createRootLogger } from './createRootLogger'; /** * A logger that just throws away all messages. @@ -35,6 +36,9 @@ let rootLogger: winston.Logger; * @public */ export function getRootLogger(): winston.Logger { + if (!rootLogger) { + rootLogger = createRootLogger(); + } return rootLogger; }