mirror of
https://github.com/grafana/grafana.git
synced 2025-02-10 23:55:47 -06:00
logs: removed unused code (#61484)
This commit is contained in:
parent
fb5a033282
commit
117874176d
@ -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}
|
||||
|
@ -6,7 +6,7 @@ type FieldDef = {
|
||||
key: string;
|
||||
value: string;
|
||||
links?: Array<LinkModel<Field>>;
|
||||
fieldIndex?: number;
|
||||
fieldIndex: number;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user