Skip to content

Commit

Permalink
Introduce LegacyAppender that forwards log records to the legacy pl…
Browse files Browse the repository at this point in the history
…atform. (#14354)
  • Loading branch information
azasypkin authored Oct 9, 2017
1 parent 936daca commit 01d0f31
Show file tree
Hide file tree
Showing 25 changed files with 393 additions and 104 deletions.
19 changes: 15 additions & 4 deletions platform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
8 changes: 3 additions & 5 deletions platform/config/Env.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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() {
Expand Down
10 changes: 5 additions & 5 deletions platform/config/__tests__/Env.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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.', () => {
Expand All @@ -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();
});
26 changes: 15 additions & 11 deletions platform/legacy/LegacyKbnServer.ts
Original file line number Diff line number Diff line change
@@ -1,21 +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;
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);
}
}
19 changes: 1 addition & 18 deletions platform/legacy/LegacyPlatformConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -80,23 +80,6 @@ export class LegacyConfigToRawConfigAdapter implements RawConfig {
loggingConfig.root.level = 'all';
}

const layout = configValue.json
? { kind: 'json' }
: { kind: 'pattern', highlight: true };

if (configValue.dest && configValue.dest !== 'stdout') {
loggingConfig.appenders.default = {
kind: 'file',
path: configValue.dest,
layout
};
} else {
loggingConfig.appenders.default = {
kind: 'console',
layout
};
}

return loggingConfig;
}

Expand Down
28 changes: 28 additions & 0 deletions platform/legacy/__tests__/LegacyKbnServer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { LegacyKbnServer } from '..';

test('correctly returns `newPlatformProxyListener`.', () => {
const rawKbnServer = {
newPlatform: {
proxyListener: {}
}
};

const legacyKbnServer = new LegacyKbnServer(rawKbnServer);
expect(legacyKbnServer.newPlatformProxyListener).toBe(
rawKbnServer.newPlatform.proxyListener
);
});

test('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();
});
11 changes: 2 additions & 9 deletions platform/legacy/__tests__/LegacyPlatformConfig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@ describe('Retrieving values', () => {
expect(configAdapter.get('logging')).toEqual({
root: { level: 'off' },
appenders: {
default: {
kind: 'console',
layout: { kind: 'pattern', highlight: true }
}
default: { kind: 'legacy-appender' }
}
});
});
Expand All @@ -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: 'json' }
}
default: { kind: 'legacy-appender' }
}
});
});
Expand Down
6 changes: 3 additions & 3 deletions platform/legacy/__tests__/LegacyPlatformProxifier.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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];
})
);

Expand Down Expand Up @@ -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];
})
);

Expand Down
Original file line number Diff line number Diff line change
@@ -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,
],
]
`;
23 changes: 15 additions & 8 deletions platform/legacy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
};
};
39 changes: 39 additions & 0 deletions platform/legacy/logging/appenders/LegacyAppender.ts
Original file line number Diff line number Diff line change
@@ -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.log(
[record.level.id.toLowerCase(), ...record.context.split('.')],
record.error || record.message,
record.timestamp
);
}

async dispose() {}
}
Loading

0 comments on commit 01d0f31

Please sign in to comment.