Supports metadata logging in the new platform (#47456) (#47681)

* add tests for logWithMetadata in LP

* allow passing metadata to log in NP & LP

* get rid of ternary when build data to log
This commit is contained in:
Mikhail Shustov 2019-10-09 14:49:31 +02:00 committed by GitHub
parent 617e8f17c6
commit e927e5fb92
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 134 additions and 13 deletions

View file

@ -50,7 +50,7 @@ test('correctly forwards log records.', () => {
level: LogLevel.Trace,
context: 'some-context.sub-context',
message: 'some-message',
meta: { tags: ['important', 'tags'] },
meta: { tags: ['important', 'tags'], unknown: 2 },
};
loggingServer.log(firstLogRecord);
@ -85,7 +85,14 @@ Object {
expect(thirdCall).toMatchInlineSnapshot(`
Object {
"data": "some-message",
"data": Object {
Symbol(log message with metadata): Object {
"message": "some-message",
"metadata": Object {
"unknown": 2,
},
},
},
"tags": Array [
"debug",
"some-context",

View file

@ -26,6 +26,23 @@ import { setupLogging } from '../../../../legacy/server/logging';
import { LogLevel } from '../../logging/log_level';
import { LogRecord } from '../../logging/log_record';
export const metadataSymbol = Symbol('log message with metadata');
export function attachMetaData(message: string, metadata: Record<string, any> = {}) {
return {
[metadataSymbol]: {
message,
metadata,
},
};
}
const isEmptyObject = (obj: object) => Object.keys(obj).length === 0;
function getDataToLog(error: Error | undefined, metadata: object, message: string) {
if (error) return error;
if (!isEmptyObject(metadata)) return attachMetaData(message, metadata);
return message;
}
interface PluginRegisterParams {
plugin: {
register: (
@ -90,9 +107,11 @@ export class LegacyLoggingServer {
}
public log({ level, context, message, error, timestamp, meta = {} }: LogRecord) {
const { tags = [], ...metadata } = meta;
this.events.emit('log', {
data: error || message,
tags: [getLegacyLogLevel(level), ...context.split('.'), ...(meta.tags || [])],
data: getDataToLog(error, metadata, message),
tags: [getLegacyLogLevel(level), ...context.split('.'), ...tags],
timestamp: timestamp.getTime(),
});
}

View file

@ -19,6 +19,8 @@
import moment from 'moment';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { attachMetaData } from '../../../../src/core/server/legacy/logging/legacy_logging_server';
import {
createListStream,
createPromiseFromStreams,
@ -97,6 +99,79 @@ describe('KbnLoggerJsonFormat', () => {
expect(message).toBe('memory: 0.0B uptime: 0:00:00 load: [1.00 1.00 2.00] delay: 0.000');
});
describe('with metadata', () => {
it('logs an event with meta data', async () => {
const event = {
data: attachMetaData('message for event', {
prop1: 'value1',
prop2: 'value2',
}),
tags: ['tag1', 'tag2'],
};
const result = await createPromiseFromStreams([createListStream([event]), format]);
const { level, message, prop1, prop2, tags, } = JSON.parse(result);
expect(level).toBe(undefined);
expect(message).toBe('message for event');
expect(prop1).toBe('value1');
expect(prop2).toBe('value2');
expect(tags).toEqual(['tag1', 'tag2']);
});
it('meta data rewrites event fields', async () => {
const event = {
data: attachMetaData('message for event', {
tags: ['meta-data-tag'],
prop1: 'value1',
prop2: 'value2',
}),
tags: ['tag1', 'tag2'],
};
const result = await createPromiseFromStreams([createListStream([event]), format]);
const { level, message, prop1, prop2, tags, } = JSON.parse(result);
expect(level).toBe(undefined);
expect(message).toBe('message for event');
expect(prop1).toBe('value1');
expect(prop2).toBe('value2');
expect(tags).toEqual(['meta-data-tag']);
});
it('logs an event with empty meta data', async () => {
const event = {
data: attachMetaData('message for event'),
tags: ['tag1', 'tag2'],
};
const result = await createPromiseFromStreams([createListStream([event]), format]);
const { level, message, prop1, prop2, tags, } = JSON.parse(result);
expect(level).toBe(undefined);
expect(message).toBe('message for event');
expect(prop1).toBe(undefined);
expect(prop2).toBe(undefined);
expect(tags).toEqual(['tag1', 'tag2']);
});
it('does not log meta data for an error event', async () => {
const event = {
error: new Error('reason'),
data: attachMetaData('message for event', {
prop1: 'value1',
prop2: 'value2',
}),
tags: ['tag1', 'tag2'],
};
const result = await createPromiseFromStreams([createListStream([event]), format]);
const { level, message, prop1, prop2, tags, } = JSON.parse(result);
expect(level).toBe('error');
expect(message).toBe('reason');
expect(prop1).toBe(undefined);
expect(prop2).toBe(undefined);
expect(tags).toEqual(['tag1', 'tag2']);
});
});
describe('errors', () => {
it('error type', async () => {
const event = {

View file

@ -18,6 +18,8 @@
*/
import moment from 'moment';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { attachMetaData } from '../../../../src/core/server/legacy/logging/legacy_logging_server';
import {
createListStream,
@ -62,4 +64,25 @@ describe('KbnLoggerStringFormat', () => {
expect(String(result))
.toContain(moment(time).format('HH:mm:ss.SSS'));
});
describe('with metadata', () => {
it('does not log meta data', async () => {
const format = new KbnLoggerStringFormat({});
const event = {
data: attachMetaData('message for event', {
prop1: 'value1',
}),
tags: ['tag1', 'tag2'],
};
const result = await createPromiseFromStreams([createListStream([event]), format]);
const resultString = String(result);
expect(resultString).toContain('tag1');
expect(resultString).toContain('tag2');
expect(resultString).toContain('message for event');
expect(resultString).not.toContain('value1');
expect(resultString).not.toContain('prop1');
});
});
});

View file

@ -17,15 +17,17 @@
* under the License.
*/
import { isPlainObject } from 'lodash';
const symbol = Symbol('log message with metadata');
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { metadataSymbol, attachMetaData } from '../../../../src/core/server/legacy/logging/legacy_logging_server';
export const logWithMetadata = {
isLogEvent(eventData) {
return Boolean(isPlainObject(eventData) && eventData[symbol]);
return Boolean(isPlainObject(eventData) && eventData[metadataSymbol]);
},
getLogEventData(eventData) {
const { message, metadata } = eventData[symbol];
const { message, metadata } = eventData[metadataSymbol];
return {
...metadata,
message
@ -34,12 +36,7 @@ export const logWithMetadata = {
decorateServer(server) {
server.decorate('server', 'logWithMetadata', (tags, message, metadata = {}) => {
server.log(tags, {
[symbol]: {
message,
metadata,
},
});
server.log(tags, attachMetaData(message, metadata));
});
},
};