Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions apptest/tests/vlcluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,34 @@ import (
"github.com/VictoriaMetrics/VictoriaLogs/apptest"
)

// TestVlclusterUniqValuesMerge verifies that uniq_values correctly merges results when some storage nodes have no matching values.
func TestVlclusterUniqValuesMerge(t *testing.T) {
fs.MustRemoveDir(t.Name())
tc := apptest.NewTestCase(t)
defer tc.Stop()
sut := tc.MustStartDefaultVlcluster()

// Write the same group to two storage nodes. The first node has no x values,
// while the second node has x values. This exercises merging a non-empty
// uniq_values state into an empty destination state at vlselect.
storage0 := sut.StorageNode(0)
storage0.JSONLineWrite(t, []string{
`{"_msg":"no x","host":"h1","_time":"2025-01-01T01:00:00Z"}`,
}, apptest.IngestOpts{})
storage0.ForceFlush(t)

storage1 := sut.StorageNode(1)
storage1.JSONLineWrite(t, []string{
`{"_msg":"has x","host":"h1","x":"a","_time":"2025-01-01T01:00:00Z"}`,
}, apptest.IngestOpts{})
storage1.ForceFlush(t)

got := sut.LogsQLQuery(t, `* | stats by (host) uniq_values(x) as values`, apptest.QueryOpts{})
assertLogsQLResponseEqual(t, got, &apptest.LogsQLQueryResponse{
LogLines: []string{`{"host":"h1","values":"[\"a\"]"}`},
})
}

// TestVlclusterIngestAndQuery verifies that logs are correctly ingested and queried from cluster.
func TestVlclusterIngestAndQuery(t *testing.T) {
fs.MustRemoveDir(t.Name())
Expand Down
5 changes: 5 additions & 0 deletions apptest/vlcluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,11 @@ func (app *Vlcluster) LogsQLQueryRaw(t *testing.T, query string, opts QueryOpts)
return app.selectNode.cli.PostForm(t, url, values)
}

// StorageNode returns the i-th storage node, allowing direct log ingestion that bypasses the insert node.
func (app *Vlcluster) StorageNode(i int) *Vlsingle {
return app.storageNodes[i]
}

// String returns the string representation of the app state.
func (app *Vlcluster) String() string {
return "Vlcluster"
Expand Down
1 change: 1 addition & 0 deletions docs/victorialogs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ according to the following docs:
* FEATURE: [dashboards/kubernetes-explorer](https://github.com/VictoriaMetrics/VictoriaLogs/blob/master/dashboards/victorialogs-kubernetes-explorer.json): add new dashboard for exploring Kubernetes logs via [VictoriaLogs datasource](https://docs.victoriametrics.com/victorialogs/integrations/grafana/) in Grafana. Thanks to @sias32 for [the contribution](https://github.com/VictoriaMetrics/VictoriaLogs/pull/1254)!
* FEATURE: [File Collector](https://docs.victoriametrics.com/victorialogs/vlagent/#collect-logs-from-files): enhance glob pattern support with additional syntax: double-star `/**/` for matching nested directories (e.g. `/var/log/**/*.log`), alternatives `{a,b}` for matching multiple specific names (e.g. `{access,error}.log`), character classes `[a-z]` and `?` wildcard for single-character matching. See [#1393](https://github.com/VictoriaMetrics/VictoriaLogs/issues/1393) and [these docs](https://docs.victoriametrics.com/victorialogs/vlagent/#glob-pattern-requirements) for the full pattern syntax reference.

* BUGFIX: [LogsQL](https://docs.victoriametrics.com/victorialogs/logsql/): fix panic when using [`uniq_values()`](https://docs.victoriametrics.com/victorialogs/logsql/#uniq_values-stats) in the [`stats` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe) in VictoriaLogs cluster when some `vlstorage` nodes return no values for the requested field while other `vlstorage` nodes return values for the same group. See [#1383](https://github.com/VictoriaMetrics/VictoriaLogs/issues/1383).
* BUGFIX: [LogsQL](https://docs.victoriametrics.com/victorialogs/logsql/): fix [`unroll` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#unroll-pipe) and [`json_array_len` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#json_array_len-pipe) ignoring JSON arrays preceded by whitespace. See [#1427](https://github.com/VictoriaMetrics/VictoriaLogs/issues/1427).
* BUGFIX: [vlagent](https://docs.victoriametrics.com/victorialogs/vlagent/): hide sensitive values passed via `-remoteWrite.proxyURL` in `/metrics`, `/flags`, and startup logs. Previously these values could be exposed in plain text. See [#1320](https://github.com/VictoriaMetrics/VictoriaLogs/pull/1320).
* BUGFIX: [web UI](https://docs.victoriametrics.com/victorialogs/querying/#web-ui): sanitize markdown URLs in logs rendered with `markdown parsing` enabled, allowing only `http`, `https`, `mailto`, and `tel` schemes for active links and images. See [#1313](https://github.com/VictoriaMetrics/VictoriaLogs/pull/1313).
Expand Down
3 changes: 3 additions & 0 deletions lib/logstorage/stats_uniq_values.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ func (sup *statsUniqValuesProcessor) mergeState(_ *chunkedAllocator, sf statsFun
return
}

if sup.m == nil {
sup.m = make(map[string]struct{}, len(src.m))
}
for k := range src.m {
if _, ok := sup.m[k]; !ok {
sup.m[k] = struct{}{}
Expand Down