Commit a3c99f48 by David Committed by GitHub

Logs: Fix parsing for logfmt fields that have parens (#21407)

* Logs: Fix parsing for logfmt fields that have parens

- added `()`, `[]`, and `{}` to be allowed in logfmt field names

* Fix matcher
parent e9bcee30
...@@ -98,21 +98,25 @@ describe('LogsParsers', () => { ...@@ -98,21 +98,25 @@ describe('LogsParsers', () => {
test('should return parsed fields', () => { test('should return parsed fields', () => {
expect( expect(
parser.getFields( parser.getFields(
'foo=bar baz="42 + 1" msg="[resolver] received A record \\"127.0.0.1\\" for \\"localhost.\\" from udp:192.168.65.1"' '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([ ).toEqual([
'foo=bar', 'foo=bar',
'baz="42 + 1"', 'baz="42 + 1"',
'msg="[resolver] received A record \\"127.0.0.1\\" for \\"localhost.\\" from udp:192.168.65.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', () => { test('should return label for field', () => {
expect(parser.getLabelFromField('foo=bar')).toBe('foo'); expect(parser.getLabelFromField('foo=bar')).toBe('foo');
expect(parser.getLabelFromField('time(ms)=50')).toBe('time(ms)');
}); });
test('should return value for field', () => { test('should return value for field', () => {
expect(parser.getValueFromField('foo=bar')).toBe('bar'); expect(parser.getValueFromField('foo=bar')).toBe('bar');
expect(parser.getValueFromField('time(ms)=50')).toBe('50');
expect( expect(
parser.getValueFromField( parser.getValueFromField(
'msg="[resolver] received A record \\"127.0.0.1\\" for \\"localhost.\\" from udp:192.168.65.1"' 'msg="[resolver] received A record \\"127.0.0.1\\" for \\"localhost.\\" from udp:192.168.65.1"'
...@@ -126,6 +130,13 @@ describe('LogsParsers', () => { ...@@ -126,6 +130,13 @@ describe('LogsParsers', () => {
expect(match).toBeDefined(); expect(match).toBeDefined();
expect(match![1]).toBe('bar'); 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', () => { describe('JSON', () => {
......
import { countBy, chain } from 'lodash'; import { countBy, chain, escapeRegExp } from 'lodash';
import { LogLevel, LogRowModel, LogLabelStatsModel, LogsParser } from '../types/logs'; import { LogLevel, LogRowModel, LogLabelStatsModel, LogsParser } from '../types/logs';
import { DataFrame, FieldType } from '../types/index'; import { DataFrame, FieldType } from '../types/index';
...@@ -8,7 +8,7 @@ import { ArrayVector } from '../vector/ArrayVector'; ...@@ -8,7 +8,7 @@ import { ArrayVector } from '../vector/ArrayVector';
// first a label from start of the string or first white space, then any word chars until "=" // first a label from start of the string or first white space, then any word chars until "="
// second either an empty quotes, or anything that starts with quote and ends with unescaped quote, // second either an empty quotes, or anything that starts with quote and ends with unescaped quote,
// or any non whitespace chars that do not start with qoute // or any non whitespace chars that do not start with qoute
const LOGFMT_REGEXP = /(?:^|\s)(\w+)=(""|(?:".*?[^\\]"|[^"\s]\S*))/; const LOGFMT_REGEXP = /(?:^|\s)([\w\(\)\[\]\{\}]+)=(""|(?:".*?[^\\]"|[^"\s]\S*))/;
/** /**
* Returns the log level of a log line. * Returns the log level of a log line.
...@@ -85,7 +85,7 @@ export const LogsParsers: { [name: string]: LogsParser } = { ...@@ -85,7 +85,7 @@ export const LogsParsers: { [name: string]: LogsParser } = {
}, },
logfmt: { logfmt: {
buildMatcher: label => new RegExp(`(?:^|\\s)${label}=("[^"]*"|\\S+)`), buildMatcher: label => new RegExp(`(?:^|\\s)${escapeRegExp(label)}=("[^"]*"|\\S+)`),
getFields: line => { getFields: line => {
const fields: string[] = []; const fields: string[] = [];
line.replace(new RegExp(LOGFMT_REGEXP, 'g'), substring => { line.replace(new RegExp(LOGFMT_REGEXP, 'g'), substring => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment