logs: removed unused code (#61484)

This commit is contained in:
Gábor Farkas 2023-01-13 14:11:57 +01:00 committed by GitHub
parent fb5a033282
commit 117874176d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 6 additions and 232 deletions

View File

@ -1,11 +1,10 @@
import { css, cx } from '@emotion/css';
import memoizeOne from 'memoize-one';
import React, { PureComponent } from 'react';
import { CoreApp, DataFrame, Field, GrafanaTheme2, LinkModel, LogRowModel } from '@grafana/data';
import { Themeable2, withTheme2 } from '@grafana/ui';
import { calculateFieldStats, calculateLogsLabelStats, calculateStats, getParser } from '../utils';
import { calculateLogsLabelStats, calculateStats } from '../utils';
import { LogDetailsRow } from './LogDetailsRow';
import { getLogRowStyles } from './getLogRowStyles';
@ -50,13 +49,6 @@ const getStyles = (theme: GrafanaTheme2) => {
};
class UnThemedLogDetails extends PureComponent<Props> {
getParser = memoizeOne(getParser);
getStatsForField = (key: string) => {
const matcher = this.getParser(this.props.row.entry)!.buildMatcher(key);
return calculateFieldStats(this.props.getRows(), matcher);
};
render() {
const {
app,
@ -135,11 +127,7 @@ class UnThemedLogDetails extends PureComponent<Props> {
onClickHideField={onClickHideField}
onClickFilterOutLabel={onClickFilterOutLabel}
onClickFilterLabel={onClickFilterLabel}
getStats={() =>
fieldIndex === undefined
? this.getStatsForField(key)
: calculateStats(row.dataFrame.fields[fieldIndex].values.toArray())
}
getStats={() => calculateStats(row.dataFrame.fields[fieldIndex].values.toArray())}
displayedFields={displayedFields}
wrapLogMessage={wrapLogMessage}
row={row}
@ -165,11 +153,7 @@ class UnThemedLogDetails extends PureComponent<Props> {
links={links}
onClickShowField={onClickShowField}
onClickHideField={onClickHideField}
getStats={() =>
fieldIndex === undefined
? this.getStatsForField(key)
: calculateStats(row.dataFrame.fields[fieldIndex].values.toArray())
}
getStats={() => calculateStats(row.dataFrame.fields[fieldIndex].values.toArray())}
displayedFields={displayedFields}
wrapLogMessage={wrapLogMessage}
row={row}

View File

@ -6,7 +6,7 @@ type FieldDef = {
key: string;
value: string;
links?: Array<LinkModel<Field>>;
fieldIndex?: number;
fieldIndex: number;
};
/**

View File

@ -3,7 +3,6 @@ import { Labels, LogLevel, LogsModel, LogRowModel, LogsSortOrder, MutableDataFra
import {
getLogLevel,
calculateLogsLabelStats,
calculateFieldStats,
getParser,
LogsParsers,
calculateStats,
@ -115,49 +114,6 @@ describe('LogsParsers', () => {
expect(parser.test('foo')).toBeFalsy();
expect(parser.test('foo=bar')).toBeTruthy();
});
test('should return detected fields', () => {
expect(
parser.getFields(
'foo=bar baz="42 + 1" msg="[resolver] received A record \\"127.0.0.1\\" for \\"localhost.\\" from udp:192.168.65.1" time(ms)=50 label{foo}=bar'
)
).toEqual([
'foo=bar',
'baz="42 + 1"',
'msg="[resolver] received A record \\"127.0.0.1\\" for \\"localhost.\\" from udp:192.168.65.1"',
'time(ms)=50',
'label{foo}=bar',
]);
});
test('should return label for field', () => {
expect(parser.getLabelFromField('foo=bar')).toBe('foo');
expect(parser.getLabelFromField('time(ms)=50')).toBe('time(ms)');
});
test('should return value for field', () => {
expect(parser.getValueFromField('foo=bar')).toBe('bar');
expect(parser.getValueFromField('time(ms)=50')).toBe('50');
expect(
parser.getValueFromField(
'msg="[resolver] received A record \\"127.0.0.1\\" for \\"localhost.\\" from udp:192.168.65.1"'
)
).toBe('"[resolver] received A record \\"127.0.0.1\\" for \\"localhost.\\" from udp:192.168.65.1"');
});
test('should build a valid value matcher', () => {
const matcher = parser.buildMatcher('foo');
const match = 'foo=bar'.match(matcher);
expect(match).toBeDefined();
expect(match![1]).toBe('bar');
});
test('should build a valid complex value matcher', () => {
const matcher = parser.buildMatcher('time(ms)');
const match = 'time(ms)=50'.match(matcher);
expect(match).toBeDefined();
expect(match![1]).toBe('50');
});
});
describe('JSON', () => {
@ -168,83 +124,6 @@ describe('LogsParsers', () => {
expect(parser.test('"foo"')).toBeFalsy();
expect(parser.test('{"foo":"bar"}')).toBeTruthy();
});
test('should return detected fields', () => {
expect(parser.getFields('{ "foo" : "bar", "baz" : 42 }')).toEqual(['"foo":"bar"', '"baz":42']);
});
test('should return detected fields for nested quotes', () => {
expect(parser.getFields(`{"foo":"bar: '[value=\\"42\\"]'"}`)).toEqual([`"foo":"bar: '[value=\\"42\\"]'"`]);
});
test('should return label for field', () => {
expect(parser.getLabelFromField('"foo" : "bar"')).toBe('foo');
expect(parser.getLabelFromField('"docker.memory.fail.count":0')).toBe('docker.memory.fail.count');
});
test('should return value for field', () => {
expect(parser.getValueFromField('"foo" : "bar"')).toBe('"bar"');
expect(parser.getValueFromField('"foo" : 42')).toBe('42');
expect(parser.getValueFromField('"foo" : 42.1')).toBe('42.1');
});
test('should build a valid value matcher for strings', () => {
const matcher = parser.buildMatcher('foo');
const match = '{"foo":"bar"}'.match(matcher);
expect(match).toBeDefined();
expect(match![1]).toBe('bar');
});
test('should build a valid value matcher for integers', () => {
const matcher = parser.buildMatcher('foo');
const match = '{"foo":42.1}'.match(matcher);
expect(match).toBeDefined();
expect(match![1]).toBe('42.1');
});
});
});
describe('calculateFieldStats()', () => {
test('should return no stats for empty rows', () => {
expect(calculateFieldStats([], /foo=(.*)/)).toEqual([]);
});
test('should return no stats if extractor does not match', () => {
const rows = [
{
entry: 'foo=bar',
},
] as LogRowModel[];
expect(calculateFieldStats(rows, /baz=(.*)/)).toEqual([]);
});
test('should return stats for found field', () => {
const rows = [
{
entry: 'foo="42 + 1"',
},
{
entry: 'foo=503 baz=foo',
},
{
entry: 'foo="42 + 1"',
},
{
entry: 't=2018-12-05T07:44:59+0000 foo=503',
},
] as LogRowModel[];
expect(calculateFieldStats(rows, /foo=("[^"]*"|\S+)/)).toMatchObject([
{
value: '"42 + 1"',
count: 2,
},
{
value: '503',
count: 2,
},
]);
});
});

View File

@ -1,15 +1,6 @@
import { countBy, chain, escapeRegExp } from 'lodash';
import { countBy, chain } from 'lodash';
import {
ArrayVector,
DataFrame,
FieldType,
LogLevel,
LogRowModel,
LogLabelStatsModel,
LogsModel,
LogsSortOrder,
} from '@grafana/data';
import { LogLevel, LogRowModel, LogLabelStatsModel, LogsModel, LogsSortOrder } from '@grafana/data';
// This matches:
// first a label from start of the string or first white space, then any word chars until "="
@ -53,49 +44,7 @@ export function getLogLevelFromKey(key: string | number): LogLevel {
return LogLevel.unknown;
}
export function addLogLevelToSeries(series: DataFrame, lineIndex: number): DataFrame {
const levels = new ArrayVector<LogLevel>();
const lines = series.fields[lineIndex];
for (let i = 0; i < lines.values.length; i++) {
const line = lines.values.get(lineIndex);
levels.buffer.push(getLogLevel(line));
}
return {
...series, // Keeps Tags, RefID etc
fields: [
...series.fields,
{
name: 'LogLevel',
type: FieldType.string,
values: levels,
config: {},
},
],
};
}
interface LogsParser {
/**
* Value-agnostic matcher for a field label.
* Used to filter rows, and first capture group contains the value.
*/
buildMatcher: (label: string) => RegExp;
/**
* Returns all parsable substrings from a line, used for highlighting
*/
getFields: (line: string) => string[];
/**
* Gets the label name from a parsable substring of a line
*/
getLabelFromField: (field: string) => string;
/**
* Gets the label value from a parsable substring of a line
*/
getValueFromField: (field: string) => string;
/**
* Function to verify if this is a valid parser for the given line.
* The parser accepts the line if it returns true.
@ -105,18 +54,6 @@ interface LogsParser {
export const LogsParsers: { [name: string]: LogsParser } = {
JSON: {
buildMatcher: (label) => new RegExp(`(?:{|,)\\s*"${label}"\\s*:\\s*"?([\\d\\.]+|[^"]*)"?`),
getFields: (line) => {
try {
const parsed = JSON.parse(line);
return Object.keys(parsed).map((key) => {
return `"${key}":${JSON.stringify(parsed[key])}`;
});
} catch {}
return [];
},
getLabelFromField: (field) => (field.match(/^"([^"]+)"\s*:/) || [])[1],
getValueFromField: (field) => (field.match(/:\s*(.*)$/) || [])[1],
test: (line) => {
let parsed;
try {
@ -129,36 +66,10 @@ export const LogsParsers: { [name: string]: LogsParser } = {
},
logfmt: {
buildMatcher: (label) => new RegExp(`(?:^|\\s)${escapeRegExp(label)}=("[^"]*"|\\S+)`),
getFields: (line) => {
const fields: string[] = [];
line.replace(new RegExp(LOGFMT_REGEXP, 'g'), (substring) => {
fields.push(substring.trim());
return '';
});
return fields;
},
getLabelFromField: (field) => (field.match(LOGFMT_REGEXP) || [])[1],
getValueFromField: (field) => (field.match(LOGFMT_REGEXP) || [])[2],
test: (line) => LOGFMT_REGEXP.test(line),
},
};
export function calculateFieldStats(rows: LogRowModel[], extractor: RegExp): LogLabelStatsModel[] {
// Consider only rows that satisfy the matcher
const rowsWithField = rows.filter((row) => extractor.test(row.entry));
const rowCount = rowsWithField.length;
// Get field value counts for eligible rows
const countsByValue = countBy(rowsWithField, (r) => {
const row: LogRowModel = r;
const match = row.entry.match(extractor);
return match ? match[1] : null;
});
return getSortedCounts(countsByValue, rowCount);
}
export function calculateLogsLabelStats(rows: LogRowModel[], label: string): LogLabelStatsModel[] {
// Consider only rows that have the given label
const rowsWithLabel = rows.filter((row) => row.labels[label] !== undefined);