diff --git a/docs/sources/explore/logs-integration.md b/docs/sources/explore/logs-integration.md index 92ffc6eabe7..34275f90e03 100644 --- a/docs/sources/explore/logs-integration.md +++ b/docs/sources/explore/logs-integration.md @@ -92,15 +92,15 @@ For the logs where a `level` label is specified, we use the value of this label **Supported log levels and mapping of log level abbreviation and expressions:** -| Log level | Color | Supported expressions | -| :-------- | :--------- | ---------------------------------------- | -| critical | purple | emerg, fatal, alert, crit, critical | -| error | red | err, eror, error | -| warning | yellow | warn, warning | -| info | green | info, information, informational, notice | -| debug | blue | dbug, debug | -| trace | light blue | trace | -| unknown | grey | \* | +| Log level | Color | Supported expressions | +| :-------- | :--------- | ---------------------------------------------- | +| critical | purple | emerg, fatal, alert, crit, critical, 0, 1, 2 | +| error | red | err, eror, error, 3 | +| warning | yellow | warn, warning, 4 | +| info | green | info, information, informational, notice, 5, 6 | +| debug | blue | dbug, debug, 7 | +| trace | light blue | trace | +| unknown | grey | \* | ### Highlight searched words diff --git a/packages/grafana-data/src/types/logs.ts b/packages/grafana-data/src/types/logs.ts index 0124ffe98ac..2d363a63f7e 100644 --- a/packages/grafana-data/src/types/logs.ts +++ b/packages/grafana-data/src/types/logs.ts @@ -33,6 +33,21 @@ export enum LogLevel { unknown = 'unknown', } +/** + * Mapping of log level abbreviation to canonical log level. + * Supported levels are reduce to limit color variation. + */ +export const NumericLogLevel: Record = { + '0': LogLevel.critical, + '1': LogLevel.critical, + '2': LogLevel.critical, + '3': LogLevel.error, + '4': LogLevel.warning, + '5': LogLevel.info, + '6': LogLevel.info, + '7': LogLevel.debug, +}; + // Used for meta information such as common labels or returned log rows in logs view in Explore export enum LogsMetaKind { Number, diff --git a/public/app/features/logs/logsModel.ts b/public/app/features/logs/logsModel.ts index b76f8f81dc4..1bbe72776b6 100644 --- a/public/app/features/logs/logsModel.ts +++ b/public/app/features/logs/logsModel.ts @@ -425,7 +425,7 @@ export function logSeriesToLogsModel( let logLevel = LogLevel.unknown; const logLevelKey = (logLevelField && logLevelField.values[j]) || (labels && labels['level']); - if (logLevelKey) { + if (typeof logLevelKey === 'number' || typeof logLevelKey === 'string') { logLevel = getLogLevelFromKey(logLevelKey); } else { logLevel = getLogLevel(entry); diff --git a/public/app/features/logs/utils.test.ts b/public/app/features/logs/utils.test.ts index 184a594acb9..484d16efe7a 100644 --- a/public/app/features/logs/utils.test.ts +++ b/public/app/features/logs/utils.test.ts @@ -63,8 +63,30 @@ describe('getLogLevelFromKey()', () => { it('returns correct log level when level is capitalized', () => { expect(getLogLevelFromKey('INFO')).toBe(LogLevel.info); }); - it('returns unknown log level when level is integer', () => { - expect(getLogLevelFromKey(1)).toBe(LogLevel.unknown); + describe('Numeric log levels', () => { + it('returns critical', () => { + expect(getLogLevelFromKey(0)).toBe(LogLevel.critical); + expect(getLogLevelFromKey('0')).toBe(LogLevel.critical); + expect(getLogLevelFromKey('1')).toBe(LogLevel.critical); + expect(getLogLevelFromKey('2')).toBe(LogLevel.critical); + }); + it('returns error', () => { + expect(getLogLevelFromKey('3')).toBe(LogLevel.error); + }); + it('returns warning', () => { + expect(getLogLevelFromKey('4')).toBe(LogLevel.warning); + }); + it('returns info', () => { + expect(getLogLevelFromKey('5')).toBe(LogLevel.info); + expect(getLogLevelFromKey('6')).toBe(LogLevel.info); + }); + it('returns debug', () => { + expect(getLogLevelFromKey('7')).toBe(LogLevel.debug); + }); + it('returns unknown log level when level is an unexpected integer', () => { + expect(getLogLevelFromKey('8')).toBe(LogLevel.unknown); + expect(getLogLevelFromKey(8)).toBe(LogLevel.unknown); + }); }); }); diff --git a/public/app/features/logs/utils.ts b/public/app/features/logs/utils.ts index e1a0b54ecc1..150caee3740 100644 --- a/public/app/features/logs/utils.ts +++ b/public/app/features/logs/utils.ts @@ -13,6 +13,7 @@ import { MutableDataFrame, QueryResultMeta, LogsVolumeType, + NumericLogLevel, } from '@grafana/data'; import { getDataframeFields } from './components/logParser'; @@ -49,6 +50,17 @@ export function getLogLevelFromKey(key: string | number): LogLevel { if (level) { return level; } + if (typeof key === 'string') { + // The level did not match any entry of LogLevel. It might be unknown or a numeric level. + const numericLevel = parseInt(key, 10); + // Safety check to confirm that we're parsing a number and not a number with a string. + // For example `parseInt('1abcd', 10)` outputs 1 + if (key.length === numericLevel.toString().length) { + return NumericLogLevel[key] || LogLevel.unknown; + } + } else if (typeof key === 'number') { + return NumericLogLevel[key] || LogLevel.unknown; + } return LogLevel.unknown; }