feat(backend-common): support custom logger options
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Updated the `rootLogger` in `@backstage/backend-common` to support custom logging options. This is useful when you want to make some changes without re-implementing the entire logger and calling `setRootLogger` or `logger.configure`. For example you can add additional `defaultMeta` tags to each log entry. The following changes are included:
|
||||
|
||||
- Added `createRootLogger` which accepts winston `LoggerOptions`. These options allow overriding the default keys.
|
||||
- Added an additional error format that can include stack traces. This can be enabled by setting a `LOG_STACKTRACE=true` environment variable. Any `Error` objects passed to `logger.error('message', err)` will include the full stack trace in a `stack` log entry key.
|
||||
|
||||
Example Usage:
|
||||
|
||||
```ts
|
||||
// Create the logger
|
||||
const logger = createRootLogger({
|
||||
defaultMeta: { appName: 'backstage', appEnv: 'prod' },
|
||||
});
|
||||
|
||||
// Add a custom logger transport
|
||||
logger.add(new MyCustomTransport());
|
||||
|
||||
const config = await loadBackendConfig({
|
||||
argv: process.argv,
|
||||
logger: getRootLogger(), // already set to new logger instance
|
||||
});
|
||||
```
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as winston from 'winston';
|
||||
import { TransformableInfo } from 'logform';
|
||||
|
||||
|
||||
@@ -14,5 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './formats';
|
||||
export * from './rootLogger';
|
||||
export * from './voidLogger';
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import * as winston from 'winston';
|
||||
import { getRootLogger, setRootLogger } from './rootLogger';
|
||||
import { createRootLogger, getRootLogger, setRootLogger } from './rootLogger';
|
||||
|
||||
describe('rootLogger', () => {
|
||||
it('can replace the default logger', () => {
|
||||
@@ -29,4 +29,70 @@ describe('rootLogger', () => {
|
||||
expect.stringContaining('testing'),
|
||||
);
|
||||
});
|
||||
|
||||
describe('createRootLoger', () => {
|
||||
it('creates a new logger', () => {
|
||||
const oldLogger = getRootLogger();
|
||||
const newLogger = createRootLogger();
|
||||
|
||||
expect(oldLogger).not.toBe(newLogger);
|
||||
});
|
||||
|
||||
it('replaces the existing root logger', () => {
|
||||
const oldLogger = getRootLogger();
|
||||
createRootLogger();
|
||||
const newLogger = getRootLogger();
|
||||
expect(oldLogger).not.toBe(newLogger);
|
||||
});
|
||||
|
||||
it('can append additional default metadata', () => {
|
||||
const format = winston.format.json();
|
||||
const logger = createRootLogger({
|
||||
format,
|
||||
defaultMeta: {
|
||||
appName: 'backstage',
|
||||
appEnv: 'prod',
|
||||
containerId: 'abc',
|
||||
},
|
||||
});
|
||||
jest.spyOn(format, 'transform');
|
||||
|
||||
logger.info('testing');
|
||||
|
||||
expect(format.transform).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
message: 'testing',
|
||||
service: 'backstage',
|
||||
appName: 'backstage',
|
||||
appEnv: 'prod',
|
||||
containerId: 'abc',
|
||||
}),
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
it('can add override existing transports', () => {
|
||||
const transport = new winston.transports.Console({ level: 'debug' });
|
||||
const logger = createRootLogger({ transports: [transport] });
|
||||
expect(logger.transports.length).toBe(1);
|
||||
expect(logger.transports[0]).toBe(transport);
|
||||
});
|
||||
|
||||
it('can append an additional transport', () => {
|
||||
const logger = createRootLogger();
|
||||
const transport = new winston.transports.Console({ level: 'debug' });
|
||||
logger.add(transport);
|
||||
expect(logger.transports.length).toBe(2);
|
||||
expect(logger.transports[1]).toBe(transport);
|
||||
expect(logger.transports[1].level).toBe('debug');
|
||||
});
|
||||
|
||||
it('can override default format', () => {
|
||||
const format = winston.format(() => false)();
|
||||
const logger = createRootLogger({ format });
|
||||
expect(
|
||||
logger.format.transform({ message: 'hello', level: 'info' }),
|
||||
).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,23 +13,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { merge } from 'lodash';
|
||||
import * as winston from 'winston';
|
||||
import { LoggerOptions } from 'winston';
|
||||
import { coloredFormat } from './formats';
|
||||
|
||||
let rootLogger: winston.Logger = winston.createLogger({
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
format:
|
||||
process.env.NODE_ENV === 'production'
|
||||
? winston.format.json()
|
||||
: coloredFormat,
|
||||
defaultMeta: { service: 'backstage' },
|
||||
transports: [
|
||||
new winston.transports.Console({
|
||||
silent:
|
||||
process.env.JEST_WORKER_ID !== undefined && !process.env.LOG_LEVEL,
|
||||
}),
|
||||
],
|
||||
});
|
||||
let rootLogger: winston.Logger;
|
||||
|
||||
export function getRootLogger(): winston.Logger {
|
||||
return rootLogger;
|
||||
@@ -38,3 +28,34 @@ export function getRootLogger(): winston.Logger {
|
||||
export function setRootLogger(newLogger: winston.Logger) {
|
||||
rootLogger = newLogger;
|
||||
}
|
||||
|
||||
export function createRootLogger(
|
||||
options: winston.LoggerOptions = {},
|
||||
env = process.env,
|
||||
): winston.Logger {
|
||||
const logger = winston.createLogger(
|
||||
merge<LoggerOptions, LoggerOptions>(
|
||||
{
|
||||
level: env.LOG_LEVEL || 'info',
|
||||
format: winston.format.combine(
|
||||
env.NODE_ENV === 'production' ? winston.format.json() : coloredFormat,
|
||||
),
|
||||
defaultMeta: {
|
||||
service: 'backstage',
|
||||
},
|
||||
transports: [
|
||||
new winston.transports.Console({
|
||||
silent: env.JEST_WORKER_ID !== undefined && !env.LOG_LEVEL,
|
||||
}),
|
||||
],
|
||||
},
|
||||
options,
|
||||
),
|
||||
);
|
||||
|
||||
setRootLogger(logger);
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
rootLogger = createRootLogger();
|
||||
|
||||
Reference in New Issue
Block a user