Skip to content

Commit

Permalink
add conversion patterns for timestamp
Browse files Browse the repository at this point in the history
  • Loading branch information
mshustov committed Feb 7, 2020
1 parent 63f8fa7 commit 36ec899
Show file tree
Hide file tree
Showing 9 changed files with 458 additions and 70 deletions.
34 changes: 34 additions & 0 deletions src/core/server/logging/layouts/conversions/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 chalk from 'chalk';

import { Conversion } from './type';
import { LogRecord } from '../../log_record';

export const ContextConversion: Conversion = {
pattern: /{context}/gi,
formatter(record: LogRecord, highlight: boolean) {
let message = record.context;
if (highlight) {
message = chalk.magenta(message);
}
return message;
},
};
44 changes: 44 additions & 0 deletions src/core/server/logging/layouts/conversions/level.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 chalk from 'chalk';

import { Conversion } from './type';
import { LogLevel } from '../../log_level';
import { LogRecord } from '../../log_record';

const LEVEL_COLORS = new Map([
[LogLevel.Fatal, chalk.red],
[LogLevel.Error, chalk.red],
[LogLevel.Warn, chalk.yellow],
[LogLevel.Debug, chalk.green],
[LogLevel.Trace, chalk.blue],
]);

export const LevelConversion: Conversion = {
pattern: /{level}/gi,
formatter(record: LogRecord, highlight: boolean) {
let message = record.level.id.toUpperCase().padEnd(5);
if (highlight && LEVEL_COLORS.has(record.level)) {
const color = LEVEL_COLORS.get(record.level)!;
message = color(message);
}
return message;
},
};
29 changes: 29 additions & 0 deletions src/core/server/logging/layouts/conversions/message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 { Conversion } from './type';
import { LogRecord } from '../../log_record';

export const MessageConversion: Conversion = {
pattern: /{message}/gi,
formatter(record: LogRecord) {
// Error stack is much more useful than just the message.
return (record.error && record.error.stack) || record.message;
},
};
27 changes: 27 additions & 0 deletions src/core/server/logging/layouts/conversions/meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 { Conversion } from './type';
import { LogRecord } from '../../log_record';

export const MetaConversion: Conversion = {
pattern: /{meta}/gi,
formatter(record: LogRecord) {
return record.meta ? `[${JSON.stringify(record.meta)}]` : '';
},
};
28 changes: 28 additions & 0 deletions src/core/server/logging/layouts/conversions/pid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 { Conversion } from './type';
import { LogRecord } from '../../log_record';

export const PidConversion: Conversion = {
pattern: /{pid}/gi,
formatter(record: LogRecord) {
return String(record.pid);
},
};
87 changes: 87 additions & 0 deletions src/core/server/logging/layouts/conversions/timestamp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 moment from 'moment-timezone';

import { Conversion } from './type';
import { LogRecord } from '../../log_record';

const timestampRegExp = /{timestamp({([^}]+)})?({([^}]+)})?}/gi;

const formats = {
ISO8601: 'ISO8601',
ISO8601_TZ: 'ISO8601_TZ',
ABSOLUTE: 'ABSOLUTE',
UNIX: 'UNIX',
UNIX_MILLIS: 'UNIX_MILLIS',
};

function formatDate(date: Date, dateFormat: string = formats.ISO8601, timezone?: string): string {
const momentDate = moment(date);
if (timezone) {
momentDate.tz(timezone);
}
switch (dateFormat) {
case formats.ISO8601:
return momentDate.toISOString();
case formats.ISO8601_TZ:
return momentDate.format('YYYY-MM-DDTHH:mm:ss,SSSZZ');
case formats.ABSOLUTE:
return momentDate.format('HH:mm:ss,SSS');
case formats.UNIX:
return momentDate.format('X');
case formats.UNIX_MILLIS:
return momentDate.format('x');
default:
throw new Error(`Unknown format: ${dateFormat}`);
}
}

function validateDateFormat(input: string) {
if (Reflect.has(formats, input)) return;
throw new Error(
`Date format expected one of ${Reflect.ownKeys(formats).join(', ')}, but given: ${input}`
);
}

function validateTimezone(timezone: string) {
if (moment.tz.zone(timezone)) return;
throw new Error(`Unknown timezone: ${timezone}`);
}

function validate(rawString: string) {
for (const matched of rawString.matchAll(timestampRegExp)) {
const [, , dateFormat, , timezone] = matched;

if (dateFormat) {
validateDateFormat(dateFormat);
}
if (timezone) {
validateTimezone(timezone);
}
}
}

export const TimestampConversion: Conversion = {
pattern: timestampRegExp,
formatter(record: LogRecord, highlight: boolean, ...matched: string[]) {
const [, , dateFormat, , timezone] = matched;
return formatDate(record.timestamp, dateFormat, timezone);
},
validate,
};
25 changes: 25 additions & 0 deletions src/core/server/logging/layouts/conversions/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 { LogRecord } from 'kibana/server';

export interface Conversion {
pattern: RegExp;
formatter: (record: LogRecord, highlight: boolean) => string;
validate?: (input: string) => void;
}
Loading

0 comments on commit 36ec899

Please sign in to comment.