mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
lib/logstorage: properly search for the surrounding logs in stream_context
pipe
The set of log fields in the found logs may differ from the set of log fields present in the log stream. So compare only the log fields in the found logs when searching for the matching log entry in the log stream. While at it, return _stream field in the delimiter log entry, since this field is used by VictoriaLogs Web UI for grouping logs by log streams.
This commit is contained in:
parent
e0ea83c466
commit
6bb66cb3e9
4 changed files with 27 additions and 18 deletions
|
@ -19,6 +19,8 @@ according to [these docs](https://docs.victoriametrics.com/victorialogs/quicksta
|
|||
|
||||
## tip
|
||||
|
||||
* BUGFIX: return the proper surrounding logs for [`stream_context` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stream_context-pipe) when additional [pipes](https://docs.victoriametrics.com/victorialogs/logsql/#pipes) are put after the `stream_context` pipe. This has been broken in [v0.26.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v0.26.0-victorialogs).
|
||||
|
||||
## [v0.26.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v0.26.0-victorialogs)
|
||||
|
||||
Released at 2024-07-01
|
||||
|
|
|
@ -364,6 +364,10 @@ func (wctx *pipeStreamContextWriteContext) writeStreamContextRows(streamID strin
|
|||
Name: "_stream_id",
|
||||
Value: streamID,
|
||||
},
|
||||
{
|
||||
Name: "_stream",
|
||||
Value: getFieldValue(r.fields, "_stream"),
|
||||
},
|
||||
{
|
||||
Name: "_msg",
|
||||
Value: "---",
|
||||
|
@ -402,20 +406,30 @@ func getStreamContextRowIdx(rows []streamContextRow, r *streamContextRow) int {
|
|||
if n == len(rows) {
|
||||
return -1
|
||||
}
|
||||
if rows[n].timestamp != r.timestamp {
|
||||
return -1
|
||||
|
||||
equalFields := func(fields []Field) bool {
|
||||
for _, f := range r.fields {
|
||||
if f.Value != getFieldValue(fields, f.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
for rows[n].timestamp == r.timestamp && !equalFields(rows[n].fields, r.fields) {
|
||||
|
||||
for rows[n].timestamp == r.timestamp && !equalFields(rows[n].fields) {
|
||||
n++
|
||||
if n >= len(rows) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
if rows[n].timestamp != r.timestamp {
|
||||
return -1
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sortStreamContextRows(rows []streamContextRow) {
|
||||
sort.SliceStable(rows, func(i, j int) bool {
|
||||
sort.Slice(rows, func(i, j int) bool {
|
||||
return rows[i].timestamp < rows[j].timestamp
|
||||
})
|
||||
}
|
||||
|
|
|
@ -79,20 +79,13 @@ func (f *Field) marshalToLogfmt(dst []byte) []byte {
|
|||
return dst
|
||||
}
|
||||
|
||||
func equalFields(a, b []Field) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, x := range a {
|
||||
y := b[i]
|
||||
if x.Name != y.Name {
|
||||
return false
|
||||
}
|
||||
if x.Value != y.Value {
|
||||
return false
|
||||
func getFieldValue(fields []Field, name string) string {
|
||||
for _, f := range fields {
|
||||
if f.Name == name {
|
||||
return f.Value
|
||||
}
|
||||
}
|
||||
return true
|
||||
return ""
|
||||
}
|
||||
|
||||
func needLogfmtQuoting(s string) bool {
|
||||
|
|
|
@ -707,7 +707,7 @@ func TestStorageRunQuery(t *testing.T) {
|
|||
| stream_context before 1000
|
||||
| stats count() rows`, [][]Field{
|
||||
{
|
||||
{"rows", "858"},
|
||||
{"rows", "825"},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
@ -716,7 +716,7 @@ func TestStorageRunQuery(t *testing.T) {
|
|||
| stream_context after 1000
|
||||
| stats count() rows`, [][]Field{
|
||||
{
|
||||
{"rows", "462"},
|
||||
{"rows", "495"},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue