mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Add UI support for detected_level
(#93574)
feat(detected_level): Add UI support for `detected_level`
This commit is contained in:
parent
da60c561a8
commit
7189a4af81
@ -5,7 +5,7 @@ import { GrafanaTheme2, Labels } from '@grafana/data';
|
||||
import { Tooltip, useStyles2 } from '@grafana/ui';
|
||||
|
||||
// Levels are already encoded in color, filename is a Loki-ism
|
||||
const HIDDEN_LABELS = ['level', 'lvl', 'filename'];
|
||||
const HIDDEN_LABELS = ['detected_level', 'level', 'lvl', 'filename'];
|
||||
|
||||
interface Props {
|
||||
labels: Labels;
|
||||
|
@ -45,7 +45,7 @@ export function parseLegacyLogsFrame(frame: DataFrame): LogsFrame | null {
|
||||
}
|
||||
|
||||
const timeNanosecondField = cache.getFieldByName('tsNs') ?? null;
|
||||
const severityField = cache.getFieldByName('level') ?? null;
|
||||
const severityField = cache.getFieldByName('detected_level') ?? cache.getFieldByName('level') ?? null;
|
||||
const idField = cache.getFieldByName('id') ?? null;
|
||||
|
||||
// extracting the labels is done very differently for old-loki-style and simple-style
|
||||
|
@ -360,6 +360,87 @@ describe('dataFrameToLogsModel', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('given one series should return expected logs model with detected_level', () => {
|
||||
const series: DataFrame[] = [
|
||||
createDataFrame({
|
||||
fields: [
|
||||
{
|
||||
name: 'time',
|
||||
type: FieldType.time,
|
||||
values: ['2019-04-26T09:28:11.352440161Z', '2019-04-26T14:42:50.991981292Z'],
|
||||
},
|
||||
{
|
||||
name: 'message',
|
||||
type: FieldType.string,
|
||||
values: ['foo=bar', 'foo=bar'],
|
||||
labels: {
|
||||
job: 'grafana',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'detected_level',
|
||||
type: FieldType.string,
|
||||
values: ['info', 'error'],
|
||||
},
|
||||
],
|
||||
meta: {
|
||||
limit: 1000,
|
||||
},
|
||||
refId: 'A',
|
||||
}),
|
||||
];
|
||||
const logsModel = dataFrameToLogsModel(series, 1);
|
||||
expect(logsModel.hasUniqueLabels).toBeFalsy();
|
||||
expect(logsModel.rows).toHaveLength(2);
|
||||
expect(logsModel.rows).toMatchObject([
|
||||
{
|
||||
entry: 'foo=bar',
|
||||
labels: { job: 'grafana' },
|
||||
logLevel: 'info',
|
||||
uniqueLabels: {},
|
||||
uid: 'A_0',
|
||||
},
|
||||
{
|
||||
entry: 'foo=bar',
|
||||
labels: { job: 'grafana' },
|
||||
logLevel: 'error',
|
||||
uniqueLabels: {},
|
||||
uid: 'A_1',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(logsModel.series).toHaveLength(2);
|
||||
expect(logsModel.series).toMatchObject([
|
||||
{
|
||||
name: 'info',
|
||||
fields: [
|
||||
{ type: 'time', values: [1556270891000, 1556289770000] },
|
||||
{ type: 'number', values: [1, 0] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'error',
|
||||
fields: [
|
||||
{ type: 'time', values: [1556289770000] },
|
||||
{ type: 'number', values: [1] },
|
||||
],
|
||||
},
|
||||
]);
|
||||
expect(logsModel.meta).toHaveLength(2);
|
||||
expect(logsModel.meta![0]).toMatchObject({
|
||||
label: COMMON_LABELS,
|
||||
value: {
|
||||
job: 'grafana',
|
||||
},
|
||||
kind: LogsMetaKind.LabelsMap,
|
||||
});
|
||||
expect(logsModel.meta![1]).toMatchObject({
|
||||
label: LIMIT_LABEL,
|
||||
value: `1000 (2 returned)`,
|
||||
kind: LogsMetaKind.String,
|
||||
});
|
||||
});
|
||||
|
||||
it('with infinite scrolling enabled it should return expected logs model', () => {
|
||||
config.featureToggles.logsInfiniteScrolling = true;
|
||||
|
||||
|
@ -424,7 +424,7 @@ export function logSeriesToLogsModel(
|
||||
}
|
||||
|
||||
let logLevel = LogLevel.unknown;
|
||||
const logLevelKey = (logLevelField && logLevelField.values[j]) || (labels && labels['level']);
|
||||
const logLevelKey = (logLevelField && logLevelField.values[j]) || (labels?.detected_level ?? labels?.level);
|
||||
if (typeof logLevelKey === 'number' || typeof logLevelKey === 'string') {
|
||||
logLevel = getLogLevelFromKey(logLevelKey);
|
||||
} else {
|
||||
@ -633,7 +633,7 @@ function defaultExtractLevel(dataFrame: DataFrame): LogLevel {
|
||||
}
|
||||
|
||||
function getLogLevelFromLabels(labels: Labels): LogLevel {
|
||||
const level = labels['level'] ?? labels['lvl'] ?? labels['loglevel'] ?? '';
|
||||
const level = labels['detected_level'] ?? labels['level'] ?? labels['lvl'] ?? labels['loglevel'] ?? '';
|
||||
return level ? getLogLevelFromKey(level) : LogLevel.unknown;
|
||||
}
|
||||
|
||||
|
@ -1429,11 +1429,10 @@ describe('LokiDatasource', () => {
|
||||
}
|
||||
)
|
||||
).toEqual({
|
||||
expr: 'sum by (level) (count_over_time({label="value"} | drop __error__[$__auto]))',
|
||||
expr: 'sum by (level, detected_level) (count_over_time({label="value"} | drop __error__[$__auto]))',
|
||||
queryType: LokiQueryType.Range,
|
||||
refId: 'log-volume-A',
|
||||
supportingQueryType: SupportingQueryType.LogsVolume,
|
||||
legendFormat: '{{ level }}',
|
||||
});
|
||||
});
|
||||
|
||||
@ -1448,11 +1447,10 @@ describe('LokiDatasource', () => {
|
||||
}
|
||||
)
|
||||
).toEqual({
|
||||
expr: 'sum by (level) (count_over_time({label="value"} | drop __error__[$__auto]))',
|
||||
expr: 'sum by (level, detected_level) (count_over_time({label="value"} | drop __error__[$__auto]))',
|
||||
queryType: LokiQueryType.Range,
|
||||
refId: 'log-volume-A',
|
||||
supportingQueryType: SupportingQueryType.LogsVolume,
|
||||
legendFormat: '{{ level }}',
|
||||
});
|
||||
});
|
||||
|
||||
@ -1468,8 +1466,7 @@ describe('LokiDatasource', () => {
|
||||
}
|
||||
)
|
||||
).toEqual({
|
||||
expr: 'sum by (level) (count_over_time({label="value"} | drop __error__[$__auto]))',
|
||||
legendFormat: '{{ level }}',
|
||||
expr: 'sum by (level, detected_level) (count_over_time({label="value"} | drop __error__[$__auto]))',
|
||||
queryType: 'range',
|
||||
refId: 'log-volume-A',
|
||||
supportingQueryType: 'logsVolume',
|
||||
@ -1510,7 +1507,9 @@ describe('LokiDatasource', () => {
|
||||
refId: 'A',
|
||||
}
|
||||
);
|
||||
expect(query?.expr).toEqual('sum by (level) (count_over_time({label="value"} | drop __error__[$__auto]))');
|
||||
expect(query?.expr).toEqual(
|
||||
'sum by (level, detected_level) (count_over_time({label="value"} | drop __error__[$__auto]))'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -217,7 +217,7 @@ export class LokiDatasource
|
||||
}
|
||||
|
||||
const dropErrorExpression = `${expr} | drop __error__`;
|
||||
const field = options.field || 'level';
|
||||
const field = options.field || 'level, detected_level';
|
||||
if (isQueryWithError(this.interpolateString(dropErrorExpression, placeHolderScopedVars)) === false) {
|
||||
expr = dropErrorExpression;
|
||||
}
|
||||
@ -228,7 +228,6 @@ export class LokiDatasource
|
||||
queryType: LokiQueryType.Range,
|
||||
supportingQueryType: SupportingQueryType.LogsVolume,
|
||||
expr: `sum by (${field}) (count_over_time(${expr}[$__auto]))`,
|
||||
legendFormat: `{{ ${field} }}`,
|
||||
};
|
||||
|
||||
case SupplementaryQueryType.LogsSample:
|
||||
|
@ -130,6 +130,11 @@ describe('extractLevelLikeLabelFromDataFrame', () => {
|
||||
input.fields[1].values = [{ error_level: 'info' }];
|
||||
expect(extractLevelLikeLabelFromDataFrame(input)).toBe('error_level');
|
||||
});
|
||||
it('returns label if detected_level label is present', () => {
|
||||
const input = cloneDeep(frame);
|
||||
input.fields[1].values = [{ detected_level: 'info' }];
|
||||
expect(extractLevelLikeLabelFromDataFrame(input)).toBe('detected_level');
|
||||
});
|
||||
it('returns undefined if no level-like label is present', () => {
|
||||
const input = cloneDeep(frame);
|
||||
input.fields[1].values = [{ foo: 'info' }];
|
||||
|
@ -121,7 +121,9 @@ export function extractLevelLikeLabelFromDataFrame(frame: DataFrame): string | n
|
||||
|
||||
// Find first level-like label
|
||||
for (let labels of labelsArray) {
|
||||
const label = Object.keys(labels).find((label) => label === 'lvl' || label.includes('level'));
|
||||
const label = Object.keys(labels).find(
|
||||
(label) => label === 'detected_level' || label === 'level' || label === 'lvl' || label.includes('level')
|
||||
);
|
||||
if (label) {
|
||||
levelLikeLabel = label;
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user