Skip to content

Commit 571df07

Browse files
authored
Remain in inQuotes state for escaped double-quotes (#366)
1 parent 4f8fe18 commit 571df07

File tree

3 files changed

+108
-1
lines changed

3 files changed

+108
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* BUGFIX: fix log level coloring when no custom rules are configured. See [#347](https://github.com/VictoriaMetrics/victorialogs-datasource/issues/347).
88
* BUGFIX: respect adhoc filters variables. See [#361](https://github.com/VictoriaMetrics/victorialogs-datasource/issues/361)
99
* BUGFIX: fix issue with concurrent map writes when performing multiple requests to the datasource. See [this issue](https://github.com/VictoriaMetrics/victoriametrics-datasource/issues/363)
10+
* BUGFIX: fix a parsing issue with quoted characters inside `_stream` fields. See [#365](https://github.com/VictoriaMetrics/victorialogs-datasource/issues/365).
1011

1112
## v0.19.3
1213

pkg/utils/stream_fields_parser.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,25 +80,30 @@ func splitStreamsToFields(streamFields string) []string {
8080
var fields []string
8181
var currentField strings.Builder
8282
var inQuotes bool
83+
var escaping bool
8384
var expectingComma bool
8485

8586
for i := 0; i < len(streamFields); i++ {
8687
char := streamFields[i]
8788

8889
if char == '"' {
89-
inQuotes = !inQuotes
90+
if !escaping {
91+
inQuotes = !inQuotes
92+
}
9093
currentField.WriteByte(char)
9194

9295
// After closing quote, we should be expecting a comma for field separation
9396
if !inQuotes {
9497
expectingComma = true
9598
}
99+
escaping = false
96100
} else if char == ',' && expectingComma {
97101
// Only split on commas that follow a closing quote
98102
field := strings.TrimSpace(currentField.String())
99103
fields = append(fields, field)
100104
currentField.Reset()
101105
expectingComma = false
106+
escaping = false
102107
} else {
103108
currentField.WriteByte(char)
104109

@@ -107,6 +112,7 @@ func splitStreamsToFields(streamFields string) []string {
107112
if expectingComma && char != ' ' {
108113
expectingComma = false
109114
}
115+
escaping = char == '\\' && !escaping
110116
}
111117
}
112118

pkg/utils/stream_fields_parser_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,4 +368,104 @@ func TestParseStreamFields(t *testing.T) {
368368
},
369369
}
370370
f(o)
371+
372+
// Escaped double-quotes
373+
o = opts{
374+
streamFields: `{peculiar="\"",job="loki.source.journal.read"}`,
375+
want: []StreamField{
376+
{
377+
Label: "peculiar",
378+
Value: `"`,
379+
}, {
380+
Label: "job",
381+
Value: "loki.source.journal.read",
382+
},
383+
},
384+
}
385+
f(o)
386+
387+
// Escaped double-quotes
388+
o = opts{
389+
streamFields: `{peculiar="\"",job="loki.source.journal.read",name="value"}`,
390+
want: []StreamField{
391+
{
392+
Label: "peculiar",
393+
Value: `"`,
394+
}, {
395+
Label: "job",
396+
Value: "loki.source.journal.read",
397+
}, {
398+
Label: "name",
399+
Value: "value",
400+
},
401+
},
402+
}
403+
f(o)
404+
405+
// Escaped backslash
406+
o = opts{
407+
streamFields: `{peculiar="\\",job="loki.source.journal.read"}`,
408+
want: []StreamField{
409+
{
410+
Label: "peculiar",
411+
Value: `\`,
412+
}, {
413+
Label: "job",
414+
Value: "loki.source.journal.read",
415+
},
416+
},
417+
}
418+
f(o)
419+
420+
// Escaped backslash
421+
o = opts{
422+
streamFields: `{peculiar="\\",job="loki.source.journal.read",name="value"}`,
423+
want: []StreamField{
424+
{
425+
Label: "peculiar",
426+
Value: `\`,
427+
}, {
428+
Label: "job",
429+
Value: "loki.source.journal.read",
430+
}, {
431+
Label: "name",
432+
Value: "value",
433+
},
434+
},
435+
}
436+
f(o)
437+
438+
// Escaped tab
439+
o = opts{
440+
streamFields: `{peculiar="\thello",job="loki.source.journal.read"}`,
441+
want: []StreamField{
442+
{
443+
Label: "peculiar",
444+
Value: "\thello",
445+
}, {
446+
Label: "job",
447+
Value: "loki.source.journal.read",
448+
},
449+
},
450+
}
451+
f(o)
452+
453+
// Escaped tab
454+
o = opts{
455+
streamFields: `{peculiar="\thello",job="loki.source.journal.read",name="value"}`,
456+
want: []StreamField{
457+
{
458+
Label: "peculiar",
459+
Value: "\thello",
460+
}, {
461+
Label: "job",
462+
Value: "loki.source.journal.read",
463+
}, {
464+
Label: "name",
465+
Value: "value",
466+
},
467+
},
468+
}
469+
f(o)
470+
371471
}

0 commit comments

Comments
 (0)