From 2dd3f400306ab719b5adf15a3e4d2bca9e70b481 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Fri, 6 Oct 2017 12:45:16 +0200 Subject: [PATCH 1/5] Introduce `LegacyJsonLayout` and `LegacyPatternLayout`. --- platform/legacy/LegacyPlatformConfig.ts | 4 +- .../__tests__/LegacyPlatformConfig.test.ts | 4 +- .../logging/layouts/LegacyJsonLayout.ts | 44 +++++++++ .../logging/layouts/LegacyPatternLayout.ts | 90 +++++++++++++++++++ .../__tests__/LegacyJsonLayout.test.ts | 80 +++++++++++++++++ .../__tests__/LegacyPatternLayout.test.ts | 87 ++++++++++++++++++ .../LegacyJsonLayout.test.ts.snap | 17 ++++ .../LegacyPatternLayout.test.ts.snap | 17 ++++ platform/logging/layouts/Layouts.ts | 22 ++++- 9 files changed, 359 insertions(+), 6 deletions(-) create mode 100644 platform/legacy/logging/layouts/LegacyJsonLayout.ts create mode 100644 platform/legacy/logging/layouts/LegacyPatternLayout.ts create mode 100644 platform/legacy/logging/layouts/__tests__/LegacyJsonLayout.test.ts create mode 100644 platform/legacy/logging/layouts/__tests__/LegacyPatternLayout.test.ts create mode 100644 platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyJsonLayout.test.ts.snap create mode 100644 platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyPatternLayout.test.ts.snap diff --git a/platform/legacy/LegacyPlatformConfig.ts b/platform/legacy/LegacyPlatformConfig.ts index f15805a68d1b0..44a792586a5a8 100644 --- a/platform/legacy/LegacyPlatformConfig.ts +++ b/platform/legacy/LegacyPlatformConfig.ts @@ -81,8 +81,8 @@ export class LegacyConfigToRawConfigAdapter implements RawConfig { } const layout = configValue.json - ? { kind: 'json' } - : { kind: 'pattern', highlight: true }; + ? { kind: 'legacy-json' } + : { kind: 'legacy-pattern' }; if (configValue.dest && configValue.dest !== 'stdout') { loggingConfig.appenders.default = { diff --git a/platform/legacy/__tests__/LegacyPlatformConfig.test.ts b/platform/legacy/__tests__/LegacyPlatformConfig.test.ts index b75dc5298f040..26d0aef3300d6 100644 --- a/platform/legacy/__tests__/LegacyPlatformConfig.test.ts +++ b/platform/legacy/__tests__/LegacyPlatformConfig.test.ts @@ -40,7 +40,7 @@ describe('Retrieving values', () => { appenders: { default: { kind: 'console', - layout: { kind: 'pattern', highlight: true } + layout: { kind: 'legacy-pattern' } } } }); @@ -57,7 +57,7 @@ describe('Retrieving values', () => { default: { kind: 'file', path: '/some/path.log', - layout: { kind: 'json' } + layout: { kind: 'legacy-json' } } } }); diff --git a/platform/legacy/logging/layouts/LegacyJsonLayout.ts b/platform/legacy/logging/layouts/LegacyJsonLayout.ts new file mode 100644 index 0000000000000..1390501535522 --- /dev/null +++ b/platform/legacy/logging/layouts/LegacyJsonLayout.ts @@ -0,0 +1,44 @@ +import { utc } from 'moment'; +import { Schema, typeOfSchema } from '../../../types/schema'; +import { LogRecord } from '../../../logging/LogRecord'; +import { Layout } from '../../../logging/layouts/Layouts'; + +const createSchema = ({ literal, object }: Schema) => { + return object({ + kind: literal('legacy-json') + }); +}; + +const schemaType = typeOfSchema(createSchema); +/** @internal */ +export type LegacyJsonLayoutConfigType = typeof schemaType; + +/** + * Layout that just converts `LogRecord` into JSON string in the same + * format as used by the legacy platform. + * @internal + */ +export class LegacyJsonLayout implements Layout { + static createConfigSchema = createSchema; + + format(record: LogRecord): string { + const recordToSerialize: { [key: string]: any } = { + type: 'log', + '@timestamp': utc(record.timestamp).format(), + tags: [record.level.id.toLowerCase(), ...record.context.split('.')], + pid: process.pid, + message: record.message + }; + + if (record.error !== undefined) { + recordToSerialize.level = record.level.id.toLowerCase(); + recordToSerialize.error = { + message: record.error.message, + name: record.error.name, + stack: record.error.stack + }; + } + + return JSON.stringify(recordToSerialize); + } +} diff --git a/platform/legacy/logging/layouts/LegacyPatternLayout.ts b/platform/legacy/logging/layouts/LegacyPatternLayout.ts new file mode 100644 index 0000000000000..8c325f93052ee --- /dev/null +++ b/platform/legacy/logging/layouts/LegacyPatternLayout.ts @@ -0,0 +1,90 @@ +import * as chalk from 'chalk'; +import { utc } from 'moment'; +import { Schema, typeOfSchema } from '../../../types/schema'; +import { LogLevel } from '../../../logging/LogLevel'; +import { LogRecord } from '../../../logging/LogRecord'; +import { Layout } from '../../../logging/layouts/Layouts'; + +/** + * A set of static constants describing supported parameters in the log message pattern. + */ +const Parameters = Object.freeze({ + Timestamp: '{timestamp}', + Level: '{level}', + Context: '{context}', + Message: '{message}' +}); + +/** + * Regular expression used to parse log message pattern and fill in placeholders + * with the actual data. + */ +const PATTERN_REGEX = new RegExp( + `${Parameters.Timestamp}|${Parameters.Level}|${Parameters.Context}|${Parameters.Message}`, + 'gi' +); + +/** + * Mapping between `LogLevel` and color that is used to highlight `level` part of + * the log message. + */ +const LEVEL_COLORS = new Map([ + [LogLevel.Fatal, chalk.magenta], + [LogLevel.Error, chalk.red], + [LogLevel.Warn, chalk.red], + [LogLevel.Info, chalk.green], + [LogLevel.Debug, chalk.gray], + [LogLevel.Trace, chalk.gray] +]); + +/** + * Default pattern used by PatternLayout if it's not overridden in the configuration. + */ +const DEFAULT_PATTERN = + `${chalk.gray('server')} ${chalk.blue('log')} ` + + `[${Parameters.Timestamp}] [${Parameters.Level}][${Parameters.Context}] ${Parameters.Message}`; + +const createSchema = ({ literal, object }: Schema) => { + return object({ kind: literal('legacy-pattern') }); +}; + +const schemaType = typeOfSchema(createSchema); +/** @internal */ +export type LegacyPatternLayoutConfigType = typeof schemaType; + +/** + * Layout that formats `LogRecord` using the `pattern` string with optional + * color highlighting (eg. to make log messages easier to read in the terminal). + * @internal + */ +export class LegacyPatternLayout implements Layout { + static createConfigSchema = createSchema; + + /** + * Formats `LogRecord` into a string based on the specified `pattern` and `highlighting` options. + * @param record Instance of `LogRecord` to format into string. + */ + format(record: LogRecord): string { + // Error stack is much more useful than just the message. + const message = (record.error && record.error.stack) || record.message; + const formattedRecord = new Map([ + [Parameters.Timestamp, utc(record.timestamp).format('HH:mm:ss.SSS')], + [Parameters.Level, record.level.id.toLowerCase()], + [Parameters.Context, record.context.replace(/\./gi, '][')], + [Parameters.Message, message] + ]); + + if (LEVEL_COLORS.has(record.level)) { + const color = LEVEL_COLORS.get(record.level)!; + formattedRecord.set( + Parameters.Level, + color(formattedRecord.get(Parameters.Level)!) + ); + } + + return DEFAULT_PATTERN.replace( + PATTERN_REGEX, + match => formattedRecord.get(match)! + ); + } +} diff --git a/platform/legacy/logging/layouts/__tests__/LegacyJsonLayout.test.ts b/platform/legacy/logging/layouts/__tests__/LegacyJsonLayout.test.ts new file mode 100644 index 0000000000000..aaa25ac4756ad --- /dev/null +++ b/platform/legacy/logging/layouts/__tests__/LegacyJsonLayout.test.ts @@ -0,0 +1,80 @@ +import * as mockSchema from '../../../../lib/schema'; + +import { LogLevel } from '../../../../logging/LogLevel'; +import { LogRecord } from '../../../../logging/LogRecord'; +import { LegacyJsonLayout } from '../LegacyJsonLayout'; + +global.process.pid = 1234; + +const timestamp = new Date(Date.UTC(2012, 1, 1, 11, 22, 33, 44)); +const records: LogRecord[] = [ + { + timestamp, + message: 'message-1', + context: 'context-1', + error: { + message: 'Some error message', + name: 'Some error name', + stack: 'Some error stack' + }, + level: LogLevel.Fatal + }, + { + timestamp, + message: 'message-2', + context: 'context-2', + level: LogLevel.Error + }, + { + timestamp, + message: 'message-2', + context: 'context-2.sub-context-2.sub-sub-context-2', + level: LogLevel.Error + }, + { + timestamp, + message: 'message-3', + context: 'context-3', + level: LogLevel.Warn + }, + { + timestamp, + message: 'message-4', + context: 'context-4', + level: LogLevel.Debug + }, + { + timestamp, + message: 'message-5', + context: 'context-5', + level: LogLevel.Info + }, + { + timestamp, + message: 'message-5', + context: 'context-5.sub-context-5', + level: LogLevel.Info + }, + { + timestamp, + message: 'message-6', + context: 'context-6', + level: LogLevel.Trace + } +]; + +test('`createConfigSchema()` creates correct schema.', () => { + const layoutSchema = LegacyJsonLayout.createConfigSchema(mockSchema); + + expect(layoutSchema.validate({ kind: 'legacy-json' })).toEqual({ + kind: 'legacy-json' + }); +}); + +test('`format()` correctly formats record.', () => { + const layout = new LegacyJsonLayout(); + + for (const record of records) { + expect(layout.format(record)).toMatchSnapshot(); + } +}); diff --git a/platform/legacy/logging/layouts/__tests__/LegacyPatternLayout.test.ts b/platform/legacy/logging/layouts/__tests__/LegacyPatternLayout.test.ts new file mode 100644 index 0000000000000..45dccef46246a --- /dev/null +++ b/platform/legacy/logging/layouts/__tests__/LegacyPatternLayout.test.ts @@ -0,0 +1,87 @@ +import * as mockSchema from '../../../../lib/schema'; + +import { LogLevel } from '../../../../logging/LogLevel'; +import { LogRecord } from '../../../../logging/LogRecord'; +import { LegacyPatternLayout } from '../LegacyPatternLayout'; + +global.process.pid = 1234; + +const timestamp = new Date(Date.UTC(2012, 1, 1, 11, 22, 33, 44)); +const records: LogRecord[] = [ + { + timestamp, + message: 'message-1', + context: 'context-1', + error: { + message: 'Some error message', + name: 'Some error name', + stack: 'Some error stack' + }, + level: LogLevel.Fatal + }, + { + timestamp, + message: 'message-2', + context: 'context-2', + level: LogLevel.Error + }, + { + timestamp, + message: 'message-2', + context: 'context-2.sub-context-2.sub-sub-context-2', + level: LogLevel.Error + }, + { + timestamp, + message: 'message-3', + context: 'context-3', + level: LogLevel.Warn + }, + { + timestamp, + message: 'message-4', + context: 'context-4', + level: LogLevel.Debug + }, + { + timestamp, + message: 'message-5', + context: 'context-5', + level: LogLevel.Info + }, + { + timestamp, + message: 'message-5', + context: 'context-5.sub-context-5', + level: LogLevel.Info + }, + { + timestamp, + message: 'message-6', + context: 'context-6', + level: LogLevel.Trace + } +]; + +test('`createConfigSchema()` creates correct schema.', () => { + const layoutSchema = LegacyPatternLayout.createConfigSchema(mockSchema); + + const validConfigWithOptional = { kind: 'legacy-pattern' }; + expect(layoutSchema.validate(validConfigWithOptional)).toEqual({ + kind: 'legacy-pattern' + }); + + const wrongConfig1 = { kind: 'json' }; + expect(() => layoutSchema.validate(wrongConfig1)).toThrow(); + + const wrongConfig2 = { kind: 'pattern', pattern: 1 }; + expect(() => layoutSchema.validate(wrongConfig2)).toThrow(); +}); + +test('`format()` correctly formats record with full pattern.', () => { + const layout = new LegacyPatternLayout(); + + for (const record of records) { + expect(layout.format(record)).toMatchSnapshot(); + } +}); diff --git a/platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyJsonLayout.test.ts.snap b/platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyJsonLayout.test.ts.snap new file mode 100644 index 0000000000000..9ad19d88b99e2 --- /dev/null +++ b/platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyJsonLayout.test.ts.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`\`format()\` correctly formats record. 1`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"fatal\\",\\"context-1\\"],\\"pid\\":1234,\\"message\\":\\"message-1\\",\\"level\\":\\"fatal\\",\\"error\\":{\\"message\\":\\"Some error message\\",\\"name\\":\\"Some error name\\",\\"stack\\":\\"Some error stack\\"}}"`; + +exports[`\`format()\` correctly formats record. 2`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"error\\",\\"context-2\\"],\\"pid\\":1234,\\"message\\":\\"message-2\\"}"`; + +exports[`\`format()\` correctly formats record. 3`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"error\\",\\"context-2\\",\\"sub-context-2\\",\\"sub-sub-context-2\\"],\\"pid\\":1234,\\"message\\":\\"message-2\\"}"`; + +exports[`\`format()\` correctly formats record. 4`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"warn\\",\\"context-3\\"],\\"pid\\":1234,\\"message\\":\\"message-3\\"}"`; + +exports[`\`format()\` correctly formats record. 5`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"debug\\",\\"context-4\\"],\\"pid\\":1234,\\"message\\":\\"message-4\\"}"`; + +exports[`\`format()\` correctly formats record. 6`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"info\\",\\"context-5\\"],\\"pid\\":1234,\\"message\\":\\"message-5\\"}"`; + +exports[`\`format()\` correctly formats record. 7`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"info\\",\\"context-5\\",\\"sub-context-5\\"],\\"pid\\":1234,\\"message\\":\\"message-5\\"}"`; + +exports[`\`format()\` correctly formats record. 8`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"trace\\",\\"context-6\\"],\\"pid\\":1234,\\"message\\":\\"message-6\\"}"`; diff --git a/platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyPatternLayout.test.ts.snap b/platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyPatternLayout.test.ts.snap new file mode 100644 index 0000000000000..227dcd4d4043b --- /dev/null +++ b/platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyPatternLayout.test.ts.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`\`format()\` correctly formats record with full pattern. 1`] = `"server log [11:22:33.044] [fatal][context-1] Some error stack"`; + +exports[`\`format()\` correctly formats record with full pattern. 2`] = `"server log [11:22:33.044] [error][context-2] message-2"`; + +exports[`\`format()\` correctly formats record with full pattern. 3`] = `"server log [11:22:33.044] [error][context-2][sub-context-2][sub-sub-context-2] message-2"`; + +exports[`\`format()\` correctly formats record with full pattern. 4`] = `"server log [11:22:33.044] [warn][context-3] message-3"`; + +exports[`\`format()\` correctly formats record with full pattern. 5`] = `"server log [11:22:33.044] [debug][context-4] message-4"`; + +exports[`\`format()\` correctly formats record with full pattern. 6`] = `"server log [11:22:33.044] [info][context-5] message-5"`; + +exports[`\`format()\` correctly formats record with full pattern. 7`] = `"server log [11:22:33.044] [info][context-5][sub-context-5] message-5"`; + +exports[`\`format()\` correctly formats record with full pattern. 8`] = `"server log [11:22:33.044] [trace][context-6] message-6"`; diff --git a/platform/logging/layouts/Layouts.ts b/platform/logging/layouts/Layouts.ts index fccf2127647b2..b2c3db5bca4cf 100644 --- a/platform/logging/layouts/Layouts.ts +++ b/platform/logging/layouts/Layouts.ts @@ -2,9 +2,21 @@ import { assertNever } from '../../lib/utils'; import { Schema } from '../../types/schema'; import { JsonLayout, JsonLayoutConfigType } from './JsonLayout'; import { PatternLayout, PatternLayoutConfigType } from './PatternLayout'; +import { + LegacyPatternLayout, + LegacyPatternLayoutConfigType +} from '../../legacy/logging/layouts/LegacyPatternLayout'; +import { + LegacyJsonLayout, + LegacyJsonLayoutConfigType +} from '../../legacy/logging/layouts/LegacyJsonLayout'; import { LogRecord } from '../LogRecord'; -type LayoutConfigType = PatternLayoutConfigType | JsonLayoutConfigType; +type LayoutConfigType = + | PatternLayoutConfigType + | JsonLayoutConfigType + | LegacyPatternLayoutConfigType + | LegacyJsonLayoutConfigType; /** * Entity that can format `LogRecord` instance into a string. @@ -21,7 +33,9 @@ export class Layouts { return oneOf([ JsonLayout.createConfigSchema(schema), - PatternLayout.createConfigSchema(schema) + PatternLayout.createConfigSchema(schema), + LegacyPatternLayout.createConfigSchema(schema), + LegacyJsonLayout.createConfigSchema(schema) ]); } @@ -36,6 +50,10 @@ export class Layouts { return new JsonLayout(); case 'pattern': return new PatternLayout(config.pattern, config.highlight); + case 'legacy-pattern': + return new LegacyPatternLayout(); + case 'legacy-json': + return new LegacyJsonLayout(); default: return assertNever(config); } From 0666d03cbbbc7b8cae8177b8dc20ee261b85c429 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Fri, 6 Oct 2017 15:50:43 +0200 Subject: [PATCH 2/5] Introduce `LegacyAppender` instead of custom legacy layouts. --- platform/README.md | 19 +++- platform/config/Env.ts | 8 +- platform/config/__tests__/Env.test.ts | 10 +-- platform/legacy/LegacyKbnServer.ts | 1 + platform/legacy/LegacyPlatformConfig.ts | 19 +--- .../__tests__/LegacyPlatformConfig.test.ts | 11 +-- .../__tests__/LegacyPlatformProxifier.test.ts | 6 +- .../logging/appenders/LegacyAppender.ts | 39 ++++++++ .../logging/layouts/LegacyJsonLayout.ts | 44 --------- .../logging/layouts/LegacyPatternLayout.ts | 90 ------------------- .../__tests__/LegacyJsonLayout.test.ts | 80 ----------------- .../__tests__/LegacyPatternLayout.test.ts | 87 ------------------ .../LegacyJsonLayout.test.ts.snap | 17 ---- .../LegacyPatternLayout.test.ts.snap | 17 ---- platform/logging/LoggerFactory.ts | 8 +- .../logging/__tests__/LoggerFactory.test.ts | 6 +- .../logging/__tests__/LoggingService.test.ts | 2 +- platform/logging/appenders/Appenders.ts | 26 ++++-- .../appenders/__tests__/Appenders.test.ts | 57 ++++++++---- .../__snapshots__/Appenders.test.ts.snap | 3 + platform/logging/layouts/Layouts.ts | 22 +---- platform/root/__tests__/index.test.ts | 3 +- platform/root/index.ts | 2 +- platform/server/http/HttpServer.ts | 10 ++- 24 files changed, 153 insertions(+), 434 deletions(-) create mode 100644 platform/legacy/logging/appenders/LegacyAppender.ts delete mode 100644 platform/legacy/logging/layouts/LegacyJsonLayout.ts delete mode 100644 platform/legacy/logging/layouts/LegacyPatternLayout.ts delete mode 100644 platform/legacy/logging/layouts/__tests__/LegacyJsonLayout.test.ts delete mode 100644 platform/legacy/logging/layouts/__tests__/LegacyPatternLayout.test.ts delete mode 100644 platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyJsonLayout.test.ts.snap delete mode 100644 platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyPatternLayout.test.ts.snap create mode 100644 platform/logging/appenders/__tests__/__snapshots__/Appenders.test.ts.snap diff --git a/platform/README.md b/platform/README.md index 354231fffba82..2008a6aa93e12 100644 --- a/platform/README.md +++ b/platform/README.md @@ -11,15 +11,26 @@ folder and re-run `npm install`. Make sure to build the code first, e.g. `npm run ts:build` or `npm run ts:start`. -This builds the code into `./ts-tmp/` for now. If you get into a weird state you -might clean the `ts-tmp` directory. +This builds the code into `./target/` for now. If you get into a weird state you +might clean the `target` directory. -When this completes you can start the server and plugins: +When this completes you can start the server and plugins as a standalone Node application: -``` +```bash node scripts/platform.js ``` +Or load it as a part of the legacy platform: + +```bash +npm start +``` + +In the latter case, all Kibana requests will hit the new platform first and it will decide whether request can be +solely handled by the new platform or request should be forwarded to the legacy platform. In this mode new platform does +not read config file directly, but rather transforms config provided by the legacy platform. In addition to that all log +records are forwarded to the legacy platform so that it can layout and output them properly. + ## Running tests Run Jest: diff --git a/platform/config/Env.ts b/platform/config/Env.ts index 2c28f169abdae..cea8dc049f39b 100644 --- a/platform/config/Env.ts +++ b/platform/config/Env.ts @@ -1,7 +1,7 @@ import * as process from 'process'; import { resolve } from 'path'; -import { LegacyPlatformProxifier } from '../legacy'; +import { LegacyKbnServer } from '../legacy'; interface EnvOptions { config?: string; @@ -48,10 +48,8 @@ export class Env { /** * @internal */ - getNewPlatformProxyListener(): LegacyPlatformProxifier | undefined { - if (this.options.kbnServer !== undefined) { - return this.options.kbnServer.newPlatformProxyListener; - } + getLegacyKbnServer(): LegacyKbnServer | undefined { + return this.options.kbnServer; } private getDefaultConfigFile() { diff --git a/platform/config/__tests__/Env.test.ts b/platform/config/__tests__/Env.test.ts index 95b00e4d35943..efe1afa329f5d 100644 --- a/platform/config/__tests__/Env.test.ts +++ b/platform/config/__tests__/Env.test.ts @@ -26,14 +26,14 @@ test('correctly creates default environment with empty options.', () => { expect(defaultEnv.getPluginDir('some-plugin')).toEqual( '/test/cwd/core_plugins/some-plugin/target/dist' ); - expect(defaultEnv.getNewPlatformProxyListener()).toBeUndefined(); + expect(defaultEnv.getLegacyKbnServer()).toBeUndefined(); }); test('correctly creates default environment with options overrides.', () => { - const proxyListenerMock = {}; + const kbnServerMock = {}; const defaultEnv = Env.createDefault({ config: '/some/other/path/some-kibana.yml', - kbnServer: { newPlatformProxyListener: proxyListenerMock } + kbnServer: kbnServerMock }); expect(defaultEnv.homeDir).toEqual('/test/cwd'); @@ -49,7 +49,7 @@ test('correctly creates default environment with options overrides.', () => { expect(defaultEnv.getPluginDir('some-plugin')).toEqual( '/test/cwd/core_plugins/some-plugin/target/dist' ); - expect(defaultEnv.getNewPlatformProxyListener()).toBe(proxyListenerMock); + expect(defaultEnv.getLegacyKbnServer()).toBe(kbnServerMock); }); test('correctly creates environment with constructor.', () => { @@ -70,5 +70,5 @@ test('correctly creates environment with constructor.', () => { expect(defaultEnv.getPluginDir('some-plugin')).toEqual( '/some/home/dir/core_plugins/some-plugin/target/dist' ); - expect(defaultEnv.getNewPlatformProxyListener()).toBeUndefined(); + expect(defaultEnv.getLegacyKbnServer()).toBeUndefined(); }); diff --git a/platform/legacy/LegacyKbnServer.ts b/platform/legacy/LegacyKbnServer.ts index db5a9959e55ff..dc7db9a891ee4 100644 --- a/platform/legacy/LegacyKbnServer.ts +++ b/platform/legacy/LegacyKbnServer.ts @@ -7,6 +7,7 @@ import { LegacyPlatformProxifier } from './LegacyPlatformProxifier'; */ export interface LegacyKbnServer { readonly config: LegacyConfig; + readonly server: { log: (...args: any[]) => void }; /** * Custom HTTP Listener provided by the new platform and that will be used diff --git a/platform/legacy/LegacyPlatformConfig.ts b/platform/legacy/LegacyPlatformConfig.ts index 44a792586a5a8..eca32ce4c098c 100644 --- a/platform/legacy/LegacyPlatformConfig.ts +++ b/platform/legacy/LegacyPlatformConfig.ts @@ -69,7 +69,7 @@ export class LegacyConfigToRawConfigAdapter implements RawConfig { private static transformLogging(configValue: LegacyLoggingConfig) { const loggingConfig = { root: { level: 'info' }, - appenders: { default: {} } + appenders: { default: { kind: 'legacy-appender' } } }; if (configValue.silent) { @@ -80,23 +80,6 @@ export class LegacyConfigToRawConfigAdapter implements RawConfig { loggingConfig.root.level = 'all'; } - const layout = configValue.json - ? { kind: 'legacy-json' } - : { kind: 'legacy-pattern' }; - - if (configValue.dest && configValue.dest !== 'stdout') { - loggingConfig.appenders.default = { - kind: 'file', - path: configValue.dest, - layout - }; - } else { - loggingConfig.appenders.default = { - kind: 'console', - layout - }; - } - return loggingConfig; } diff --git a/platform/legacy/__tests__/LegacyPlatformConfig.test.ts b/platform/legacy/__tests__/LegacyPlatformConfig.test.ts index 26d0aef3300d6..567a09844d2ec 100644 --- a/platform/legacy/__tests__/LegacyPlatformConfig.test.ts +++ b/platform/legacy/__tests__/LegacyPlatformConfig.test.ts @@ -38,10 +38,7 @@ describe('Retrieving values', () => { expect(configAdapter.get('logging')).toEqual({ root: { level: 'off' }, appenders: { - default: { - kind: 'console', - layout: { kind: 'legacy-pattern' } - } + default: { kind: 'legacy-appender' } } }); }); @@ -54,11 +51,7 @@ describe('Retrieving values', () => { expect(configAdapter.get('logging')).toEqual({ root: { level: 'all' }, appenders: { - default: { - kind: 'file', - path: '/some/path.log', - layout: { kind: 'legacy-json' } - } + default: { kind: 'legacy-appender' } } }); }); diff --git a/platform/legacy/__tests__/LegacyPlatformProxifier.test.ts b/platform/legacy/__tests__/LegacyPlatformProxifier.test.ts index 239c118cb931e..7075bfac10a5c 100644 --- a/platform/legacy/__tests__/LegacyPlatformProxifier.test.ts +++ b/platform/legacy/__tests__/LegacyPlatformProxifier.test.ts @@ -6,7 +6,7 @@ class mockNetServer extends EventEmitter { return { port: 1234, family: 'test-family', address: 'test-address' }; } - getConnections(callback: (error: Error, count: number) => void) { + getConnections(callback: (error: Error | undefined, count: number) => void) { callback(undefined, 100500); } } @@ -57,7 +57,7 @@ test('correctly binds to the server and redirects its events.', () => { const listener = jest.fn(); proxifier.addListener(eventName, listener); - return [eventName, listener]; + return [eventName, listener] as [string, () => void]; }) ); @@ -86,7 +86,7 @@ test('correctly unbinds from the previous server.', () => { const listener = jest.fn(); proxifier.addListener(eventName, listener); - return [eventName, listener]; + return [eventName, listener] as [string, () => void]; }) ); diff --git a/platform/legacy/logging/appenders/LegacyAppender.ts b/platform/legacy/logging/appenders/LegacyAppender.ts new file mode 100644 index 0000000000000..ce2e4cda8c555 --- /dev/null +++ b/platform/legacy/logging/appenders/LegacyAppender.ts @@ -0,0 +1,39 @@ +import { Schema, typeOfSchema } from '../../../types/schema'; +import { LogRecord } from '../../../logging/LogRecord'; +import { DisposableAppender } from '../../../logging/appenders/Appenders'; +import { LegacyKbnServer } from '../../LegacyKbnServer'; + +const createSchema = (schema: Schema) => { + const { literal, object } = schema; + + return object({ kind: literal('legacy-appender') }); +}; + +const schemaType = typeOfSchema(createSchema); +/** @internal */ +export type LegacyAppenderConfigType = typeof schemaType; + +/** + * Simple appender that just forwards `LogRecord` to the legacy KbnServer log. + * @internal + */ +export class LegacyAppender implements DisposableAppender { + static createConfigSchema = createSchema; + + constructor(private readonly kbnServer: LegacyKbnServer) {} + + /** + * Forwards `LogRecord` to the legacy platform that will layout and + * write record to the configured destination. + * @param record `LogRecord` instance to forward to. + */ + append(record: LogRecord) { + this.kbnServer.server.log( + [record.level.id.toLowerCase(), ...record.context.split('.')], + record.error || record.message, + record.timestamp + ); + } + + async dispose() {} +} diff --git a/platform/legacy/logging/layouts/LegacyJsonLayout.ts b/platform/legacy/logging/layouts/LegacyJsonLayout.ts deleted file mode 100644 index 1390501535522..0000000000000 --- a/platform/legacy/logging/layouts/LegacyJsonLayout.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { utc } from 'moment'; -import { Schema, typeOfSchema } from '../../../types/schema'; -import { LogRecord } from '../../../logging/LogRecord'; -import { Layout } from '../../../logging/layouts/Layouts'; - -const createSchema = ({ literal, object }: Schema) => { - return object({ - kind: literal('legacy-json') - }); -}; - -const schemaType = typeOfSchema(createSchema); -/** @internal */ -export type LegacyJsonLayoutConfigType = typeof schemaType; - -/** - * Layout that just converts `LogRecord` into JSON string in the same - * format as used by the legacy platform. - * @internal - */ -export class LegacyJsonLayout implements Layout { - static createConfigSchema = createSchema; - - format(record: LogRecord): string { - const recordToSerialize: { [key: string]: any } = { - type: 'log', - '@timestamp': utc(record.timestamp).format(), - tags: [record.level.id.toLowerCase(), ...record.context.split('.')], - pid: process.pid, - message: record.message - }; - - if (record.error !== undefined) { - recordToSerialize.level = record.level.id.toLowerCase(); - recordToSerialize.error = { - message: record.error.message, - name: record.error.name, - stack: record.error.stack - }; - } - - return JSON.stringify(recordToSerialize); - } -} diff --git a/platform/legacy/logging/layouts/LegacyPatternLayout.ts b/platform/legacy/logging/layouts/LegacyPatternLayout.ts deleted file mode 100644 index 8c325f93052ee..0000000000000 --- a/platform/legacy/logging/layouts/LegacyPatternLayout.ts +++ /dev/null @@ -1,90 +0,0 @@ -import * as chalk from 'chalk'; -import { utc } from 'moment'; -import { Schema, typeOfSchema } from '../../../types/schema'; -import { LogLevel } from '../../../logging/LogLevel'; -import { LogRecord } from '../../../logging/LogRecord'; -import { Layout } from '../../../logging/layouts/Layouts'; - -/** - * A set of static constants describing supported parameters in the log message pattern. - */ -const Parameters = Object.freeze({ - Timestamp: '{timestamp}', - Level: '{level}', - Context: '{context}', - Message: '{message}' -}); - -/** - * Regular expression used to parse log message pattern and fill in placeholders - * with the actual data. - */ -const PATTERN_REGEX = new RegExp( - `${Parameters.Timestamp}|${Parameters.Level}|${Parameters.Context}|${Parameters.Message}`, - 'gi' -); - -/** - * Mapping between `LogLevel` and color that is used to highlight `level` part of - * the log message. - */ -const LEVEL_COLORS = new Map([ - [LogLevel.Fatal, chalk.magenta], - [LogLevel.Error, chalk.red], - [LogLevel.Warn, chalk.red], - [LogLevel.Info, chalk.green], - [LogLevel.Debug, chalk.gray], - [LogLevel.Trace, chalk.gray] -]); - -/** - * Default pattern used by PatternLayout if it's not overridden in the configuration. - */ -const DEFAULT_PATTERN = - `${chalk.gray('server')} ${chalk.blue('log')} ` + - `[${Parameters.Timestamp}] [${Parameters.Level}][${Parameters.Context}] ${Parameters.Message}`; - -const createSchema = ({ literal, object }: Schema) => { - return object({ kind: literal('legacy-pattern') }); -}; - -const schemaType = typeOfSchema(createSchema); -/** @internal */ -export type LegacyPatternLayoutConfigType = typeof schemaType; - -/** - * Layout that formats `LogRecord` using the `pattern` string with optional - * color highlighting (eg. to make log messages easier to read in the terminal). - * @internal - */ -export class LegacyPatternLayout implements Layout { - static createConfigSchema = createSchema; - - /** - * Formats `LogRecord` into a string based on the specified `pattern` and `highlighting` options. - * @param record Instance of `LogRecord` to format into string. - */ - format(record: LogRecord): string { - // Error stack is much more useful than just the message. - const message = (record.error && record.error.stack) || record.message; - const formattedRecord = new Map([ - [Parameters.Timestamp, utc(record.timestamp).format('HH:mm:ss.SSS')], - [Parameters.Level, record.level.id.toLowerCase()], - [Parameters.Context, record.context.replace(/\./gi, '][')], - [Parameters.Message, message] - ]); - - if (LEVEL_COLORS.has(record.level)) { - const color = LEVEL_COLORS.get(record.level)!; - formattedRecord.set( - Parameters.Level, - color(formattedRecord.get(Parameters.Level)!) - ); - } - - return DEFAULT_PATTERN.replace( - PATTERN_REGEX, - match => formattedRecord.get(match)! - ); - } -} diff --git a/platform/legacy/logging/layouts/__tests__/LegacyJsonLayout.test.ts b/platform/legacy/logging/layouts/__tests__/LegacyJsonLayout.test.ts deleted file mode 100644 index aaa25ac4756ad..0000000000000 --- a/platform/legacy/logging/layouts/__tests__/LegacyJsonLayout.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import * as mockSchema from '../../../../lib/schema'; - -import { LogLevel } from '../../../../logging/LogLevel'; -import { LogRecord } from '../../../../logging/LogRecord'; -import { LegacyJsonLayout } from '../LegacyJsonLayout'; - -global.process.pid = 1234; - -const timestamp = new Date(Date.UTC(2012, 1, 1, 11, 22, 33, 44)); -const records: LogRecord[] = [ - { - timestamp, - message: 'message-1', - context: 'context-1', - error: { - message: 'Some error message', - name: 'Some error name', - stack: 'Some error stack' - }, - level: LogLevel.Fatal - }, - { - timestamp, - message: 'message-2', - context: 'context-2', - level: LogLevel.Error - }, - { - timestamp, - message: 'message-2', - context: 'context-2.sub-context-2.sub-sub-context-2', - level: LogLevel.Error - }, - { - timestamp, - message: 'message-3', - context: 'context-3', - level: LogLevel.Warn - }, - { - timestamp, - message: 'message-4', - context: 'context-4', - level: LogLevel.Debug - }, - { - timestamp, - message: 'message-5', - context: 'context-5', - level: LogLevel.Info - }, - { - timestamp, - message: 'message-5', - context: 'context-5.sub-context-5', - level: LogLevel.Info - }, - { - timestamp, - message: 'message-6', - context: 'context-6', - level: LogLevel.Trace - } -]; - -test('`createConfigSchema()` creates correct schema.', () => { - const layoutSchema = LegacyJsonLayout.createConfigSchema(mockSchema); - - expect(layoutSchema.validate({ kind: 'legacy-json' })).toEqual({ - kind: 'legacy-json' - }); -}); - -test('`format()` correctly formats record.', () => { - const layout = new LegacyJsonLayout(); - - for (const record of records) { - expect(layout.format(record)).toMatchSnapshot(); - } -}); diff --git a/platform/legacy/logging/layouts/__tests__/LegacyPatternLayout.test.ts b/platform/legacy/logging/layouts/__tests__/LegacyPatternLayout.test.ts deleted file mode 100644 index 45dccef46246a..0000000000000 --- a/platform/legacy/logging/layouts/__tests__/LegacyPatternLayout.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as mockSchema from '../../../../lib/schema'; - -import { LogLevel } from '../../../../logging/LogLevel'; -import { LogRecord } from '../../../../logging/LogRecord'; -import { LegacyPatternLayout } from '../LegacyPatternLayout'; - -global.process.pid = 1234; - -const timestamp = new Date(Date.UTC(2012, 1, 1, 11, 22, 33, 44)); -const records: LogRecord[] = [ - { - timestamp, - message: 'message-1', - context: 'context-1', - error: { - message: 'Some error message', - name: 'Some error name', - stack: 'Some error stack' - }, - level: LogLevel.Fatal - }, - { - timestamp, - message: 'message-2', - context: 'context-2', - level: LogLevel.Error - }, - { - timestamp, - message: 'message-2', - context: 'context-2.sub-context-2.sub-sub-context-2', - level: LogLevel.Error - }, - { - timestamp, - message: 'message-3', - context: 'context-3', - level: LogLevel.Warn - }, - { - timestamp, - message: 'message-4', - context: 'context-4', - level: LogLevel.Debug - }, - { - timestamp, - message: 'message-5', - context: 'context-5', - level: LogLevel.Info - }, - { - timestamp, - message: 'message-5', - context: 'context-5.sub-context-5', - level: LogLevel.Info - }, - { - timestamp, - message: 'message-6', - context: 'context-6', - level: LogLevel.Trace - } -]; - -test('`createConfigSchema()` creates correct schema.', () => { - const layoutSchema = LegacyPatternLayout.createConfigSchema(mockSchema); - - const validConfigWithOptional = { kind: 'legacy-pattern' }; - expect(layoutSchema.validate(validConfigWithOptional)).toEqual({ - kind: 'legacy-pattern' - }); - - const wrongConfig1 = { kind: 'json' }; - expect(() => layoutSchema.validate(wrongConfig1)).toThrow(); - - const wrongConfig2 = { kind: 'pattern', pattern: 1 }; - expect(() => layoutSchema.validate(wrongConfig2)).toThrow(); -}); - -test('`format()` correctly formats record with full pattern.', () => { - const layout = new LegacyPatternLayout(); - - for (const record of records) { - expect(layout.format(record)).toMatchSnapshot(); - } -}); diff --git a/platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyJsonLayout.test.ts.snap b/platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyJsonLayout.test.ts.snap deleted file mode 100644 index 9ad19d88b99e2..0000000000000 --- a/platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyJsonLayout.test.ts.snap +++ /dev/null @@ -1,17 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`\`format()\` correctly formats record. 1`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"fatal\\",\\"context-1\\"],\\"pid\\":1234,\\"message\\":\\"message-1\\",\\"level\\":\\"fatal\\",\\"error\\":{\\"message\\":\\"Some error message\\",\\"name\\":\\"Some error name\\",\\"stack\\":\\"Some error stack\\"}}"`; - -exports[`\`format()\` correctly formats record. 2`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"error\\",\\"context-2\\"],\\"pid\\":1234,\\"message\\":\\"message-2\\"}"`; - -exports[`\`format()\` correctly formats record. 3`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"error\\",\\"context-2\\",\\"sub-context-2\\",\\"sub-sub-context-2\\"],\\"pid\\":1234,\\"message\\":\\"message-2\\"}"`; - -exports[`\`format()\` correctly formats record. 4`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"warn\\",\\"context-3\\"],\\"pid\\":1234,\\"message\\":\\"message-3\\"}"`; - -exports[`\`format()\` correctly formats record. 5`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"debug\\",\\"context-4\\"],\\"pid\\":1234,\\"message\\":\\"message-4\\"}"`; - -exports[`\`format()\` correctly formats record. 6`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"info\\",\\"context-5\\"],\\"pid\\":1234,\\"message\\":\\"message-5\\"}"`; - -exports[`\`format()\` correctly formats record. 7`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"info\\",\\"context-5\\",\\"sub-context-5\\"],\\"pid\\":1234,\\"message\\":\\"message-5\\"}"`; - -exports[`\`format()\` correctly formats record. 8`] = `"{\\"type\\":\\"log\\",\\"@timestamp\\":\\"2012-02-01T11:22:33Z\\",\\"tags\\":[\\"trace\\",\\"context-6\\"],\\"pid\\":1234,\\"message\\":\\"message-6\\"}"`; diff --git a/platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyPatternLayout.test.ts.snap b/platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyPatternLayout.test.ts.snap deleted file mode 100644 index 227dcd4d4043b..0000000000000 --- a/platform/legacy/logging/layouts/__tests__/__snapshots__/LegacyPatternLayout.test.ts.snap +++ /dev/null @@ -1,17 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`\`format()\` correctly formats record with full pattern. 1`] = `"server log [11:22:33.044] [fatal][context-1] Some error stack"`; - -exports[`\`format()\` correctly formats record with full pattern. 2`] = `"server log [11:22:33.044] [error][context-2] message-2"`; - -exports[`\`format()\` correctly formats record with full pattern. 3`] = `"server log [11:22:33.044] [error][context-2][sub-context-2][sub-sub-context-2] message-2"`; - -exports[`\`format()\` correctly formats record with full pattern. 4`] = `"server log [11:22:33.044] [warn][context-3] message-3"`; - -exports[`\`format()\` correctly formats record with full pattern. 5`] = `"server log [11:22:33.044] [debug][context-4] message-4"`; - -exports[`\`format()\` correctly formats record with full pattern. 6`] = `"server log [11:22:33.044] [info][context-5] message-5"`; - -exports[`\`format()\` correctly formats record with full pattern. 7`] = `"server log [11:22:33.044] [info][context-5][sub-context-5] message-5"`; - -exports[`\`format()\` correctly formats record with full pattern. 8`] = `"server log [11:22:33.044] [trace][context-6] message-6"`; diff --git a/platform/logging/LoggerFactory.ts b/platform/logging/LoggerFactory.ts index ed06100016ccd..0737a214bfc32 100644 --- a/platform/logging/LoggerFactory.ts +++ b/platform/logging/LoggerFactory.ts @@ -1,3 +1,4 @@ +import { Env } from '../config/Env'; import { LoggingConfig, LoggerConfigType } from './LoggingConfig'; import { LogLevel } from './LogLevel'; import { Logger, BaseLogger, LoggerAdapter } from './Logger'; @@ -24,6 +25,8 @@ export class MutableLoggerFactory implements LoggerFactory { private readonly bufferAppender = new BufferAppender(); private readonly loggers: Map = new Map(); + constructor(private readonly env: Env) {} + get(...contextParts: string[]): Logger { const context = LoggingConfig.getLoggerContext(contextParts); if (this.loggers.has(context)) { @@ -53,7 +56,10 @@ export class MutableLoggerFactory implements LoggerFactory { this.appenders.clear(); for (const [appenderKey, appenderConfig] of config.appenders.entries()) { - this.appenders.set(appenderKey, Appenders.create(appenderConfig)); + this.appenders.set( + appenderKey, + Appenders.create(appenderConfig, this.env) + ); } for (const [loggerKey, loggerAdapter] of this.loggers.entries()) { diff --git a/platform/logging/__tests__/LoggerFactory.test.ts b/platform/logging/__tests__/LoggerFactory.test.ts index 302baf85a69ef..efef0075c7a0a 100644 --- a/platform/logging/__tests__/LoggerFactory.test.ts +++ b/platform/logging/__tests__/LoggerFactory.test.ts @@ -32,7 +32,7 @@ beforeEach(() => { }); test('`get()` returns Logger that appends records to buffer if config is not ready.', () => { - const factory = new MutableLoggerFactory(); + const factory = new MutableLoggerFactory({} as any); const loggerWithoutConfig = factory.get('some-context'); const testsLogger = factory.get('tests'); const testsChildLogger = factory.get('tests', 'child'); @@ -92,7 +92,7 @@ test('`get()` returns Logger that appends records to buffer if config is not rea test('`get()` returns `root` logger if context is not specified.', () => { const loggingConfigSchema = LoggingConfig.createSchema(mockSchema); - const factory = new MutableLoggerFactory(); + const factory = new MutableLoggerFactory({} as any); const config = loggingConfigSchema.validate({ appenders: { default: { @@ -114,7 +114,7 @@ test('`get()` returns `root` logger if context is not specified.', () => { }); test('`close()` disposes all resources used by appenders.', async () => { - const factory = new MutableLoggerFactory(); + const factory = new MutableLoggerFactory({} as any); const loggingConfigSchema = LoggingConfig.createSchema(mockSchema); const config = new LoggingConfig( diff --git a/platform/logging/__tests__/LoggingService.test.ts b/platform/logging/__tests__/LoggingService.test.ts index d318898298601..ffbfac432ec5e 100644 --- a/platform/logging/__tests__/LoggingService.test.ts +++ b/platform/logging/__tests__/LoggingService.test.ts @@ -24,7 +24,7 @@ let service: LoggingService; let updateConfigMock: jest.Mock; let closeMock: jest.Mock; beforeEach(() => { - factory = new MutableLoggerFactory(); + factory = new MutableLoggerFactory({} as any); updateConfigMock = jest .spyOn(factory, 'updateConfig') .mockImplementation(() => {}); diff --git a/platform/logging/appenders/Appenders.ts b/platform/logging/appenders/Appenders.ts index e01dd454a2402..8ee47558cae2f 100644 --- a/platform/logging/appenders/Appenders.ts +++ b/platform/logging/appenders/Appenders.ts @@ -1,17 +1,23 @@ import { assertNever } from '../../lib/utils'; import { Schema } from '../../types/schema'; +import { Env } from '../../config/Env'; import { ConsoleAppender, ConsoleAppenderConfigType } from './console/ConsoleAppender'; import { FileAppender, FileAppenderConfigType } from './file/FileAppender'; +import { + LegacyAppender, + LegacyAppenderConfigType +} from '../../legacy/logging/appenders/LegacyAppender'; import { LogRecord } from '../LogRecord'; import { Layouts } from '../layouts/Layouts'; /** @internal */ export type AppenderConfigType = | ConsoleAppenderConfigType - | FileAppenderConfigType; + | FileAppenderConfigType + | LegacyAppenderConfigType; /** * Entity that can append `LogRecord` instances to file, stdout, memory or whatever @@ -39,23 +45,29 @@ export class Appenders { return oneOf([ ConsoleAppender.createConfigSchema(schema), - FileAppender.createConfigSchema(schema) + FileAppender.createConfigSchema(schema), + LegacyAppender.createConfigSchema(schema) ]); } /** * Factory method that creates specific `Appender` instances based on the passed `config` parameter. * @param config Configuration specific to a particular `Appender` implementation. + * @param env Current environment that is required by some appenders. * @returns Fully constructed `Appender` instance. */ - static create(config: AppenderConfigType): DisposableAppender { - const layout = Layouts.create(config.layout); - + static create(config: AppenderConfigType, env: Env): DisposableAppender { switch (config.kind) { case 'console': - return new ConsoleAppender(layout); + return new ConsoleAppender(Layouts.create(config.layout)); case 'file': - return new FileAppender(layout, config.path); + return new FileAppender(Layouts.create(config.layout), config.path); + case 'legacy-appender': + const legacyKbnServer = env.getLegacyKbnServer(); + if (legacyKbnServer === undefined) { + throw new Error('Legacy appender requires kbnServer.'); + } + return new LegacyAppender(legacyKbnServer); default: return assertNever(config); } diff --git a/platform/logging/appenders/__tests__/Appenders.test.ts b/platform/logging/appenders/__tests__/Appenders.test.ts index 38f21695dbff9..b29528f7ae4b5 100644 --- a/platform/logging/appenders/__tests__/Appenders.test.ts +++ b/platform/logging/appenders/__tests__/Appenders.test.ts @@ -11,6 +11,7 @@ jest.mock('../../layouts/Layouts', () => ({ import { ConsoleAppender } from '../console/ConsoleAppender'; import { FileAppender } from '../file/FileAppender'; +import { LegacyAppender } from '../../../legacy/logging/appenders/LegacyAppender'; import { Appenders } from '../Appenders'; beforeEach(() => { @@ -60,24 +61,46 @@ test('`createConfigSchema()` creates correct schema.', () => { test('`create()` creates correct appender.', () => { mockCreateLayout.mockReturnValue({ format: () => '' }); - const consoleAppender = Appenders.create({ - kind: 'console', - layout: { - kind: 'pattern', - pattern: '', - highlight: true - } - }); + const consoleAppender = Appenders.create( + { + kind: 'console', + layout: { + kind: 'pattern', + pattern: '', + highlight: true + } + }, + {} as any + ); expect(consoleAppender).toBeInstanceOf(ConsoleAppender); - const fileAppender = Appenders.create({ - kind: 'file', - path: 'path', - layout: { - kind: 'pattern', - pattern: '', - highlight: true - } - }); + const fileAppender = Appenders.create( + { + kind: 'file', + path: 'path', + layout: { + kind: 'pattern', + pattern: '', + highlight: true + } + }, + {} as any + ); expect(fileAppender).toBeInstanceOf(FileAppender); }); + +test('`create()` fails to create legacy appender if kbnServer is not provided.', () => { + expect(() => { + Appenders.create({ kind: 'legacy-appender' }, { + getLegacyKbnServer() {} + } as any); + }).toThrowErrorMatchingSnapshot(); +}); + +test('`create()` creates legacy appender if kbnServer is provided.', () => { + const legacyAppender = Appenders.create({ kind: 'legacy-appender' }, { + getLegacyKbnServer: () => ({}) + } as any); + + expect(legacyAppender).toBeInstanceOf(LegacyAppender); +}); diff --git a/platform/logging/appenders/__tests__/__snapshots__/Appenders.test.ts.snap b/platform/logging/appenders/__tests__/__snapshots__/Appenders.test.ts.snap new file mode 100644 index 0000000000000..e7e8f70b345c7 --- /dev/null +++ b/platform/logging/appenders/__tests__/__snapshots__/Appenders.test.ts.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`\`create()\` fails to create legacy appender if kbnServer is not provided. 1`] = `"Legacy appender requires kbnServer."`; diff --git a/platform/logging/layouts/Layouts.ts b/platform/logging/layouts/Layouts.ts index b2c3db5bca4cf..fccf2127647b2 100644 --- a/platform/logging/layouts/Layouts.ts +++ b/platform/logging/layouts/Layouts.ts @@ -2,21 +2,9 @@ import { assertNever } from '../../lib/utils'; import { Schema } from '../../types/schema'; import { JsonLayout, JsonLayoutConfigType } from './JsonLayout'; import { PatternLayout, PatternLayoutConfigType } from './PatternLayout'; -import { - LegacyPatternLayout, - LegacyPatternLayoutConfigType -} from '../../legacy/logging/layouts/LegacyPatternLayout'; -import { - LegacyJsonLayout, - LegacyJsonLayoutConfigType -} from '../../legacy/logging/layouts/LegacyJsonLayout'; import { LogRecord } from '../LogRecord'; -type LayoutConfigType = - | PatternLayoutConfigType - | JsonLayoutConfigType - | LegacyPatternLayoutConfigType - | LegacyJsonLayoutConfigType; +type LayoutConfigType = PatternLayoutConfigType | JsonLayoutConfigType; /** * Entity that can format `LogRecord` instance into a string. @@ -33,9 +21,7 @@ export class Layouts { return oneOf([ JsonLayout.createConfigSchema(schema), - PatternLayout.createConfigSchema(schema), - LegacyPatternLayout.createConfigSchema(schema), - LegacyJsonLayout.createConfigSchema(schema) + PatternLayout.createConfigSchema(schema) ]); } @@ -50,10 +36,6 @@ export class Layouts { return new JsonLayout(); case 'pattern': return new PatternLayout(config.pattern, config.highlight); - case 'legacy-pattern': - return new LegacyPatternLayout(); - case 'legacy-json': - return new LegacyJsonLayout(); default: return assertNever(config); } diff --git a/platform/root/__tests__/index.test.ts b/platform/root/__tests__/index.test.ts index fdf4ba7f6745f..7c243f8f7dc95 100644 --- a/platform/root/__tests__/index.test.ts +++ b/platform/root/__tests__/index.test.ts @@ -41,9 +41,10 @@ jest.mock('../../logging/LoggerFactory', () => ({ import { Root } from '../'; import { Env } from '../../config/Env'; +import { RawConfig } from '../../config/RawConfigService'; const env = new Env('.', {}); -const config$ = new BehaviorSubject({}); +const config$ = new BehaviorSubject({} as RawConfig); let mockProcessExit = jest .spyOn(global.process, 'exit') diff --git a/platform/root/index.ts b/platform/root/index.ts index 0d4c9fbfb369f..f3cc037d30587 100644 --- a/platform/root/index.ts +++ b/platform/root/index.ts @@ -25,7 +25,7 @@ export class Root { private readonly env: Env, private readonly onShutdown: OnShutdown = () => {} ) { - const loggerFactory = new MutableLoggerFactory(); + const loggerFactory = new MutableLoggerFactory(env); this.loggingService = new LoggingService(loggerFactory); this.logger = loggerFactory; diff --git a/platform/server/http/HttpServer.ts b/platform/server/http/HttpServer.ts index 153085064a361..7944f439244c3 100644 --- a/platform/server/http/HttpServer.ts +++ b/platform/server/http/HttpServer.ts @@ -29,14 +29,16 @@ export class HttpServer { async start(config: HttpConfig) { this.server = this.initializeServer(config); - const proxyListener = this.env.getNewPlatformProxyListener(); - if (proxyListener !== undefined) { - proxyListener.bind(this.server); + const legacyKbnServer = this.env.getLegacyKbnServer(); + if (legacyKbnServer !== undefined) { + legacyKbnServer.newPlatformProxyListener.bind(this.server); // We register Kibana proxy middleware right before we start server to allow // all new platform plugins register their endpoints, so that kbnServer // handles only requests that aren't handled by the new platform. - this.app.use((req, res) => proxyListener.proxy(req, res)); + this.app.use((req, res) => + legacyKbnServer.newPlatformProxyListener.proxy(req, res) + ); } this.log.info(`starting http server [${config.host}:${config.port}]`); From 6342f69632c7db490bd862ebafaf3092780f19c9 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Fri, 6 Oct 2017 17:30:48 +0200 Subject: [PATCH 3/5] Add unit tests for `LegacyAppender`. --- .../__tests__/LegacyAppender.test.ts | 82 +++++++++++++++++++ .../__snapshots__/LegacyAppender.test.ts.snap | 76 +++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 platform/legacy/logging/appenders/__tests__/LegacyAppender.test.ts create mode 100644 platform/legacy/logging/appenders/__tests__/__snapshots__/LegacyAppender.test.ts.snap diff --git a/platform/legacy/logging/appenders/__tests__/LegacyAppender.test.ts b/platform/legacy/logging/appenders/__tests__/LegacyAppender.test.ts new file mode 100644 index 0000000000000..40207543afdf3 --- /dev/null +++ b/platform/legacy/logging/appenders/__tests__/LegacyAppender.test.ts @@ -0,0 +1,82 @@ +import * as mockSchema from '../../../../lib/schema'; +import { LogLevel } from '../../../../logging/LogLevel'; +import { LogRecord } from '../../../../logging/LogRecord'; +import { LegacyAppender } from '../LegacyAppender'; + +test('`createConfigSchema()` creates correct schema.', () => { + const appenderSchema = LegacyAppender.createConfigSchema(mockSchema); + const validConfig = { kind: 'legacy-appender' }; + expect(appenderSchema.validate(validConfig)).toEqual({ + kind: 'legacy-appender' + }); + + const wrongConfig = { kind: 'not-legacy-appender' }; + expect(() => appenderSchema.validate(wrongConfig)).toThrow(); +}); + +test('`append()` correctly pushes records to legacy platform.', () => { + const timestamp = new Date(Date.UTC(2012, 1, 1, 11, 22, 33, 44)); + const records: LogRecord[] = [ + { + timestamp, + message: 'message-1', + context: 'context-1', + level: LogLevel.Trace + }, + { + timestamp, + message: 'message-2', + context: 'context-2', + level: LogLevel.Debug + }, + { + timestamp, + message: 'message-3', + context: 'context-3.sub-context-3', + level: LogLevel.Info + }, + { + timestamp, + message: 'message-4', + context: 'context-4.sub-context-4', + level: LogLevel.Warn + }, + { + timestamp, + message: 'message-5-with-error', + context: 'context-5', + error: new Error('Some Error'), + level: LogLevel.Error + }, + { + timestamp, + message: 'message-6-with-message', + context: 'context-6', + level: LogLevel.Error + }, + { + timestamp, + message: 'message-7-with-error', + context: 'context-7.sub-context-7.sub-sub-context-7', + error: new Error('Some Fatal Error'), + level: LogLevel.Fatal + }, + { + timestamp, + message: 'message-8-with-message', + context: 'context-8.sub-context-8.sub-sub-context-8', + level: LogLevel.Fatal + } + ]; + + const legacyLogStub = jest.fn(); + const appender = new LegacyAppender( + { server: { log: legacyLogStub } } as any + ); + + for (const record of records) { + appender.append(record); + } + + expect(legacyLogStub.mock.calls).toMatchSnapshot(); +}); diff --git a/platform/legacy/logging/appenders/__tests__/__snapshots__/LegacyAppender.test.ts.snap b/platform/legacy/logging/appenders/__tests__/__snapshots__/LegacyAppender.test.ts.snap new file mode 100644 index 0000000000000..4a024fc806a13 --- /dev/null +++ b/platform/legacy/logging/appenders/__tests__/__snapshots__/LegacyAppender.test.ts.snap @@ -0,0 +1,76 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`\`append()\` correctly pushes records to legacy platform. 1`] = ` +Array [ + Array [ + Array [ + "trace", + "context-1", + ], + "message-1", + 2012-02-01T11:22:33.044Z, + ], + Array [ + Array [ + "debug", + "context-2", + ], + "message-2", + 2012-02-01T11:22:33.044Z, + ], + Array [ + Array [ + "info", + "context-3", + "sub-context-3", + ], + "message-3", + 2012-02-01T11:22:33.044Z, + ], + Array [ + Array [ + "warn", + "context-4", + "sub-context-4", + ], + "message-4", + 2012-02-01T11:22:33.044Z, + ], + Array [ + Array [ + "error", + "context-5", + ], + [Error: Some Error], + 2012-02-01T11:22:33.044Z, + ], + Array [ + Array [ + "error", + "context-6", + ], + "message-6-with-message", + 2012-02-01T11:22:33.044Z, + ], + Array [ + Array [ + "fatal", + "context-7", + "sub-context-7", + "sub-sub-context-7", + ], + [Error: Some Fatal Error], + 2012-02-01T11:22:33.044Z, + ], + Array [ + Array [ + "fatal", + "context-8", + "sub-context-8", + "sub-sub-context-8", + ], + "message-8-with-message", + 2012-02-01T11:22:33.044Z, + ], +] +`; From 575be1168aaef708abf3243c75b75e4961615725 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Mon, 9 Oct 2017 15:46:50 +0200 Subject: [PATCH 4/5] Convert `LegacyKbnServer` interface to class. Group all new `kbnServer` methods under `newPlatform` "namespace". --- platform/legacy/LegacyKbnServer.ts | 27 ++++++++++-------- .../legacy/__tests__/LegacyKbnServer.test.ts | 28 +++++++++++++++++++ .../LegacyKbnServer.test.ts.snap | 19 +++++++++++++ platform/legacy/index.ts | 23 +++++++++------ .../logging/appenders/LegacyAppender.ts | 2 +- .../__tests__/LegacyAppender.test.ts | 11 ++++---- src/cli/serve/serve.js | 4 +-- src/server/http/setup_connection.js | 3 +- 8 files changed, 88 insertions(+), 29 deletions(-) create mode 100644 platform/legacy/__tests__/LegacyKbnServer.test.ts create mode 100644 platform/legacy/__tests__/__snapshots__/LegacyKbnServer.test.ts.snap diff --git a/platform/legacy/LegacyKbnServer.ts b/platform/legacy/LegacyKbnServer.ts index dc7db9a891ee4..4a7c98365831b 100644 --- a/platform/legacy/LegacyKbnServer.ts +++ b/platform/legacy/LegacyKbnServer.ts @@ -1,22 +1,25 @@ -import { LegacyConfig } from './LegacyPlatformConfig'; -import { LegacyPlatformProxifier } from './LegacyPlatformProxifier'; - /** - * Represents legacy kbnServer instance, provided by the legacy platform. + * Represents a wrapper around legacy `kbnServer` instance that exposes only + * a subset of `kbnServer` APIs used by the new platform. * @internal */ -export interface LegacyKbnServer { - readonly config: LegacyConfig; - readonly server: { log: (...args: any[]) => void }; +export class LegacyKbnServer { + constructor(private readonly rawKbnServer: any) {} /** - * Custom HTTP Listener provided by the new platform and that will be used - * within legacy platform by HapiJS server. + * Custom HTTP Listener used by HapiJS server in the legacy platform. */ - newPlatformProxyListener: LegacyPlatformProxifier; + get newPlatformProxyListener() { + return this.rawKbnServer.newPlatform.proxyListener; + } /** - * Propagates legacy config updates to the new platform. + * Forwards log request to the legacy platform. + * @param tags A string or array of strings used to briefly identify the event. + * @param [data] Optional string or object to log with the event. + * @param [timestamp] Timestamp value associated with the log record. */ - updateNewPlatformConfig: (legacyConfig: LegacyConfig) => void; + log(tags: string | string[], data?: string | Error, timestamp?: Date) { + this.rawKbnServer.server.log(tags, data, timestamp); + } } diff --git a/platform/legacy/__tests__/LegacyKbnServer.test.ts b/platform/legacy/__tests__/LegacyKbnServer.test.ts new file mode 100644 index 0000000000000..28ff37ec18ae7 --- /dev/null +++ b/platform/legacy/__tests__/LegacyKbnServer.test.ts @@ -0,0 +1,28 @@ +import { LegacyKbnServer } from '..'; + +it('correctly returns `newPlatformProxyListener`.', () => { + const rawKbnServer = { + newPlatform: { + proxyListener: {} + } + }; + + const legacyKbnServer = new LegacyKbnServer(rawKbnServer); + expect(legacyKbnServer.newPlatformProxyListener).toBe( + rawKbnServer.newPlatform.proxyListener + ); +}); + +it('correctly forwards log record.', () => { + const rawKbnServer = { + server: { log: jest.fn() } + }; + + const legacyKbnServer = new LegacyKbnServer(rawKbnServer); + + const timestamp = new Date(Date.UTC(2012, 1, 1, 11, 22, 33, 44)); + legacyKbnServer.log(['one', 'two'], 'message', timestamp); + legacyKbnServer.log('three', new Error('log error'), timestamp); + + expect(rawKbnServer.server.log.mock.calls).toMatchSnapshot(); +}); diff --git a/platform/legacy/__tests__/__snapshots__/LegacyKbnServer.test.ts.snap b/platform/legacy/__tests__/__snapshots__/LegacyKbnServer.test.ts.snap new file mode 100644 index 0000000000000..af1b7cf4c6e76 --- /dev/null +++ b/platform/legacy/__tests__/__snapshots__/LegacyKbnServer.test.ts.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`correctly forwards log record. 1`] = ` +Array [ + Array [ + Array [ + "one", + "two", + ], + "message", + 2012-02-01T11:22:33.044Z, + ], + Array [ + "three", + [Error: log error], + 2012-02-01T11:22:33.044Z, + ], +] +`; diff --git a/platform/legacy/index.ts b/platform/legacy/index.ts index 7f384edc6ab11..b4a38ad94fb67 100644 --- a/platform/legacy/index.ts +++ b/platform/legacy/index.ts @@ -21,17 +21,24 @@ import { /** * @internal */ -export const injectIntoKbnServer = (kbnServer: LegacyKbnServer) => { - const legacyConfig$ = new BehaviorSubject(kbnServer.config); +export const injectIntoKbnServer = (rawKbnServer: any) => { + const legacyConfig$ = new BehaviorSubject(rawKbnServer.config); const config$ = legacyConfig$.map( legacyConfig => new LegacyConfigToRawConfigAdapter(legacyConfig) ); - kbnServer.updateNewPlatformConfig = (legacyConfig: LegacyConfig) => { - legacyConfig$.next(legacyConfig); - }; + rawKbnServer.newPlatform = { + // Custom HTTP Listener that will be used within legacy platform by HapiJS server. + proxyListener: new LegacyPlatformProxifier( + new Root( + config$, + Env.createDefault({ kbnServer: new LegacyKbnServer(rawKbnServer) }) + ) + ), - kbnServer.newPlatformProxyListener = new LegacyPlatformProxifier( - new Root(config$, Env.createDefault({ kbnServer })) - ); + // Propagates legacy config updates to the new platform. + updateConfig(legacyConfig: LegacyConfig) { + legacyConfig$.next(legacyConfig); + } + }; }; diff --git a/platform/legacy/logging/appenders/LegacyAppender.ts b/platform/legacy/logging/appenders/LegacyAppender.ts index ce2e4cda8c555..646c8a1c3ce0d 100644 --- a/platform/legacy/logging/appenders/LegacyAppender.ts +++ b/platform/legacy/logging/appenders/LegacyAppender.ts @@ -28,7 +28,7 @@ export class LegacyAppender implements DisposableAppender { * @param record `LogRecord` instance to forward to. */ append(record: LogRecord) { - this.kbnServer.server.log( + this.kbnServer.log( [record.level.id.toLowerCase(), ...record.context.split('.')], record.error || record.message, record.timestamp diff --git a/platform/legacy/logging/appenders/__tests__/LegacyAppender.test.ts b/platform/legacy/logging/appenders/__tests__/LegacyAppender.test.ts index 40207543afdf3..413cde2abfc83 100644 --- a/platform/legacy/logging/appenders/__tests__/LegacyAppender.test.ts +++ b/platform/legacy/logging/appenders/__tests__/LegacyAppender.test.ts @@ -1,6 +1,7 @@ import * as mockSchema from '../../../../lib/schema'; import { LogLevel } from '../../../../logging/LogLevel'; import { LogRecord } from '../../../../logging/LogRecord'; +import { LegacyKbnServer } from '../../../LegacyKbnServer'; import { LegacyAppender } from '../LegacyAppender'; test('`createConfigSchema()` creates correct schema.', () => { @@ -69,14 +70,14 @@ test('`append()` correctly pushes records to legacy platform.', () => { } ]; - const legacyLogStub = jest.fn(); - const appender = new LegacyAppender( - { server: { log: legacyLogStub } } as any - ); + const rawKbnServerMock = { + server: { log: jest.fn() } + }; + const appender = new LegacyAppender(new LegacyKbnServer(rawKbnServerMock)); for (const record of records) { appender.append(record); } - expect(legacyLogStub.mock.calls).toMatchSnapshot(); + expect(rawKbnServerMock.server.log.mock.calls).toMatchSnapshot(); }); diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index 5f8ad90892068..cf5e64105ec2e 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -181,8 +181,8 @@ export default function (program) { kbnServer.server.log(['info', 'config'], 'Reloaded logging configuration due to SIGHUP.'); // If new platform config subscription is active, let's notify it with the updated config. - if (kbnServer.updateNewPlatformConfig) { - kbnServer.updateNewPlatformConfig(config); + if (kbnServer.newPlatform) { + kbnServer.newPlatform.updateConfig(config); } }); diff --git a/src/server/http/setup_connection.js b/src/server/http/setup_connection.js index a7338a75b73fc..293aa480e1072 100644 --- a/src/server/http/setup_connection.js +++ b/src/server/http/setup_connection.js @@ -3,7 +3,8 @@ import { map } from 'lodash'; import secureOptions from './secure_options'; export default function (kbnServer, server, config) { - const newPlatformProxyListener = kbnServer && kbnServer.newPlatformProxyListener; + const newPlatformProxyListener = kbnServer && kbnServer.newPlatform + && kbnServer.newPlatform.proxyListener; // this mixin is used outside of the kbn server, so it MUST work without a full kbnServer object. kbnServer = null; From b9aa1ab338785e5a2a4f61c78a586619c99089c8 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Mon, 9 Oct 2017 16:21:48 +0200 Subject: [PATCH 5/5] Change `it` to `test`. --- platform/legacy/__tests__/LegacyKbnServer.test.ts | 4 ++-- platform/server/http/__tests__/HttpServer.test.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/legacy/__tests__/LegacyKbnServer.test.ts b/platform/legacy/__tests__/LegacyKbnServer.test.ts index 28ff37ec18ae7..bc788a4170595 100644 --- a/platform/legacy/__tests__/LegacyKbnServer.test.ts +++ b/platform/legacy/__tests__/LegacyKbnServer.test.ts @@ -1,6 +1,6 @@ import { LegacyKbnServer } from '..'; -it('correctly returns `newPlatformProxyListener`.', () => { +test('correctly returns `newPlatformProxyListener`.', () => { const rawKbnServer = { newPlatform: { proxyListener: {} @@ -13,7 +13,7 @@ it('correctly returns `newPlatformProxyListener`.', () => { ); }); -it('correctly forwards log record.', () => { +test('correctly forwards log record.', () => { const rawKbnServer = { server: { log: jest.fn() } }; diff --git a/platform/server/http/__tests__/HttpServer.test.ts b/platform/server/http/__tests__/HttpServer.test.ts index 7fcd8f166e32c..bf3d568fb3e79 100644 --- a/platform/server/http/__tests__/HttpServer.test.ts +++ b/platform/server/http/__tests__/HttpServer.test.ts @@ -412,7 +412,7 @@ describe('when run within legacy platform', () => { ); }); - it('binds proxy listener to server.', async () => { + test('binds proxy listener to server.', async () => { expect(newPlatformProxyListenerMock.bind).not.toHaveBeenCalled(); await server.start(config); @@ -426,7 +426,7 @@ describe('when run within legacy platform', () => { ); }); - it('forwards request to legacy platform if new one can not handle it', async () => { + test('forwards request to legacy platform if new one can not handle it', async () => { await server.start(config); await supertest((server as any).server) @@ -442,7 +442,7 @@ describe('when run within legacy platform', () => { }); }); - it('do not forward request to legacy platform if new one can handle it', async () => { + test('do not forward request to legacy platform if new one can handle it', async () => { await server.start(config); await supertest((server as any).server)