Merge pull request #16200 from backstage/rugvip/nometa
backend-plugin-api: inlined LogMeta type
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-test-utils': patch
|
||||
---
|
||||
|
||||
Updated the `mockServices.rootLogger` options to accept a single level option instead.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-plugin-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Switched out `LogMeta` type for `JsonObject`.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/backend-test-utils': patch
|
||||
'@backstage/backend-app-api': patch
|
||||
---
|
||||
|
||||
Updated usages of `LogMeta`.
|
||||
@@ -18,10 +18,10 @@ import { HelmetOptions } from 'helmet';
|
||||
import * as http from 'http';
|
||||
import { HttpRouterService } from '@backstage/backend-plugin-api';
|
||||
import { IdentityService } from '@backstage/backend-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { LifecycleService } from '@backstage/backend-plugin-api';
|
||||
import { LoadConfigOptionsRemote } from '@backstage/config-loader';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
import { LogMeta } from '@backstage/backend-plugin-api';
|
||||
import { PermissionsService } from '@backstage/backend-plugin-api';
|
||||
import { PluginCacheManager } from '@backstage/backend-common';
|
||||
import { PluginDatabaseManager } from '@backstage/backend-common';
|
||||
@@ -267,21 +267,21 @@ export class WinstonLogger implements RootLoggerService {
|
||||
// (undocumented)
|
||||
addRedactions(redactions: Iterable<string>): void;
|
||||
// (undocumented)
|
||||
child(meta: LogMeta): LoggerService;
|
||||
child(meta: JsonObject): LoggerService;
|
||||
static colorFormat(): Format;
|
||||
static create(options: WinstonLoggerOptions): WinstonLogger;
|
||||
// (undocumented)
|
||||
debug(message: string, meta?: LogMeta): void;
|
||||
debug(message: string, meta?: JsonObject): void;
|
||||
// (undocumented)
|
||||
error(message: string, meta?: LogMeta): void;
|
||||
error(message: string, meta?: JsonObject): void;
|
||||
// (undocumented)
|
||||
info(message: string, meta?: LogMeta): void;
|
||||
info(message: string, meta?: JsonObject): void;
|
||||
static redacter(): {
|
||||
format: Format;
|
||||
add: (redactions: Iterable<string>) => void;
|
||||
};
|
||||
// (undocumented)
|
||||
warn(message: string, meta?: LogMeta): void;
|
||||
warn(message: string, meta?: JsonObject): void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
@@ -291,7 +291,7 @@ export interface WinstonLoggerOptions {
|
||||
// (undocumented)
|
||||
level: string;
|
||||
// (undocumented)
|
||||
meta?: LogMeta;
|
||||
meta?: JsonObject;
|
||||
// (undocumented)
|
||||
transports: transport[];
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
import {
|
||||
LoggerService,
|
||||
LogMeta,
|
||||
RootLoggerService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { Format, TransformableInfo } from 'logform';
|
||||
import {
|
||||
Logger,
|
||||
@@ -33,7 +33,7 @@ import { escapeRegExp } from '../lib/escapeRegExp';
|
||||
* @public
|
||||
*/
|
||||
export interface WinstonLoggerOptions {
|
||||
meta?: LogMeta;
|
||||
meta?: JsonObject;
|
||||
level: string;
|
||||
format: Format;
|
||||
transports: Transport[];
|
||||
@@ -150,23 +150,23 @@ export class WinstonLogger implements RootLoggerService {
|
||||
this.#addRedactions = addRedactions;
|
||||
}
|
||||
|
||||
error(message: string, meta?: LogMeta): void {
|
||||
error(message: string, meta?: JsonObject): void {
|
||||
this.#winston.error(message, meta);
|
||||
}
|
||||
|
||||
warn(message: string, meta?: LogMeta): void {
|
||||
warn(message: string, meta?: JsonObject): void {
|
||||
this.#winston.warn(message, meta);
|
||||
}
|
||||
|
||||
info(message: string, meta?: LogMeta): void {
|
||||
info(message: string, meta?: JsonObject): void {
|
||||
this.#winston.info(message, meta);
|
||||
}
|
||||
|
||||
debug(message: string, meta?: LogMeta): void {
|
||||
debug(message: string, meta?: JsonObject): void {
|
||||
this.#winston.debug(message, meta);
|
||||
}
|
||||
|
||||
child(meta: LogMeta): LoggerService {
|
||||
child(meta: JsonObject): LoggerService {
|
||||
return new WinstonLogger(this.#winston.child(meta));
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { Logger as WinstonLogger, createLogger } from 'winston';
|
||||
import Transport, { TransportStreamOptions } from 'winston-transport';
|
||||
|
||||
@@ -31,7 +32,7 @@ class BackstageLoggerTransport extends Transport {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const { level, message, ...meta } = info as { [name: string]: unknown };
|
||||
const { level, message, ...meta } = info as JsonObject;
|
||||
switch (level) {
|
||||
case 'error':
|
||||
this.backstageLogger.error(String(message), meta);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { Config } from '@backstage/config';
|
||||
import { Handler } from 'express';
|
||||
import { IdentityApi } from '@backstage/plugin-auth-node';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { Knex } from 'knex';
|
||||
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
|
||||
@@ -311,22 +312,17 @@ export interface LifecycleServiceShutdownOptions {
|
||||
// @public
|
||||
export interface LoggerService {
|
||||
// (undocumented)
|
||||
child(meta: LogMeta): LoggerService;
|
||||
child(meta: JsonObject): LoggerService;
|
||||
// (undocumented)
|
||||
debug(message: string, meta?: Error | LogMeta): void;
|
||||
debug(message: string, meta?: Error | JsonObject): void;
|
||||
// (undocumented)
|
||||
error(message: string, meta?: Error | LogMeta): void;
|
||||
error(message: string, meta?: Error | JsonObject): void;
|
||||
// (undocumented)
|
||||
info(message: string, meta?: Error | LogMeta): void;
|
||||
info(message: string, meta?: Error | JsonObject): void;
|
||||
// (undocumented)
|
||||
warn(message: string, meta?: Error | LogMeta): void;
|
||||
warn(message: string, meta?: Error | JsonObject): void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type LogMeta = {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface PermissionsService extends PermissionEvaluator {}
|
||||
|
||||
|
||||
@@ -14,10 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type LogMeta = { [name: string]: unknown };
|
||||
import { JsonObject } from '@backstage/types';
|
||||
|
||||
/**
|
||||
* A service that provides a logging facility.
|
||||
@@ -25,10 +22,10 @@ export type LogMeta = { [name: string]: unknown };
|
||||
* @public
|
||||
*/
|
||||
export interface LoggerService {
|
||||
error(message: string, meta?: Error | LogMeta): void;
|
||||
warn(message: string, meta?: Error | LogMeta): void;
|
||||
info(message: string, meta?: Error | LogMeta): void;
|
||||
debug(message: string, meta?: Error | LogMeta): void;
|
||||
error(message: string, meta?: Error | JsonObject): void;
|
||||
warn(message: string, meta?: Error | JsonObject): void;
|
||||
info(message: string, meta?: Error | JsonObject): void;
|
||||
debug(message: string, meta?: Error | JsonObject): void;
|
||||
|
||||
child(meta: LogMeta): LoggerService;
|
||||
child(meta: JsonObject): LoggerService;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export type {
|
||||
LifecycleServiceShutdownHook,
|
||||
LifecycleServiceShutdownOptions,
|
||||
} from './LifecycleService';
|
||||
export type { LoggerService, LogMeta } from './LoggerService';
|
||||
export type { LoggerService } from './LoggerService';
|
||||
export type { PermissionsService } from './PermissionsService';
|
||||
export type { PluginMetadataService } from './PluginMetadataService';
|
||||
export type { RootHttpRouterService } from './RootHttpRouterService';
|
||||
|
||||
@@ -91,14 +91,7 @@ export namespace mockServices {
|
||||
export namespace rootLogger {
|
||||
// (undocumented)
|
||||
export type Options = {
|
||||
levels:
|
||||
| boolean
|
||||
| {
|
||||
error: boolean;
|
||||
warn: boolean;
|
||||
info: boolean;
|
||||
debug: boolean;
|
||||
};
|
||||
level?: 'none' | 'error' | 'warn' | 'info' | 'debug';
|
||||
};
|
||||
const // (undocumented)
|
||||
factory: (options?: Options | undefined) => ServiceFactory<LoggerService>;
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { MockRootLoggerService } from './MockRootLoggerService';
|
||||
|
||||
describe('MockRootLoggerService', () => {
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('should be silent by default', () => {
|
||||
jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'debug').mockImplementation(() => {});
|
||||
|
||||
const logger = MockRootLoggerService.create();
|
||||
logger.error('error');
|
||||
logger.warn('warn');
|
||||
logger.info('info');
|
||||
logger.debug('debug');
|
||||
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
expect(console.warn).not.toHaveBeenCalled();
|
||||
expect(console.info).not.toHaveBeenCalled();
|
||||
expect(console.debug).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shuld be able to set none level', () => {
|
||||
jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'debug').mockImplementation(() => {});
|
||||
|
||||
const logger = MockRootLoggerService.create({ level: 'none' });
|
||||
logger.error('error');
|
||||
logger.warn('warn');
|
||||
logger.info('info');
|
||||
logger.debug('debug');
|
||||
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
expect(console.warn).not.toHaveBeenCalled();
|
||||
expect(console.info).not.toHaveBeenCalled();
|
||||
expect(console.debug).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shuld be able to set error level', () => {
|
||||
jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'debug').mockImplementation(() => {});
|
||||
|
||||
const logger = MockRootLoggerService.create({ level: 'error' });
|
||||
logger.error('error');
|
||||
logger.warn('warn');
|
||||
logger.info('info');
|
||||
logger.debug('debug');
|
||||
|
||||
expect(console.error).toHaveBeenCalled();
|
||||
expect(console.warn).not.toHaveBeenCalled();
|
||||
expect(console.info).not.toHaveBeenCalled();
|
||||
expect(console.debug).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shuld be able to set warn level', () => {
|
||||
jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'debug').mockImplementation(() => {});
|
||||
|
||||
const logger = MockRootLoggerService.create({ level: 'warn' });
|
||||
logger.error('error');
|
||||
logger.warn('warn');
|
||||
logger.info('info');
|
||||
logger.debug('debug');
|
||||
|
||||
expect(console.error).toHaveBeenCalled();
|
||||
expect(console.warn).toHaveBeenCalled();
|
||||
expect(console.info).not.toHaveBeenCalled();
|
||||
expect(console.debug).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shuld be able to set info level', () => {
|
||||
jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'debug').mockImplementation(() => {});
|
||||
|
||||
const logger = MockRootLoggerService.create({ level: 'info' });
|
||||
logger.error('error');
|
||||
logger.warn('warn');
|
||||
logger.info('info');
|
||||
logger.debug('debug');
|
||||
|
||||
expect(console.error).toHaveBeenCalled();
|
||||
expect(console.warn).toHaveBeenCalled();
|
||||
expect(console.info).toHaveBeenCalled();
|
||||
expect(console.debug).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shuld be able to set debug level', () => {
|
||||
jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'debug').mockImplementation(() => {});
|
||||
|
||||
const logger = MockRootLoggerService.create({ level: 'debug' });
|
||||
logger.error('error');
|
||||
logger.warn('warn');
|
||||
logger.info('info');
|
||||
logger.debug('debug');
|
||||
|
||||
expect(console.error).toHaveBeenCalled();
|
||||
expect(console.warn).toHaveBeenCalled();
|
||||
expect(console.info).toHaveBeenCalled();
|
||||
expect(console.debug).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -16,58 +16,65 @@
|
||||
|
||||
import {
|
||||
LoggerService,
|
||||
LogMeta,
|
||||
RootLoggerService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import type { mockServices } from './mockServices';
|
||||
|
||||
export class MockRootLoggerService implements RootLoggerService {
|
||||
#levels: Exclude<mockServices.rootLogger.Options['levels'], boolean>;
|
||||
#meta: LogMeta;
|
||||
const levels = {
|
||||
none: 0,
|
||||
error: 1,
|
||||
warn: 2,
|
||||
info: 3,
|
||||
debug: 4,
|
||||
};
|
||||
|
||||
error(message: string, meta?: LogMeta | Error | undefined): void {
|
||||
export class MockRootLoggerService implements RootLoggerService {
|
||||
#level: number;
|
||||
#meta: JsonObject;
|
||||
|
||||
static create(
|
||||
options?: mockServices.rootLogger.Options,
|
||||
): MockRootLoggerService {
|
||||
const level = options?.level ?? 'none';
|
||||
if (!(level in levels)) {
|
||||
throw new Error(`Invalid log level '${level}'`);
|
||||
}
|
||||
return new MockRootLoggerService(levels[level], {});
|
||||
}
|
||||
|
||||
error(message: string, meta?: JsonObject | Error | undefined): void {
|
||||
this.#log('error', message, meta);
|
||||
}
|
||||
|
||||
warn(message: string, meta?: LogMeta | Error | undefined): void {
|
||||
warn(message: string, meta?: JsonObject | Error | undefined): void {
|
||||
this.#log('warn', message, meta);
|
||||
}
|
||||
|
||||
info(message: string, meta?: LogMeta | Error | undefined): void {
|
||||
info(message: string, meta?: JsonObject | Error | undefined): void {
|
||||
this.#log('info', message, meta);
|
||||
}
|
||||
|
||||
debug(message: string, meta?: LogMeta | Error | undefined): void {
|
||||
debug(message: string, meta?: JsonObject | Error | undefined): void {
|
||||
this.#log('debug', message, meta);
|
||||
}
|
||||
|
||||
child(meta: LogMeta): LoggerService {
|
||||
return new MockRootLoggerService(this.#levels, { ...this.#meta, ...meta });
|
||||
child(meta: JsonObject): LoggerService {
|
||||
return new MockRootLoggerService(this.#level, { ...this.#meta, ...meta });
|
||||
}
|
||||
|
||||
constructor(
|
||||
levels: mockServices.rootLogger.Options['levels'],
|
||||
meta: LogMeta,
|
||||
) {
|
||||
if (typeof levels === 'boolean') {
|
||||
this.#levels = {
|
||||
error: levels,
|
||||
debug: levels,
|
||||
info: levels,
|
||||
warn: levels,
|
||||
};
|
||||
} else {
|
||||
this.#levels = levels;
|
||||
}
|
||||
private constructor(level: number, meta: JsonObject) {
|
||||
this.#level = level;
|
||||
this.#meta = meta;
|
||||
}
|
||||
|
||||
#log(
|
||||
level: 'error' | 'warn' | 'info' | 'debug',
|
||||
message: string,
|
||||
meta?: LogMeta | Error | undefined,
|
||||
meta?: JsonObject | Error | undefined,
|
||||
) {
|
||||
if (this.#levels[level]) {
|
||||
const levelValue = levels[level] ?? 0;
|
||||
if (levelValue <= this.#level) {
|
||||
const labels = Object.entries(this.#meta)
|
||||
.map(([key, value]) => `${key}=${value}`)
|
||||
.join(',');
|
||||
|
||||
@@ -67,13 +67,11 @@ export namespace mockServices {
|
||||
}
|
||||
|
||||
export function rootLogger(options?: rootLogger.Options): LoggerService {
|
||||
return new MockRootLoggerService(options?.levels ?? false, {});
|
||||
return MockRootLoggerService.create(options);
|
||||
}
|
||||
export namespace rootLogger {
|
||||
export type Options = {
|
||||
levels:
|
||||
| boolean
|
||||
| { error: boolean; warn: boolean; info: boolean; debug: boolean };
|
||||
level?: 'none' | 'error' | 'warn' | 'info' | 'debug';
|
||||
};
|
||||
|
||||
export const factory = simpleFactory(coreServices.rootLogger, rootLogger);
|
||||
|
||||
Reference in New Issue
Block a user