mirror of
https://github.com/hanzoai/o11y.git
synced 2026-10-15 12:58:33 +00:00
debrand: hanzo-ds sqlbuilder/sqlparser forks + brand-neutral mock seam
Completes the debrand on top of the driver/dscol work already on main: - Repoint to canonical native forks: hanzo-ds/sqlbuilder v1.42.2, hanzo-ds/sqlparser v0.4.16. - Datastore sql flavor now renders native ILIKE (v1.42.2); statement-builder test expectations updated from the LOWER(x) LIKE LOWER(?) emulation. - Mock: expose datastore-go-mock behind a brand-neutral datastoremock.Conn seam so first-party code names no ClickConnMockCommon symbol. - Scrub CH/SigNoz from comments; drop dead SigNoz tracker links. Zero clickhouse/signoz/CH in first-party Go and go.mod.
This commit is contained in:
@@ -27,10 +27,8 @@ require (
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674
|
||||
github.com/hanzoai/datastore-go-mock v0.14.3
|
||||
github.com/hanzoai/datastore-sql-parser v0.4.17
|
||||
github.com/hanzoai/govaluate v0.1.0
|
||||
github.com/hanzoai/otel-collector v0.144.13
|
||||
github.com/hanzoai/sqlbuilder v1.39.2
|
||||
github.com/hanzoai/sqlite v0.3.0
|
||||
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12
|
||||
github.com/knadh/koanf v1.5.0
|
||||
@@ -424,6 +422,8 @@ require (
|
||||
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
||||
github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
|
||||
github.com/hanzo-ds/sqlbuilder v1.42.2
|
||||
github.com/hanzo-ds/sqlparser v0.4.16
|
||||
github.com/hanzoai/cloud v1.786.112
|
||||
github.com/hanzoai/datastore-go/v2 v2.47.2
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
|
||||
@@ -901,6 +901,10 @@ github.com/hanzo-ds/mock v0.14.3 h1:z82cTtCqfWS2XELCd9CvXPTObRHiWxLfQbCWe4QKQos=
|
||||
github.com/hanzo-ds/mock v0.14.3/go.mod h1:e4/Onlu7dbV1kJWxlfefPLcRDb35bvN7Uj/I4+quEVc=
|
||||
github.com/hanzo-ds/native v0.72.0 h1:lQhH2dza3foJCHN6scIVsEpqdj/xzI1N0QlI94vtWh8=
|
||||
github.com/hanzo-ds/native v0.72.0/go.mod h1:11FZtFdtfXMnmpybDEW6+uPRWFeC3TOT59YaV+lED+E=
|
||||
github.com/hanzo-ds/sqlbuilder v1.42.2 h1:739sudcAav513tsIj57CUjADCcEUzrztpOPYHy1nzjE=
|
||||
github.com/hanzo-ds/sqlbuilder v1.42.2/go.mod h1:Nk+F+SDxtsqAeI63jT7JPACZQ60top3rQCmKXUhfKQw=
|
||||
github.com/hanzo-ds/sqlparser v0.4.16 h1:OeWiLSL6u/I/RzhUKHHbE33MevQ2b0QVyDgSJur6OTs=
|
||||
github.com/hanzo-ds/sqlparser v0.4.16/go.mod h1:b+9oCGF3WYGz4FfVo9eZ4wJiF7fiLa9aCWFGCcbqQbY=
|
||||
github.com/hanzoai/ai v1.806.9 h1:D9mYBiWL7SWgrKHK7/gMxDBa4ZUovs3Al60NZzNftKw=
|
||||
github.com/hanzoai/ai v1.806.9/go.mod h1:dpcWcO9pLWZaBFl+1yJeyazgLDn8gmbFynB/zwtxldg=
|
||||
github.com/hanzoai/beego/v2 v2.4.1 h1:rChSPaueQtzriNxmt4jonobe6ujeqho0WTcPVYaH8Ac=
|
||||
@@ -915,8 +919,6 @@ github.com/hanzoai/datastore-go-mock v0.14.3 h1:n3fsY8yr9h9ewzgmtb38qugT2UqhjIML
|
||||
github.com/hanzoai/datastore-go-mock v0.14.3/go.mod h1:bWEdo98i6P0K2Z/0CIabxh/ML0BvqY8bocm6bsO7N7U=
|
||||
github.com/hanzoai/datastore-go/v2 v2.47.2 h1:SThITu8+otmlWuAiSmZ2L3z+2suLIAdAfwoliwO8qLs=
|
||||
github.com/hanzoai/datastore-go/v2 v2.47.2/go.mod h1:MQYk/Ztzt+WoT1SMx2wS2XvvdETWgXJQfUwT/bBj8qw=
|
||||
github.com/hanzoai/datastore-sql-parser v0.4.17 h1:I12ZticgPs6dz0lrI44dwCC3hvzdemIOShOUukAqMwk=
|
||||
github.com/hanzoai/datastore-sql-parser v0.4.17/go.mod h1:r5c3YMxBZzeuAlWJ0uAn8AHReHDtZYb3NYyt0jVLUMU=
|
||||
github.com/hanzoai/dbx v1.16.0 h1:C8wsb9BIiit4nYnXizpcB4SyzVaepPkQFwq5i9fxAV0=
|
||||
github.com/hanzoai/dbx v1.16.0/go.mod h1:ynP6HSiDDoFZ8M3DC+XvSglBPFRygfTd/gjTWabh4yA=
|
||||
github.com/hanzoai/expr v1.17.8 h1:qDKAhoS5DOU9gjPR/tBmucQhI0W9ysZM1l5hrdlhgAY=
|
||||
@@ -935,8 +937,6 @@ github.com/hanzoai/pdf v1.2.0 h1:3/zYs4estaf6hpa3Ug/NgfYEQpmkmMClmRcREAP8KUo=
|
||||
github.com/hanzoai/pdf v1.2.0/go.mod h1:Lb5LhbMY7QvrxxMeKbI22Kvoz4XQhHgJV7Erq0U8zHU=
|
||||
github.com/hanzoai/search-go v0.36.0 h1:bQfbAs/bc/s3qZDCtSqEAxp48koHkb0Z4ezUknt2AQc=
|
||||
github.com/hanzoai/search-go v0.36.0/go.mod h1:jdcYUdG6exMfRfJvilWhaNdAR8XWQRPvZtuRxQBzn34=
|
||||
github.com/hanzoai/sqlbuilder v1.39.2 h1:YDfZlCfgwRYSYag5LjeuclbQ5CRvqLehOmeDdTnzA6M=
|
||||
github.com/hanzoai/sqlbuilder v1.39.2/go.mod h1:XlCgRiiXt/5PWeXG7OValozMoZN+ywY1T0hOwqZvnxo=
|
||||
github.com/hanzoai/sqlite v0.3.0 h1:Siqa7b89CgSCteg5ubXOCQiPRxYIJGb9kMemwjXMIUQ=
|
||||
github.com/hanzoai/sqlite v0.3.0/go.mod h1:/eumCoj+3FLbLXr3jZomamv2DdJvh4No2nfYDdlGgUU=
|
||||
github.com/hanzoai/tasks v1.51.0 h1:Mf1dyL8Y2EQ/m8cIc5+i8BdYvob6fZek9bj8O8sHJ3Y=
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Package datastoresql binds the SQL dialect spoken by the telemetry datastore.
|
||||
package datastoresql
|
||||
|
||||
import "github.com/hanzoai/sqlbuilder"
|
||||
import "github.com/hanzo-ds/sqlbuilder"
|
||||
|
||||
// Flavor is the SQL dialect every statement builder renders through. It is the
|
||||
// one place first-party code names the upstream dialect selector.
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/types/dashboardtypes"
|
||||
qbtypesv5 "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/antlr4-go/antlr/v4"
|
||||
sqlbuilder "github.com/hanzoai/sqlbuilder"
|
||||
sqlbuilder "github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
// bunPlaceholderFlavor is any flavor that renders `?` placeholders, which bun
|
||||
|
||||
@@ -200,7 +200,7 @@ func (module *module) GetByMetricNames(ctx context.Context, orgID valuer.UUID, m
|
||||
}
|
||||
|
||||
// Track which metrics were found in this widget, along with the
|
||||
// group-by and filter labels referenced for each metric. CH/PromQL
|
||||
// group-by and filter labels referenced for each metric. Datastore/PromQL
|
||||
// paths are presence-only and leave the label sets empty.
|
||||
foundMetrics := make(map[string]bool)
|
||||
groupByByMetric := make(map[string][]string)
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/o11y/pkg/valuer"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
// quoteIdentifier wraps s in backticks for use as a Datastore identifier,
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/types/inframonitoringtypes"
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/valuer"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
// getPerGroupHostStatusCounts computes the number of active and inactive hosts per group
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/types/inframonitoringtypes"
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/valuer"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
// buildNodeRecords assembles the page records. Condition counts come from
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/types/inframonitoringtypes"
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/valuer"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
// buildPodRecords assembles the page records. Phase counts come from
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
"github.com/hanzoai/o11y/pkg/datastoresql"
|
||||
|
||||
sqlbuilder "github.com/hanzoai/sqlbuilder"
|
||||
sqlbuilder "github.com/hanzo-ds/sqlbuilder"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/hanzoai/o11y/pkg/cache"
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
dsmock "github.com/hanzoai/datastore-go-mock"
|
||||
"github.com/hanzoai/o11y/pkg/telemetrystore/datastoremock"
|
||||
"github.com/hanzoai/o11y/pkg/cache"
|
||||
"github.com/hanzoai/o11y/pkg/cache/cachetest"
|
||||
"github.com/hanzoai/o11y/pkg/errors"
|
||||
@@ -77,7 +78,7 @@ func newFlagger(t *testing.T, reductionEnabled bool) flagger.Flagger {
|
||||
// newTestModule builds the metricsexplorer module backed by a mocked datastore
|
||||
// connection, a mock metadata store, and an in-memory cache. reductionEnabled
|
||||
// toggles the metrics-reduction feature flag.
|
||||
func newTestModule(t *testing.T, matcher sqlmock.QueryMatcher, reductionEnabled bool) (metricsexplorer.Module, dsmock.ClickConnMockCommon, *telemetrytypestest.MockMetadataStore) {
|
||||
func newTestModule(t *testing.T, matcher sqlmock.QueryMatcher, reductionEnabled bool) (metricsexplorer.Module, datastoremock.Conn, *telemetrytypestest.MockMetadataStore) {
|
||||
t.Helper()
|
||||
|
||||
ts := telemetrystoretest.New(telemetrystore.Config{}, matcher)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/querybuilder"
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
type conditionBuilder struct {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
schema "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
var ruleStateHistoryColumns = map[string]*schema.Column{
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/types/rulestatehistorytypes"
|
||||
"github.com/hanzoai/o11y/pkg/types/ruletypes"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
sqlbuilder "github.com/hanzoai/sqlbuilder"
|
||||
sqlbuilder "github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/hanzoai/o11y/pkg/datastoresql"
|
||||
|
||||
sqlbuilder "github.com/hanzoai/sqlbuilder"
|
||||
sqlbuilder "github.com/hanzo-ds/sqlbuilder"
|
||||
|
||||
"github.com/hanzoai/o11y/pkg/errors"
|
||||
"github.com/hanzoai/o11y/pkg/telemetrystore"
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
dsmock "github.com/hanzoai/datastore-go-mock"
|
||||
"github.com/hanzoai/o11y/pkg/telemetrystore/datastoremock"
|
||||
"github.com/hanzoai/o11y/pkg/telemetrystore/telemetrystoretest"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -32,7 +33,7 @@ func TestClient_QuerySamples(t *testing.T) {
|
||||
metricName string
|
||||
subQuery string
|
||||
args []any
|
||||
setupMock func(mock dsmock.ClickConnMockCommon, args ...any)
|
||||
setupMock func(mock datastoremock.Conn, args ...any)
|
||||
expectedTimeSeries int
|
||||
expectError bool
|
||||
description string
|
||||
@@ -57,7 +58,7 @@ func TestClient_QuerySamples(t *testing.T) {
|
||||
expectedTimeSeries: 2,
|
||||
expectError: false,
|
||||
description: "Should successfully retrieve samples for multiple time series",
|
||||
setupMock: func(mock dsmock.ClickConnMockCommon, args ...any) {
|
||||
setupMock: func(mock datastoremock.Conn, args ...any) {
|
||||
values := [][]interface{}{
|
||||
{"cpu_usage", uint64(123), int64(1001), float64(1.1), uint32(0)},
|
||||
{"cpu_usage", uint64(123), int64(1001), float64(1.1), uint32(0)},
|
||||
@@ -136,7 +137,7 @@ func TestClient_getFingerprintsFromDatastoreQuery(t *testing.T) {
|
||||
metricName string
|
||||
subQuery string
|
||||
args []any
|
||||
setupMock func(m dsmock.ClickConnMockCommon, args ...any)
|
||||
setupMock func(m datastoremock.Conn, args ...any)
|
||||
want map[uint64][]prompb.Label
|
||||
wantErr bool
|
||||
}{
|
||||
@@ -149,7 +150,7 @@ func TestClient_getFingerprintsFromDatastoreQuery(t *testing.T) {
|
||||
// args slice is empty here, but test‑case still owns it
|
||||
args: []any{},
|
||||
|
||||
setupMock: func(m dsmock.ClickConnMockCommon, args ...any) {
|
||||
setupMock: func(m datastoremock.Conn, args ...any) {
|
||||
rows := [][]any{
|
||||
{uint64(123), `{"t1":"s1","t2":"s2"}`},
|
||||
{uint64(234), `{"t1":"s1","t2":"s2"}`},
|
||||
|
||||
@@ -56,7 +56,7 @@ func newchSQLQuery(
|
||||
}
|
||||
|
||||
func (q *chSQLQuery) Fingerprint() string {
|
||||
// No caching for CH queries for now
|
||||
// No caching for Datastore queries for now
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ func (q *querier) postProcessResults(ctx context.Context, orgID valuer.UUID, res
|
||||
// Apply table formatting for UI if requested
|
||||
if req.FormatOptions != nil && req.FormatOptions.FormatTableResultForUI && req.RequestType == qbtypes.RequestTypeScalar {
|
||||
|
||||
// merge result only needed for non-CH query
|
||||
// merge result only needed for non-Datastore query
|
||||
if len(req.CompositeQuery.Queries) == 1 {
|
||||
if req.CompositeQuery.Queries[0].Type == qbtypes.QueryTypeDatastoreSQL {
|
||||
retResult := map[string]any{}
|
||||
|
||||
@@ -499,7 +499,7 @@ func (r *BaseRule) FilterNewSeries(ctx context.Context, ts time.Time, series []*
|
||||
return series, nil
|
||||
}
|
||||
|
||||
// Build lookup keys from series which will be used to query metadata from CH
|
||||
// Build lookup keys from series which will be used to query metadata from Datastore
|
||||
lookupKeys := make([]telemetrytypes.MetricMetadataLookupKey, 0)
|
||||
seriesIdxToLookupKeys := make(map[int][]telemetrytypes.MetricMetadataLookupKey) // series index -> lookup keys
|
||||
|
||||
|
||||
@@ -937,7 +937,6 @@ var (
|
||||
// So recovery only triggers when the value climbs back above 30%, not just above 20%.
|
||||
// The zone between 20%–30% is the hysteresis band to avoid flapping when
|
||||
// the value oscillates around the alert threshold.
|
||||
// TODO(srikanthccv): https://github.com/SigNoz/engineering-pod/issues/4332
|
||||
{
|
||||
description: "Category 1: Below operator - value in recovery zone, no active alert -> no alert returned",
|
||||
values: &qbtypes.TimeSeries{
|
||||
@@ -957,7 +956,6 @@ var (
|
||||
activeAlerts: map[uint64]struct{}{}, // No active alerts
|
||||
thresholdName: "test_threshold",
|
||||
},
|
||||
// TODO(srikanthccv): https://github.com/SigNoz/engineering-pod/issues/4333
|
||||
{
|
||||
description: "Category 1: NotEq operator - value in recovery zone, no active alert -> no alert returned",
|
||||
values: &qbtypes.TimeSeries{
|
||||
@@ -1280,7 +1278,6 @@ var (
|
||||
expectedRecoveryTarget: 70.0,
|
||||
thresholdName: "cat1_atleastonce_below_recovery",
|
||||
},
|
||||
// TODO(srikanthccv): https://github.com/SigNoz/engineering-pod/issues/4333
|
||||
{
|
||||
description: "Category 1: AtleastOnce + Equals - active alert, one value equals recovery -> IsRecovering=true",
|
||||
values: &qbtypes.TimeSeries{
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/hanzoai/o11y/pkg/datastoresql"
|
||||
|
||||
dsparser "github.com/hanzoai/datastore-sql-parser/parser"
|
||||
dsparser "github.com/hanzo-ds/sqlparser/parser"
|
||||
"github.com/hanzoai/o11y/pkg/errors"
|
||||
"github.com/hanzoai/o11y/pkg/factory"
|
||||
"github.com/hanzoai/o11y/pkg/flagger"
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/errors"
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
@@ -230,12 +230,12 @@ func DataTypeCollisionHandledFieldName(key *telemetrytypes.TelemetryFieldKey, va
|
||||
telemetrytypes.FieldDataTypeFloat64,
|
||||
telemetrytypes.FieldDataTypeArrayFloat64:
|
||||
switch v := value.(type) {
|
||||
// why? ; CH returns an error for a simple check
|
||||
// why? ; Datastore returns an error for a simple check
|
||||
// attributes_number['http.status_code'] = 200 but not for attributes_number['http.status_code'] >= 200
|
||||
// DB::Exception: Bad get: has UInt64, requested Float64.
|
||||
// How is it working in v4? v4 prepares the full query with values in query string
|
||||
// When we format the float it becomes attributes_number['http.status_code'] = 200.000
|
||||
// Which CH gladly accepts and doesn't throw error
|
||||
// Which Datastore gladly accepts and doesn't throw error
|
||||
// However, when passed as query args, the default formatter
|
||||
// (see github.com/hanzoai/datastore-go/v2 bind.go format())
|
||||
// is used which prepares the
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/antlr4-go/antlr/v4"
|
||||
"github.com/hanzoai/o11y/pkg/errors"
|
||||
grammar "github.com/hanzoai/o11y/pkg/parser/havingexpression/grammar"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
// havingExpressionRewriteVisitor walks the parse tree of a HavingExpression in a single
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
|
||||
sqlbuilder "github.com/hanzoai/sqlbuilder"
|
||||
sqlbuilder "github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
var searchTroubleshootingGuideURL = "https://o11y.io/docs/userguide/search-troubleshooting/"
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
grammar "github.com/hanzoai/o11y/pkg/parser/filterquery/grammar"
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
sqlbuilder "github.com/hanzoai/sqlbuilder"
|
||||
sqlbuilder "github.com/hanzo-ds/sqlbuilder"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ func NewAPI(settings factory.ProviderSettings, queryParser QueryParser) *API {
|
||||
|
||||
// AnalyzeQueryFilter analyzes a query and extracts metric names and grouping columns.
|
||||
func (a *API) AnalyzeQueryFilter(w http.ResponseWriter, r *http.Request) {
|
||||
// Limit request body size to 255 KB (CH query limit is 256 KB)
|
||||
// Limit request body size to 255 KB (Datastore query limit is 256 KB)
|
||||
r.Body = http.MaxBytesReader(w, r.Body, 255*1024)
|
||||
|
||||
var req parsertypes.QueryFilterAnalyzeRequest
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
dsparser "github.com/hanzoai/datastore-sql-parser/parser"
|
||||
dsparser "github.com/hanzo-ds/sqlparser/parser"
|
||||
"github.com/hanzoai/o11y/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -308,7 +308,7 @@ func (e *DatastoreFilterExtractor) extractColumnStrByExpr(expr dsparser.Expr) st
|
||||
// Ident is a simple identifier like "region" or "timestamp"
|
||||
case *dsparser.Ident:
|
||||
// Handling for backticks which are native to Datastore and used for literal names.
|
||||
// CH Parser removes the backticks from the identifier, so we need to add them back.
|
||||
// Datastore Parser removes the backticks from the identifier, so we need to add them back.
|
||||
if ex.QuoteType == dsparser.BackTicks {
|
||||
return "`" + ex.Name + "`"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package queryfilterextractor
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/hanzoai/datastore-sql-parser/parser"
|
||||
"github.com/hanzo-ds/sqlparser/parser"
|
||||
"github.com/hanzoai/o11y/pkg/errors"
|
||||
)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
schema "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
type conditionBuilder struct {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
schema "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/telemetryresourcefilter"
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
type auditQueryStatementBuilder struct {
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/valuer"
|
||||
schema "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
type conditionBuilder struct {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/flagger/flaggertest"
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -208,7 +208,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorLike,
|
||||
value: "%error%",
|
||||
expectedSQL: "LOWER(body) LIKE LOWER(?)",
|
||||
expectedSQL: "body ILIKE ?",
|
||||
expectedArgs: []any{"%error%"},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -220,7 +220,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorNotLike,
|
||||
value: "%error%",
|
||||
expectedSQL: "LOWER(body) NOT LIKE LOWER(?)",
|
||||
expectedSQL: "body NOT ILIKE ?",
|
||||
expectedArgs: []any{"%error%"},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -233,7 +233,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorILike,
|
||||
value: "%admin%",
|
||||
expectedSQL: "(LOWER(attributes_string['user.id']) LIKE LOWER(?) AND mapContains(attributes_string, 'user.id') = ?)",
|
||||
expectedSQL: "(attributes_string['user.id'] ILIKE ? AND mapContains(attributes_string, 'user.id') = ?)",
|
||||
expectedArgs: []any{"%admin%", true},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -246,7 +246,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorNotILike,
|
||||
value: "%admin%",
|
||||
expectedSQL: "WHERE LOWER(attributes_string['user.id']) NOT LIKE LOWER(?)",
|
||||
expectedSQL: "WHERE attributes_string['user.id'] NOT ILIKE ?",
|
||||
expectedArgs: []any{"%admin%"},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -259,7 +259,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorContains,
|
||||
value: 521509198310,
|
||||
expectedSQL: "LOWER(attributes_string['user.id']) LIKE LOWER(?)",
|
||||
expectedSQL: "attributes_string['user.id'] ILIKE ?",
|
||||
expectedArgs: []any{"%521509198310%", true},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -271,7 +271,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorContains,
|
||||
value: 521509198310,
|
||||
expectedSQL: "LOWER(body) LIKE LOWER(?)",
|
||||
expectedSQL: "body ILIKE ?",
|
||||
expectedArgs: []any{"%521509198310%"},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -284,7 +284,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorContains,
|
||||
value: "admin",
|
||||
expectedSQL: "(LOWER(attributes_string['user.id']) LIKE LOWER(?) AND mapContains(attributes_string, 'user.id') = ?)",
|
||||
expectedSQL: "(attributes_string['user.id'] ILIKE ? AND mapContains(attributes_string, 'user.id') = ?)",
|
||||
expectedArgs: []any{"%admin%", true},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -727,7 +727,7 @@ func TestConditionForJSONBodySearch(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorContains,
|
||||
value: "200",
|
||||
expectedSQL: `LOWER(JSON_VALUE(body, '$."http"."status_code"')) LIKE LOWER(?)`,
|
||||
expectedSQL: `JSON_VALUE(body, '$."http"."status_code"') ILIKE ?`,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
@@ -738,7 +738,7 @@ func TestConditionForJSONBodySearch(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorNotContains,
|
||||
value: "200",
|
||||
expectedSQL: `LOWER(JSON_VALUE(body, '$."http"."status_code"')) NOT LIKE LOWER(?)`,
|
||||
expectedSQL: `JSON_VALUE(body, '$."http"."status_code"') NOT ILIKE ?`,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/valuer"
|
||||
schema "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
"github.com/hanzoai/otel-collector/utils"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
@@ -126,7 +126,7 @@ func TestFilterExprLogsBodyJSON(t *testing.T) {
|
||||
category: "json",
|
||||
query: `body.message CONTAINS "hello 'world'"`,
|
||||
shouldPass: true,
|
||||
expectedQuery: `WHERE (LOWER(JSON_VALUE(body, '$."message"')) LIKE LOWER(?) AND JSON_EXISTS(body, '$."message"'))`,
|
||||
expectedQuery: `WHERE (JSON_VALUE(body, '$."message"') ILIKE ? AND JSON_EXISTS(body, '$."message"'))`,
|
||||
expectedArgs: []any{"%hello 'world'%"},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
|
||||
@@ -1035,7 +1035,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "ILIKE operator",
|
||||
query: "message ILIKE \"%error%\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE (LOWER(attributes_string['message']) LIKE LOWER(?) AND mapContains(attributes_string, 'message') = ?)",
|
||||
expectedQuery: "WHERE (attributes_string['message'] ILIKE ? AND mapContains(attributes_string, 'message') = ?)",
|
||||
expectedArgs: []any{"%error%", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1043,7 +1043,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "ILIKE operator",
|
||||
query: "path ILIKE \"/api/%\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE (LOWER(attributes_string['path']) LIKE LOWER(?) AND mapContains(attributes_string, 'path') = ?)",
|
||||
expectedQuery: "WHERE (attributes_string['path'] ILIKE ? AND mapContains(attributes_string, 'path') = ?)",
|
||||
expectedArgs: []any{"/api/%", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1051,7 +1051,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "ILIKE operator",
|
||||
query: "email ILIKE \"%@EXAMPLE.com\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE (LOWER(attributes_string['email']) LIKE LOWER(?) AND mapContains(attributes_string, 'email') = ?)",
|
||||
expectedQuery: "WHERE (attributes_string['email'] ILIKE ? AND mapContains(attributes_string, 'email') = ?)",
|
||||
expectedArgs: []any{"%@EXAMPLE.com", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1059,7 +1059,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "ILIKE operator",
|
||||
query: "filename ILIKE \"%.PDF\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE (LOWER(attributes_string['filename']) LIKE LOWER(?) AND mapContains(attributes_string, 'filename') = ?)",
|
||||
expectedQuery: "WHERE (attributes_string['filename'] ILIKE ? AND mapContains(attributes_string, 'filename') = ?)",
|
||||
expectedArgs: []any{"%.PDF", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1103,7 +1103,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "NOT ILIKE operator",
|
||||
query: "message NOT ILIKE \"%error%\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE LOWER(attributes_string['message']) NOT LIKE LOWER(?)",
|
||||
expectedQuery: "WHERE attributes_string['message'] NOT ILIKE ?",
|
||||
expectedArgs: []any{"%error%"},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1111,7 +1111,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "NOT ILIKE operator",
|
||||
query: "path NOT ILIKE \"/api/%\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE LOWER(attributes_string['path']) NOT LIKE LOWER(?)",
|
||||
expectedQuery: "WHERE attributes_string['path'] NOT ILIKE ?",
|
||||
expectedArgs: []any{"/api/%"},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1119,7 +1119,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "NOT ILIKE operator",
|
||||
query: "email NOT ILIKE \"%@EXAMPLE.com\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE LOWER(attributes_string['email']) NOT LIKE LOWER(?)",
|
||||
expectedQuery: "WHERE attributes_string['email'] NOT ILIKE ?",
|
||||
expectedArgs: []any{"%@EXAMPLE.com"},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1127,7 +1127,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "NOT ILIKE operator",
|
||||
query: "filename NOT ILIKE \"%.PDF\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE LOWER(attributes_string['filename']) NOT LIKE LOWER(?)",
|
||||
expectedQuery: "WHERE attributes_string['filename'] NOT ILIKE ?",
|
||||
expectedArgs: []any{"%.PDF"},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1491,7 +1491,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "CONTAINS operator",
|
||||
query: "message CONTAINS \"error\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE (LOWER(attributes_string['message']) LIKE LOWER(?) AND mapContains(attributes_string, 'message') = ?)",
|
||||
expectedQuery: "WHERE (attributes_string['message'] ILIKE ? AND mapContains(attributes_string, 'message') = ?)",
|
||||
expectedArgs: []any{"%error%", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1499,7 +1499,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "number contains body",
|
||||
query: "body CONTAINS 521509198310",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE LOWER(body) LIKE LOWER(?)",
|
||||
expectedQuery: "WHERE body ILIKE ?",
|
||||
expectedArgs: []any{"%521509198310%"},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1507,7 +1507,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "CONTAINS operator",
|
||||
query: "level CONTAINS \"critical\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE (LOWER(attributes_string['level']) LIKE LOWER(?) AND mapContains(attributes_string, 'level') = ?)",
|
||||
expectedQuery: "WHERE (attributes_string['level'] ILIKE ? AND mapContains(attributes_string, 'level') = ?)",
|
||||
expectedArgs: []any{"%critical%", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1515,7 +1515,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "CONTAINS operator",
|
||||
query: "path CONTAINS \"api\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE (LOWER(attributes_string['path']) LIKE LOWER(?) AND mapContains(attributes_string, 'path') = ?)",
|
||||
expectedQuery: "WHERE (attributes_string['path'] ILIKE ? AND mapContains(attributes_string, 'path') = ?)",
|
||||
expectedArgs: []any{"%api%", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1525,7 +1525,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "NOT CONTAINS operator",
|
||||
query: "message NOT CONTAINS \"error\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE LOWER(attributes_string['message']) NOT LIKE LOWER(?)",
|
||||
expectedQuery: "WHERE attributes_string['message'] NOT ILIKE ?",
|
||||
expectedArgs: []any{"%error%"},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1533,7 +1533,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "NOT CONTAINS operator",
|
||||
query: "level NOT CONTAINS \"critical\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE LOWER(attributes_string['level']) NOT LIKE LOWER(?)",
|
||||
expectedQuery: "WHERE attributes_string['level'] NOT ILIKE ?",
|
||||
expectedArgs: []any{"%critical%"},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1541,7 +1541,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "NOT CONTAINS operator",
|
||||
query: "path NOT CONTAINS \"api\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE LOWER(attributes_string['path']) NOT LIKE LOWER(?)",
|
||||
expectedQuery: "WHERE attributes_string['path'] NOT ILIKE ?",
|
||||
expectedArgs: []any{"%api%"},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1595,7 +1595,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "Explicit AND",
|
||||
query: "message CONTAINS \"error\" AND level=\"ERROR\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE ((LOWER(attributes_string['message']) LIKE LOWER(?) AND mapContains(attributes_string, 'message') = ?) AND (attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?))",
|
||||
expectedQuery: "WHERE ((attributes_string['message'] ILIKE ? AND mapContains(attributes_string, 'message') = ?) AND (attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?))",
|
||||
expectedArgs: []any{"%error%", true, "ERROR", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1673,7 +1673,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "AND + OR combinations",
|
||||
query: "level=\"ERROR\" OR (level=\"WARN\" AND message CONTAINS \"timeout\")",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE ((attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?) OR (((attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?) AND (LOWER(attributes_string['message']) LIKE LOWER(?) AND mapContains(attributes_string, 'message') = ?))))",
|
||||
expectedQuery: "WHERE ((attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?) OR (((attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?) AND (attributes_string['message'] ILIKE ? AND mapContains(attributes_string, 'message') = ?))))",
|
||||
expectedArgs: []any{"ERROR", true, "WARN", true, "%timeout%", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1727,7 +1727,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "AND + OR + NOT combinations",
|
||||
query: "(level=\"ERROR\" OR level=\"FATAL\") AND NOT message CONTAINS \"expected\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE ((((attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?) OR (attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?))) AND NOT ((LOWER(attributes_string['message']) LIKE LOWER(?) AND mapContains(attributes_string, 'message') = ?)))",
|
||||
expectedQuery: "WHERE ((((attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?) OR (attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?))) AND NOT ((attributes_string['message'] ILIKE ? AND mapContains(attributes_string, 'message') = ?)))",
|
||||
expectedArgs: []any{"ERROR", true, "FATAL", true, "%expected%", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1761,7 +1761,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "Implicit AND",
|
||||
query: "message CONTAINS \"error\" level=\"ERROR\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE ((LOWER(attributes_string['message']) LIKE LOWER(?) AND mapContains(attributes_string, 'message') = ?) AND (attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?))",
|
||||
expectedQuery: "WHERE ((attributes_string['message'] ILIKE ? AND mapContains(attributes_string, 'message') = ?) AND (attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?))",
|
||||
expectedArgs: []any{"%error%", true, "ERROR", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1779,7 +1779,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "Mixed implicit/explicit AND",
|
||||
query: "count>0 level=\"ERROR\" AND message CONTAINS \"error\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE ((toFloat64(attributes_number['count']) > ? AND mapContains(attributes_number, 'count') = ?) AND (attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?) AND (LOWER(attributes_string['message']) LIKE LOWER(?) AND mapContains(attributes_string, 'message') = ?))",
|
||||
expectedQuery: "WHERE ((toFloat64(attributes_number['count']) > ? AND mapContains(attributes_number, 'count') = ?) AND (attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?) AND (attributes_string['message'] ILIKE ? AND mapContains(attributes_string, 'message') = ?))",
|
||||
expectedArgs: []any{float64(0), true, "ERROR", true, "%error%", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -1857,7 +1857,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "Complex nested grouping",
|
||||
query: "(level=\"ERROR\" OR (level=\"WARN\" AND (message CONTAINS \"timeout\" OR message CONTAINS \"connection\")))",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE (((attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?) OR (((attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?) AND (((LOWER(attributes_string['message']) LIKE LOWER(?) AND mapContains(attributes_string, 'message') = ?) OR (LOWER(attributes_string['message']) LIKE LOWER(?) AND mapContains(attributes_string, 'message') = ?)))))))",
|
||||
expectedQuery: "WHERE (((attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?) OR (((attributes_string['level'] = ? AND mapContains(attributes_string, 'level') = ?) AND (((attributes_string['message'] ILIKE ? AND mapContains(attributes_string, 'message') = ?) OR (attributes_string['message'] ILIKE ? AND mapContains(attributes_string, 'message') = ?)))))))",
|
||||
expectedArgs: []any{"ERROR", true, "WARN", true, "%timeout%", true, "%connection%", true},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -2269,7 +2269,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
category: "More common filters",
|
||||
query: "service.name=\"api\" AND (status>=500 OR duration>1000) AND NOT message CONTAINS \"expected\"",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE ((multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) = ? AND multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) IS NOT NULL) AND (((toFloat64(attributes_number['status']) >= ? AND mapContains(attributes_number, 'status') = ?) OR (toFloat64(attributes_number['duration']) > ? AND mapContains(attributes_number, 'duration') = ?))) AND NOT ((LOWER(attributes_string['message']) LIKE LOWER(?) AND mapContains(attributes_string, 'message') = ?)))",
|
||||
expectedQuery: "WHERE ((multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) = ? AND multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) IS NOT NULL) AND (((toFloat64(attributes_number['status']) >= ? AND mapContains(attributes_number, 'status') = ?) OR (toFloat64(attributes_number['duration']) > ? AND mapContains(attributes_number, 'duration') = ?))) AND NOT ((attributes_string['message'] ILIKE ? AND mapContains(attributes_string, 'message') = ?)))",
|
||||
expectedArgs: []any{"api", float64(500), true, float64(1000), true, "%expected%", true},
|
||||
},
|
||||
|
||||
@@ -2396,7 +2396,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
)
|
||||
`,
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE ((((((((toFloat64(attributes_number['status']) >= ? AND mapContains(attributes_number, 'status') = ?) AND (toFloat64(attributes_number['status']) < ? AND mapContains(attributes_number, 'status') = ?))) OR (((toFloat64(attributes_number['status']) >= ? AND mapContains(attributes_number, 'status') = ?) AND (toFloat64(attributes_number['status']) < ? AND mapContains(attributes_number, 'status') = ?) AND NOT ((toFloat64(attributes_number['status']) = ? AND mapContains(attributes_number, 'status') = ?)))))) AND ((((multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) = ? OR multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) = ? OR multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) = ?) AND multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) IS NOT NULL) OR (((multiIf(resource.`service.type` IS NOT NULL, resource.`service.type`::String, mapContains(resources_string, 'service.type'), resources_string['service.type'], NULL) = ? AND multiIf(resource.`service.type` IS NOT NULL, resource.`service.type`::String, mapContains(resources_string, 'service.type'), resources_string['service.type'], NULL) IS NOT NULL) AND NOT ((multiIf(resource.`service.deprecated` IS NOT NULL, resource.`service.deprecated`::String, mapContains(resources_string, 'service.deprecated'), resources_string['service.deprecated'], NULL) = ? AND multiIf(resource.`service.deprecated` IS NOT NULL, resource.`service.deprecated`::String, mapContains(resources_string, 'service.deprecated'), resources_string['service.deprecated'], NULL) IS NOT NULL)))))))) AND (((((toFloat64(attributes_number['duration']) < ? AND mapContains(attributes_number, 'duration') = ?) OR ((toFloat64(attributes_number['duration']) BETWEEN ? AND ? AND mapContains(attributes_number, 'duration') = ?)))) AND ((multiIf(resource.`environment` IS NOT NULL, resource.`environment`::String, mapContains(resources_string, 'environment'), resources_string['environment'], NULL) <> ? OR (((multiIf(resource.`environment` IS NOT NULL, resource.`environment`::String, mapContains(resources_string, 'environment'), resources_string['environment'], NULL) = ? AND multiIf(resource.`environment` IS NOT NULL, resource.`environment`::String, mapContains(resources_string, 'environment'), resources_string['environment'], NULL) IS NOT NULL) AND (attributes_bool['is_automated_test'] = ? AND mapContains(attributes_bool, 'is_automated_test') = ?))))))) AND NOT ((((((LOWER(attributes_string['message']) LIKE LOWER(?) AND mapContains(attributes_string, 'message') = ?) OR (LOWER(attributes_string['message']) LIKE LOWER(?) AND mapContains(attributes_string, 'message') = ?))) AND (attributes_string['severity'] = ? AND mapContains(attributes_string, 'severity') = ?)))))",
|
||||
expectedQuery: "WHERE ((((((((toFloat64(attributes_number['status']) >= ? AND mapContains(attributes_number, 'status') = ?) AND (toFloat64(attributes_number['status']) < ? AND mapContains(attributes_number, 'status') = ?))) OR (((toFloat64(attributes_number['status']) >= ? AND mapContains(attributes_number, 'status') = ?) AND (toFloat64(attributes_number['status']) < ? AND mapContains(attributes_number, 'status') = ?) AND NOT ((toFloat64(attributes_number['status']) = ? AND mapContains(attributes_number, 'status') = ?)))))) AND ((((multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) = ? OR multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) = ? OR multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) = ?) AND multiIf(resource.`service.name` IS NOT NULL, resource.`service.name`::String, mapContains(resources_string, 'service.name'), resources_string['service.name'], NULL) IS NOT NULL) OR (((multiIf(resource.`service.type` IS NOT NULL, resource.`service.type`::String, mapContains(resources_string, 'service.type'), resources_string['service.type'], NULL) = ? AND multiIf(resource.`service.type` IS NOT NULL, resource.`service.type`::String, mapContains(resources_string, 'service.type'), resources_string['service.type'], NULL) IS NOT NULL) AND NOT ((multiIf(resource.`service.deprecated` IS NOT NULL, resource.`service.deprecated`::String, mapContains(resources_string, 'service.deprecated'), resources_string['service.deprecated'], NULL) = ? AND multiIf(resource.`service.deprecated` IS NOT NULL, resource.`service.deprecated`::String, mapContains(resources_string, 'service.deprecated'), resources_string['service.deprecated'], NULL) IS NOT NULL)))))))) AND (((((toFloat64(attributes_number['duration']) < ? AND mapContains(attributes_number, 'duration') = ?) OR ((toFloat64(attributes_number['duration']) BETWEEN ? AND ? AND mapContains(attributes_number, 'duration') = ?)))) AND ((multiIf(resource.`environment` IS NOT NULL, resource.`environment`::String, mapContains(resources_string, 'environment'), resources_string['environment'], NULL) <> ? OR (((multiIf(resource.`environment` IS NOT NULL, resource.`environment`::String, mapContains(resources_string, 'environment'), resources_string['environment'], NULL) = ? AND multiIf(resource.`environment` IS NOT NULL, resource.`environment`::String, mapContains(resources_string, 'environment'), resources_string['environment'], NULL) IS NOT NULL) AND (attributes_bool['is_automated_test'] = ? AND mapContains(attributes_bool, 'is_automated_test') = ?))))))) AND NOT ((((((attributes_string['message'] ILIKE ? AND mapContains(attributes_string, 'message') = ?) OR (attributes_string['message'] ILIKE ? AND mapContains(attributes_string, 'message') = ?))) AND (attributes_string['severity'] = ? AND mapContains(attributes_string, 'severity') = ?)))))",
|
||||
expectedArgs: []any{
|
||||
float64(200), true, float64(300), true, float64(400), true, float64(500), true, float64(404), true,
|
||||
"api", "web", "auth",
|
||||
@@ -2483,7 +2483,7 @@ func TestFilterExprLogsConflictNegation(t *testing.T) {
|
||||
category: "not_contains",
|
||||
query: "body NOT CONTAINS 'done'",
|
||||
shouldPass: true,
|
||||
expectedQuery: "WHERE (LOWER(body) NOT LIKE LOWER(?) AND LOWER(attributes_string['body']) NOT LIKE LOWER(?))",
|
||||
expectedQuery: "WHERE (body NOT ILIKE ? AND attributes_string['body'] NOT ILIKE ?)",
|
||||
expectedArgs: []any{"%done%", "%done%"},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
@@ -2492,7 +2492,7 @@ func TestFilterExprLogsConflictNegation(t *testing.T) {
|
||||
query: "body NOT LIKE 'done'",
|
||||
shouldPass: true,
|
||||
// lower index search on body even for LIKE
|
||||
expectedQuery: "WHERE (LOWER(body) NOT LIKE LOWER(?) AND attributes_string['body'] NOT LIKE ?)",
|
||||
expectedQuery: "WHERE (body NOT ILIKE ? AND attributes_string['body'] NOT LIKE ?)",
|
||||
expectedArgs: []any{"done", "done"},
|
||||
expectedErrorContains: "",
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
schemamigrator "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -191,7 +191,7 @@ func TestJSONStmtBuilder_PrimitivePaths(t *testing.T) {
|
||||
name: "message Contains 'Iron Award'",
|
||||
filter: "message Contains 'Iron Award'",
|
||||
expected: TestExpected{
|
||||
WhereClause: "LOWER(body_v2.message) LIKE LOWER(?)",
|
||||
WhereClause: "body_v2.message ILIKE ?",
|
||||
Args: []any{"%Iron Award%", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
},
|
||||
},
|
||||
@@ -209,7 +209,7 @@ func TestJSONStmtBuilder_PrimitivePaths(t *testing.T) {
|
||||
name: "Simple Int field Contains value",
|
||||
filter: "body.user.age Contains 25",
|
||||
expected: TestExpected{
|
||||
WhereClause: "(((LOWER(toString(dynamicElement(body_v2.`user.age`, 'Int64'))) LIKE LOWER(?)) AND has(JSONAllPaths(body_v2), 'user.age')) OR ((LOWER(dynamicElement(body_v2.`user.age`, 'String')) LIKE LOWER(?)) AND has(JSONAllPaths(body_v2), 'user.age')))",
|
||||
WhereClause: "(((toString(dynamicElement(body_v2.`user.age`, 'Int64')) ILIKE ?) AND has(JSONAllPaths(body_v2), 'user.age')) OR ((dynamicElement(body_v2.`user.age`, 'String') ILIKE ?) AND has(JSONAllPaths(body_v2), 'user.age')))",
|
||||
Args: []any{"%25%", "%25%", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
Warnings: []string{"Key `user.age` is ambiguous, found 2 different combinations of field context / data type: [name=user.age,context=body,datatype=int64 name=user.age,context=body,datatype=string]."},
|
||||
},
|
||||
@@ -218,7 +218,7 @@ func TestJSONStmtBuilder_PrimitivePaths(t *testing.T) {
|
||||
name: "Simple Float field Contains value",
|
||||
filter: "body.user.height Contains 5.8",
|
||||
expected: TestExpected{
|
||||
WhereClause: "((LOWER(toString(dynamicElement(body_v2.`user.height`, 'Float64'))) LIKE LOWER(?)) AND has(JSONAllPaths(body_v2), 'user.height'))",
|
||||
WhereClause: "((toString(dynamicElement(body_v2.`user.height`, 'Float64')) ILIKE ?) AND has(JSONAllPaths(body_v2), 'user.height'))",
|
||||
Args: []any{"%5.8%", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
},
|
||||
},
|
||||
@@ -266,7 +266,7 @@ func TestJSONStmtBuilder_PrimitivePaths(t *testing.T) {
|
||||
name: "Primitive String NotContains",
|
||||
filter: "body.user.name NOT CONTAINS 'IIT'",
|
||||
expected: TestExpected{
|
||||
WhereClause: "(LOWER(assumeNotNull(dynamicElement(body_v2.`user.name`, 'String'))) NOT LIKE LOWER(?))",
|
||||
WhereClause: "(assumeNotNull(dynamicElement(body_v2.`user.name`, 'String')) NOT ILIKE ?)",
|
||||
Args: []any{"%IIT%", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
},
|
||||
},
|
||||
@@ -514,7 +514,7 @@ func TestJSONStmtBuilder_ArrayPaths(t *testing.T) {
|
||||
name: "Key inside Array(JSON) contains String value",
|
||||
filter: "body.education[].name Contains 'IIT'",
|
||||
expected: TestExpected{
|
||||
WhereClause: "((arrayExists(`body_v2.education`-> LOWER(dynamicElement(`body_v2.education`.`name`, 'String')) LIKE LOWER(?), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education'))",
|
||||
WhereClause: "((arrayExists(`body_v2.education`-> dynamicElement(`body_v2.education`.`name`, 'String') ILIKE ?, dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education'))",
|
||||
Args: []any{"%IIT%", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
},
|
||||
},
|
||||
@@ -522,7 +522,7 @@ func TestJSONStmtBuilder_ArrayPaths(t *testing.T) {
|
||||
name: "Int in array Contains value",
|
||||
filter: "body.education[].year Contains 2020",
|
||||
expected: TestExpected{
|
||||
WhereClause: "((arrayExists(`body_v2.education`-> LOWER(toString(dynamicElement(`body_v2.education`.`year`, 'Int64'))) LIKE LOWER(?), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education'))",
|
||||
WhereClause: "((arrayExists(`body_v2.education`-> toString(dynamicElement(`body_v2.education`.`year`, 'Int64')) ILIKE ?, dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education'))",
|
||||
Args: []any{"%2020%", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
},
|
||||
},
|
||||
@@ -547,7 +547,7 @@ func TestJSONStmtBuilder_ArrayPaths(t *testing.T) {
|
||||
name: "Array simple path NotContains",
|
||||
filter: "body.education[].name NOT CONTAINS 'IIT'",
|
||||
expected: TestExpected{
|
||||
WhereClause: "(NOT arrayExists(`body_v2.education`-> LOWER(dynamicElement(`body_v2.education`.`name`, 'String')) LIKE LOWER(?), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))')))",
|
||||
WhereClause: "(NOT arrayExists(`body_v2.education`-> dynamicElement(`body_v2.education`.`name`, 'String') ILIKE ?, dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))')))",
|
||||
Args: []any{"%IIT%", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
},
|
||||
},
|
||||
@@ -557,7 +557,7 @@ func TestJSONStmtBuilder_ArrayPaths(t *testing.T) {
|
||||
name: "Key inside Array(JSON) contains Float value",
|
||||
filter: "body.education[].parameters Contains 1.65",
|
||||
expected: TestExpected{
|
||||
WhereClause: "(((arrayExists(`body_v2.education`-> (arrayExists(x -> LOWER(toString(x)) LIKE LOWER(?), dynamicElement(`body_v2.education`.`parameters`, 'Array(Nullable(Float64))')) OR arrayExists(x -> toFloat64(x) = ?, dynamicElement(`body_v2.education`.`parameters`, 'Array(Nullable(Float64))'))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education')) OR ((arrayExists(`body_v2.education`-> (arrayExists(x -> LOWER(toString(x)) LIKE LOWER(?), arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.education`.`parameters`, 'Array(Dynamic)'))) OR arrayExists(x -> accurateCastOrNull(x, 'Float64') = ?, arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.education`.`parameters`, 'Array(Dynamic)')))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education')))",
|
||||
WhereClause: "(((arrayExists(`body_v2.education`-> (arrayExists(x -> toString(x) ILIKE ?, dynamicElement(`body_v2.education`.`parameters`, 'Array(Nullable(Float64))')) OR arrayExists(x -> toFloat64(x) = ?, dynamicElement(`body_v2.education`.`parameters`, 'Array(Nullable(Float64))'))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education')) OR ((arrayExists(`body_v2.education`-> (arrayExists(x -> toString(x) ILIKE ?, arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.education`.`parameters`, 'Array(Dynamic)'))) OR arrayExists(x -> accurateCastOrNull(x, 'Float64') = ?, arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.education`.`parameters`, 'Array(Dynamic)')))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education')))",
|
||||
Args: []any{"%1.65%", 1.65, "%1.65%", 1.65, "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
Warnings: []string{"Key `education[].parameters` is ambiguous, found 2 different combinations of field context / data type: [name=education[].parameters,context=body,datatype=[]float64 name=education[].parameters,context=body,datatype=[]dynamic]."},
|
||||
},
|
||||
@@ -575,7 +575,7 @@ func TestJSONStmtBuilder_ArrayPaths(t *testing.T) {
|
||||
name: "Dynamic array contains String",
|
||||
filter: "body.education[].parameters Contains 'passed'",
|
||||
expected: TestExpected{
|
||||
WhereClause: "(((arrayExists(`body_v2.education`-> (arrayExists(x -> LOWER(toString(x)) LIKE LOWER(?), dynamicElement(`body_v2.education`.`parameters`, 'Array(Nullable(Float64))')) OR arrayExists(x -> toString(x) = ?, dynamicElement(`body_v2.education`.`parameters`, 'Array(Nullable(Float64))'))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education')) OR ((arrayExists(`body_v2.education`-> (arrayExists(x -> LOWER(toString(x)) LIKE LOWER(?), arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.education`.`parameters`, 'Array(Dynamic)'))) OR arrayExists(x -> toString(x) = ?, arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.education`.`parameters`, 'Array(Dynamic)')))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education')))",
|
||||
WhereClause: "(((arrayExists(`body_v2.education`-> (arrayExists(x -> toString(x) ILIKE ?, dynamicElement(`body_v2.education`.`parameters`, 'Array(Nullable(Float64))')) OR arrayExists(x -> toString(x) = ?, dynamicElement(`body_v2.education`.`parameters`, 'Array(Nullable(Float64))'))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education')) OR ((arrayExists(`body_v2.education`-> (arrayExists(x -> toString(x) ILIKE ?, arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.education`.`parameters`, 'Array(Dynamic)'))) OR arrayExists(x -> toString(x) = ?, arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.education`.`parameters`, 'Array(Dynamic)')))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education')))",
|
||||
Args: []any{"%passed%", "passed", "%passed%", "passed", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
Warnings: []string{"Key `education[].parameters` is ambiguous, found 2 different combinations of field context / data type: [name=education[].parameters,context=body,datatype=[]float64 name=education[].parameters,context=body,datatype=[]dynamic]."},
|
||||
},
|
||||
@@ -593,7 +593,7 @@ func TestJSONStmtBuilder_ArrayPaths(t *testing.T) {
|
||||
name: "Terminal array NotContains float",
|
||||
filter: "body.education[].parameters NOT CONTAINS 1.65",
|
||||
expected: TestExpected{
|
||||
WhereClause: "((NOT arrayExists(`body_v2.education`-> (arrayExists(x -> LOWER(toString(x)) LIKE LOWER(?), dynamicElement(`body_v2.education`.`parameters`, 'Array(Nullable(Float64))')) OR arrayExists(x -> toFloat64(x) = ?, dynamicElement(`body_v2.education`.`parameters`, 'Array(Nullable(Float64))'))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND (NOT arrayExists(`body_v2.education`-> (arrayExists(x -> LOWER(toString(x)) LIKE LOWER(?), arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.education`.`parameters`, 'Array(Dynamic)'))) OR arrayExists(x -> accurateCastOrNull(x, 'Float64') = ?, arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.education`.`parameters`, 'Array(Dynamic)')))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))))",
|
||||
WhereClause: "((NOT arrayExists(`body_v2.education`-> (arrayExists(x -> toString(x) ILIKE ?, dynamicElement(`body_v2.education`.`parameters`, 'Array(Nullable(Float64))')) OR arrayExists(x -> toFloat64(x) = ?, dynamicElement(`body_v2.education`.`parameters`, 'Array(Nullable(Float64))'))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND (NOT arrayExists(`body_v2.education`-> (arrayExists(x -> toString(x) ILIKE ?, arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.education`.`parameters`, 'Array(Dynamic)'))) OR arrayExists(x -> accurateCastOrNull(x, 'Float64') = ?, arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.education`.`parameters`, 'Array(Dynamic)')))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))))",
|
||||
Args: []any{"%1.65%", float64(1.65), "%1.65%", float64(1.65), "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
Warnings: []string{"Key `education[].parameters` is ambiguous, found 2 different combinations of field context / data type: [name=education[].parameters,context=body,datatype=[]float64 name=education[].parameters,context=body,datatype=[]dynamic]."},
|
||||
},
|
||||
@@ -683,7 +683,7 @@ func TestJSONStmtBuilder_ArrayPaths(t *testing.T) {
|
||||
name: "Super nested array contains Int64 value",
|
||||
filter: "body.interests[].entities[].reviews[].entries[].metadata[].positions[].ratings Contains 4",
|
||||
expected: TestExpected{
|
||||
WhereClause: "(((arrayExists(`body_v2.interests`-> arrayExists(`body_v2.interests[].entities`-> arrayExists(`body_v2.interests[].entities[].reviews`-> arrayExists(`body_v2.interests[].entities[].reviews[].entries`-> arrayExists(`body_v2.interests[].entities[].reviews[].entries[].metadata`-> arrayExists(`body_v2.interests[].entities[].reviews[].entries[].metadata[].positions`-> (arrayExists(x -> LOWER(toString(x)) LIKE LOWER(?), dynamicElement(`body_v2.interests[].entities[].reviews[].entries[].metadata[].positions`.`ratings`, 'Array(Nullable(Int64))')) OR arrayExists(x -> toFloat64(x) = ?, dynamicElement(`body_v2.interests[].entities[].reviews[].entries[].metadata[].positions`.`ratings`, 'Array(Nullable(Int64))'))), dynamicElement(`body_v2.interests[].entities[].reviews[].entries[].metadata`.`positions`, 'Array(JSON(max_dynamic_types=0, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests[].entities[].reviews[].entries`.`metadata`, 'Array(JSON(max_dynamic_types=1, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests[].entities[].reviews`.`entries`, 'Array(JSON(max_dynamic_types=2, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests[].entities`.`reviews`, 'Array(JSON(max_dynamic_types=4, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests`.`entities`, 'Array(JSON(max_dynamic_types=8, max_dynamic_paths=0))')), dynamicElement(body_v2.`interests`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'interests')) OR ((arrayExists(`body_v2.interests`-> arrayExists(`body_v2.interests[].entities`-> arrayExists(`body_v2.interests[].entities[].reviews`-> arrayExists(`body_v2.interests[].entities[].reviews[].entries`-> arrayExists(`body_v2.interests[].entities[].reviews[].entries[].metadata`-> arrayExists(`body_v2.interests[].entities[].reviews[].entries[].metadata[].positions`-> (arrayExists(x -> LOWER(x) LIKE LOWER(?), dynamicElement(`body_v2.interests[].entities[].reviews[].entries[].metadata[].positions`.`ratings`, 'Array(Nullable(String))')) OR arrayExists(x -> toFloat64OrNull(x) = ?, dynamicElement(`body_v2.interests[].entities[].reviews[].entries[].metadata[].positions`.`ratings`, 'Array(Nullable(String))'))), dynamicElement(`body_v2.interests[].entities[].reviews[].entries[].metadata`.`positions`, 'Array(JSON(max_dynamic_types=0, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests[].entities[].reviews[].entries`.`metadata`, 'Array(JSON(max_dynamic_types=1, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests[].entities[].reviews`.`entries`, 'Array(JSON(max_dynamic_types=2, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests[].entities`.`reviews`, 'Array(JSON(max_dynamic_types=4, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests`.`entities`, 'Array(JSON(max_dynamic_types=8, max_dynamic_paths=0))')), dynamicElement(body_v2.`interests`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'interests')))",
|
||||
WhereClause: "(((arrayExists(`body_v2.interests`-> arrayExists(`body_v2.interests[].entities`-> arrayExists(`body_v2.interests[].entities[].reviews`-> arrayExists(`body_v2.interests[].entities[].reviews[].entries`-> arrayExists(`body_v2.interests[].entities[].reviews[].entries[].metadata`-> arrayExists(`body_v2.interests[].entities[].reviews[].entries[].metadata[].positions`-> (arrayExists(x -> toString(x) ILIKE ?, dynamicElement(`body_v2.interests[].entities[].reviews[].entries[].metadata[].positions`.`ratings`, 'Array(Nullable(Int64))')) OR arrayExists(x -> toFloat64(x) = ?, dynamicElement(`body_v2.interests[].entities[].reviews[].entries[].metadata[].positions`.`ratings`, 'Array(Nullable(Int64))'))), dynamicElement(`body_v2.interests[].entities[].reviews[].entries[].metadata`.`positions`, 'Array(JSON(max_dynamic_types=0, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests[].entities[].reviews[].entries`.`metadata`, 'Array(JSON(max_dynamic_types=1, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests[].entities[].reviews`.`entries`, 'Array(JSON(max_dynamic_types=2, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests[].entities`.`reviews`, 'Array(JSON(max_dynamic_types=4, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests`.`entities`, 'Array(JSON(max_dynamic_types=8, max_dynamic_paths=0))')), dynamicElement(body_v2.`interests`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'interests')) OR ((arrayExists(`body_v2.interests`-> arrayExists(`body_v2.interests[].entities`-> arrayExists(`body_v2.interests[].entities[].reviews`-> arrayExists(`body_v2.interests[].entities[].reviews[].entries`-> arrayExists(`body_v2.interests[].entities[].reviews[].entries[].metadata`-> arrayExists(`body_v2.interests[].entities[].reviews[].entries[].metadata[].positions`-> (arrayExists(x -> x ILIKE ?, dynamicElement(`body_v2.interests[].entities[].reviews[].entries[].metadata[].positions`.`ratings`, 'Array(Nullable(String))')) OR arrayExists(x -> toFloat64OrNull(x) = ?, dynamicElement(`body_v2.interests[].entities[].reviews[].entries[].metadata[].positions`.`ratings`, 'Array(Nullable(String))'))), dynamicElement(`body_v2.interests[].entities[].reviews[].entries[].metadata`.`positions`, 'Array(JSON(max_dynamic_types=0, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests[].entities[].reviews[].entries`.`metadata`, 'Array(JSON(max_dynamic_types=1, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests[].entities[].reviews`.`entries`, 'Array(JSON(max_dynamic_types=2, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests[].entities`.`reviews`, 'Array(JSON(max_dynamic_types=4, max_dynamic_paths=0))')), dynamicElement(`body_v2.interests`.`entities`, 'Array(JSON(max_dynamic_types=8, max_dynamic_paths=0))')), dynamicElement(body_v2.`interests`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'interests')))",
|
||||
Args: []any{"%4%", float64(4), "%4%", float64(4), "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
Warnings: []string{"Key `interests[].entities[].reviews[].entries[].metadata[].positions[].ratings` is ambiguous, found 2 different combinations of field context / data type: [name=interests[].entities[].reviews[].entries[].metadata[].positions[].ratings,context=body,datatype=[]int64 name=interests[].entities[].reviews[].entries[].metadata[].positions[].ratings,context=body,datatype=[]string]."},
|
||||
},
|
||||
@@ -692,7 +692,7 @@ func TestJSONStmtBuilder_ArrayPaths(t *testing.T) {
|
||||
name: "Multi nested Array(Dynamic) + Array(JSON) both can contain a value",
|
||||
filter: "body.education[].awards[].participated[].team[].branch Contains 'Civil'",
|
||||
expected: TestExpected{
|
||||
WhereClause: "((arrayExists(`body_v2.education`-> (arrayExists(`body_v2.education[].awards`-> (arrayExists(`body_v2.education[].awards[].participated`-> arrayExists(`body_v2.education[].awards[].participated[].team`-> LOWER(dynamicElement(`body_v2.education[].awards[].participated[].team`.`branch`, 'String')) LIKE LOWER(?), dynamicElement(`body_v2.education[].awards[].participated`.`team`, 'Array(JSON(max_dynamic_types=2, max_dynamic_paths=0))')), dynamicElement(`body_v2.education[].awards`.`participated`, 'Array(JSON(max_dynamic_types=4, max_dynamic_paths=0))')) OR arrayExists(`body_v2.education[].awards[].participated`-> arrayExists(`body_v2.education[].awards[].participated[].team`-> LOWER(dynamicElement(`body_v2.education[].awards[].participated[].team`.`branch`, 'String')) LIKE LOWER(?), dynamicElement(`body_v2.education[].awards[].participated`.`team`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=256))')), arrayMap(x->dynamicElement(x, 'JSON'), arrayFilter(x->(dynamicType(x) = 'JSON'), dynamicElement(`body_v2.education[].awards`.`participated`, 'Array(Dynamic)'))))), dynamicElement(`body_v2.education`.`awards`, 'Array(JSON(max_dynamic_types=8, max_dynamic_paths=0))')) OR arrayExists(`body_v2.education[].awards`-> (arrayExists(`body_v2.education[].awards[].participated`-> arrayExists(`body_v2.education[].awards[].participated[].team`-> LOWER(dynamicElement(`body_v2.education[].awards[].participated[].team`.`branch`, 'String')) LIKE LOWER(?), dynamicElement(`body_v2.education[].awards[].participated`.`team`, 'Array(JSON(max_dynamic_types=8, max_dynamic_paths=64))')), dynamicElement(`body_v2.education[].awards`.`participated`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=256))')) OR arrayExists(`body_v2.education[].awards[].participated`-> arrayExists(`body_v2.education[].awards[].participated[].team`-> LOWER(dynamicElement(`body_v2.education[].awards[].participated[].team`.`branch`, 'String')) LIKE LOWER(?), dynamicElement(`body_v2.education[].awards[].participated`.`team`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=256))')), arrayMap(x->dynamicElement(x, 'JSON'), arrayFilter(x->(dynamicType(x) = 'JSON'), dynamicElement(`body_v2.education[].awards`.`participated`, 'Array(Dynamic)'))))), arrayMap(x->dynamicElement(x, 'JSON'), arrayFilter(x->(dynamicType(x) = 'JSON'), dynamicElement(`body_v2.education`.`awards`, 'Array(Dynamic)'))))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education'))",
|
||||
WhereClause: "((arrayExists(`body_v2.education`-> (arrayExists(`body_v2.education[].awards`-> (arrayExists(`body_v2.education[].awards[].participated`-> arrayExists(`body_v2.education[].awards[].participated[].team`-> dynamicElement(`body_v2.education[].awards[].participated[].team`.`branch`, 'String') ILIKE ?, dynamicElement(`body_v2.education[].awards[].participated`.`team`, 'Array(JSON(max_dynamic_types=2, max_dynamic_paths=0))')), dynamicElement(`body_v2.education[].awards`.`participated`, 'Array(JSON(max_dynamic_types=4, max_dynamic_paths=0))')) OR arrayExists(`body_v2.education[].awards[].participated`-> arrayExists(`body_v2.education[].awards[].participated[].team`-> dynamicElement(`body_v2.education[].awards[].participated[].team`.`branch`, 'String') ILIKE ?, dynamicElement(`body_v2.education[].awards[].participated`.`team`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=256))')), arrayMap(x->dynamicElement(x, 'JSON'), arrayFilter(x->(dynamicType(x) = 'JSON'), dynamicElement(`body_v2.education[].awards`.`participated`, 'Array(Dynamic)'))))), dynamicElement(`body_v2.education`.`awards`, 'Array(JSON(max_dynamic_types=8, max_dynamic_paths=0))')) OR arrayExists(`body_v2.education[].awards`-> (arrayExists(`body_v2.education[].awards[].participated`-> arrayExists(`body_v2.education[].awards[].participated[].team`-> dynamicElement(`body_v2.education[].awards[].participated[].team`.`branch`, 'String') ILIKE ?, dynamicElement(`body_v2.education[].awards[].participated`.`team`, 'Array(JSON(max_dynamic_types=8, max_dynamic_paths=64))')), dynamicElement(`body_v2.education[].awards`.`participated`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=256))')) OR arrayExists(`body_v2.education[].awards[].participated`-> arrayExists(`body_v2.education[].awards[].participated[].team`-> dynamicElement(`body_v2.education[].awards[].participated[].team`.`branch`, 'String') ILIKE ?, dynamicElement(`body_v2.education[].awards[].participated`.`team`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=256))')), arrayMap(x->dynamicElement(x, 'JSON'), arrayFilter(x->(dynamicType(x) = 'JSON'), dynamicElement(`body_v2.education[].awards`.`participated`, 'Array(Dynamic)'))))), arrayMap(x->dynamicElement(x, 'JSON'), arrayFilter(x->(dynamicType(x) = 'JSON'), dynamicElement(`body_v2.education`.`awards`, 'Array(Dynamic)'))))), dynamicElement(body_v2.`education`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'education'))",
|
||||
Args: []any{"%Civil%", "%Civil%", "%Civil%", "%Civil%", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
},
|
||||
},
|
||||
@@ -747,7 +747,7 @@ func TestJSONStmtBuilder_ArrayPaths(t *testing.T) {
|
||||
name: "dynamic_array_element_compare_CONTAINS",
|
||||
filter: "interests[].entities[].product_codes Contains 1",
|
||||
expected: TestExpected{
|
||||
WhereClause: "((arrayExists(`body_v2.interests`-> arrayExists(`body_v2.interests[].entities`-> (arrayExists(x -> LOWER(toString(x)) LIKE LOWER(?), arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.interests[].entities`.`product_codes`, 'Array(Dynamic)'))) OR arrayExists(x -> accurateCastOrNull(x, 'Float64') = ?, arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.interests[].entities`.`product_codes`, 'Array(Dynamic)')))), dynamicElement(`body_v2.interests`.`entities`, 'Array(JSON(max_dynamic_types=8, max_dynamic_paths=0))')), dynamicElement(body_v2.`interests`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'interests'))",
|
||||
WhereClause: "((arrayExists(`body_v2.interests`-> arrayExists(`body_v2.interests[].entities`-> (arrayExists(x -> toString(x) ILIKE ?, arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.interests[].entities`.`product_codes`, 'Array(Dynamic)'))) OR arrayExists(x -> accurateCastOrNull(x, 'Float64') = ?, arrayFilter(x->(dynamicType(x) IN ('String', 'Int64', 'Float64', 'Bool')), dynamicElement(`body_v2.interests[].entities`.`product_codes`, 'Array(Dynamic)')))), dynamicElement(`body_v2.interests`.`entities`, 'Array(JSON(max_dynamic_types=8, max_dynamic_paths=0))')), dynamicElement(body_v2.`interests`, 'Array(JSON(max_dynamic_types=16, max_dynamic_paths=0))'))) AND has(JSONAllPaths(body_v2), 'interests'))",
|
||||
Args: []any{"%1%", float64(1), "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/o11y/pkg/valuer"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
type logQueryStatementBuilder struct {
|
||||
|
||||
@@ -644,7 +644,7 @@ func TestStatementBuilderListQueryServiceCollision(t *testing.T) {
|
||||
Limit: 10,
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __resource_filter AS (SELECT fingerprint FROM o11y_logs.distributed_logs_v2_resource WHERE ((simpleJSONExtractString(labels, 'service.name') = ? AND labels LIKE ? AND labels LIKE ?)) AND seen_at_ts_bucket_start >= ? AND seen_at_ts_bucket_start <= ? GROUP BY fingerprint) SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, scope_name, scope_version, body, attributes_string, attributes_number, attributes_bool, resources_string, scope_string FROM o11y_logs.distributed_logs_v2 WHERE resource_fingerprint GLOBAL IN (SELECT fingerprint FROM __resource_filter) AND (LOWER(body) LIKE LOWER(?)) AND timestamp >= ? AND ts_bucket_start >= ? AND timestamp < ? AND ts_bucket_start <= ? LIMIT ?",
|
||||
Query: "WITH __resource_filter AS (SELECT fingerprint FROM o11y_logs.distributed_logs_v2_resource WHERE ((simpleJSONExtractString(labels, 'service.name') = ? AND labels LIKE ? AND labels LIKE ?)) AND seen_at_ts_bucket_start >= ? AND seen_at_ts_bucket_start <= ? GROUP BY fingerprint) SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, scope_name, scope_version, body, attributes_string, attributes_number, attributes_bool, resources_string, scope_string FROM o11y_logs.distributed_logs_v2 WHERE resource_fingerprint GLOBAL IN (SELECT fingerprint FROM __resource_filter) AND (body ILIKE ?) AND timestamp >= ? AND ts_bucket_start >= ? AND timestamp < ? AND ts_bucket_start <= ? LIMIT ?",
|
||||
Args: []any{"cartservice", "%service.name%", "%service.name\":\"cartservice%", uint64(1747945619), uint64(1747983448), "%error%", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -673,7 +673,7 @@ func TestStatementBuilderListQueryServiceCollision(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __resource_filter AS (SELECT fingerprint FROM o11y_logs.distributed_logs_v2_resource WHERE (simpleJSONExtractString(labels, 'service.name') = ? AND labels LIKE ? AND labels LIKE ?) AND seen_at_ts_bucket_start >= ? AND seen_at_ts_bucket_start <= ? GROUP BY fingerprint) SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, scope_name, scope_version, body, attributes_string, attributes_number, attributes_bool, resources_string, scope_string FROM o11y_logs.distributed_logs_v2 WHERE resource_fingerprint GLOBAL IN (SELECT fingerprint FROM __resource_filter) AND LOWER(body) LIKE LOWER(?) AND timestamp >= ? AND ts_bucket_start >= ? AND timestamp < ? AND ts_bucket_start <= ? ORDER BY `attribute_string_materialized$$key$$name` AS `materialized.key.name` desc LIMIT ?",
|
||||
Query: "WITH __resource_filter AS (SELECT fingerprint FROM o11y_logs.distributed_logs_v2_resource WHERE (simpleJSONExtractString(labels, 'service.name') = ? AND labels LIKE ? AND labels LIKE ?) AND seen_at_ts_bucket_start >= ? AND seen_at_ts_bucket_start <= ? GROUP BY fingerprint) SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, scope_name, scope_version, body, attributes_string, attributes_number, attributes_bool, resources_string, scope_string FROM o11y_logs.distributed_logs_v2 WHERE resource_fingerprint GLOBAL IN (SELECT fingerprint FROM __resource_filter) AND body ILIKE ? AND timestamp >= ? AND ts_bucket_start >= ? AND timestamp < ? AND ts_bucket_start <= ? ORDER BY `attribute_string_materialized$$key$$name` AS `materialized.key.name` desc LIMIT ?",
|
||||
Args: []any{"cartservice", "%service.name%", "%service.name\":\"cartservice%", uint64(1747945619), uint64(1747983448), "%error%", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -1030,7 +1030,7 @@ func TestStmtBuilderBodyField(t *testing.T) {
|
||||
},
|
||||
enableUseJSONBody: true,
|
||||
expected: qbtypes.Statement{
|
||||
Query: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, scope_name, scope_version, body_v2 as body, attributes_string, attributes_number, attributes_bool, resources_string, scope_string FROM o11y_logs.distributed_logs_v2 WHERE LOWER(body_v2.message) LIKE LOWER(?) AND timestamp >= ? AND ts_bucket_start >= ? AND timestamp < ? AND ts_bucket_start <= ? LIMIT ?",
|
||||
Query: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, scope_name, scope_version, body_v2 as body, attributes_string, attributes_number, attributes_bool, resources_string, scope_string FROM o11y_logs.distributed_logs_v2 WHERE body_v2.message ILIKE ? AND timestamp >= ? AND ts_bucket_start >= ? AND timestamp < ? AND ts_bucket_start <= ? LIMIT ?",
|
||||
Args: []any{"%error%", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
Warnings: []string{bodySearchDefaultWarning},
|
||||
},
|
||||
@@ -1046,7 +1046,7 @@ func TestStmtBuilderBodyField(t *testing.T) {
|
||||
},
|
||||
enableUseJSONBody: false,
|
||||
expected: qbtypes.Statement{
|
||||
Query: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, scope_name, scope_version, body, attributes_string, attributes_number, attributes_bool, resources_string, scope_string FROM o11y_logs.distributed_logs_v2 WHERE LOWER(body) LIKE LOWER(?) AND timestamp >= ? AND ts_bucket_start >= ? AND timestamp < ? AND ts_bucket_start <= ? LIMIT ?",
|
||||
Query: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, scope_name, scope_version, body, attributes_string, attributes_number, attributes_bool, resources_string, scope_string FROM o11y_logs.distributed_logs_v2 WHERE body ILIKE ? AND timestamp >= ? AND ts_bucket_start >= ? AND timestamp < ? AND ts_bucket_start <= ? LIMIT ?",
|
||||
Args: []any{"%error%", "1747947419000000000", uint64(1747945619), "1747983448000000000", uint64(1747983448), 10},
|
||||
},
|
||||
expectedErr: nil,
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
schemamigrator "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
"github.com/hanzoai/otel-collector/constants"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -23,7 +23,7 @@ func TestBuildListLogsJSONIndexesQuery(t *testing.T) {
|
||||
cluster: "test-cluster",
|
||||
filters: nil,
|
||||
expectedSQL: "SELECT name, type_full, expr, granularity FROM clusterAllReplicas('test-cluster', system.data_skipping_indices) " +
|
||||
"WHERE database = ? AND table = ? AND (LOWER(expr) LIKE LOWER(?) OR LOWER(expr) LIKE LOWER(?))",
|
||||
"WHERE database = ? AND table = ? AND (expr ILIKE ? OR expr ILIKE ?)",
|
||||
expectedArgs: []any{
|
||||
telemetrylogs.DBName,
|
||||
telemetrylogs.LogsV2LocalTableName,
|
||||
@@ -36,7 +36,7 @@ func TestBuildListLogsJSONIndexesQuery(t *testing.T) {
|
||||
cluster: "test-cluster",
|
||||
filters: []string{"foo", "bar"},
|
||||
expectedSQL: "SELECT name, type_full, expr, granularity FROM clusterAllReplicas('test-cluster', system.data_skipping_indices) " +
|
||||
"WHERE database = ? AND table = ? AND (LOWER(expr) LIKE LOWER(?) OR LOWER(expr) LIKE LOWER(?)) AND (LOWER(replaceAll(expr, '`', '')) LIKE LOWER(?) OR LOWER(replaceAll(expr, '`', '')) LIKE LOWER(?))",
|
||||
"WHERE database = ? AND table = ? AND (expr ILIKE ? OR expr ILIKE ?) AND (replaceAll(expr, '`', '') ILIKE ? OR replaceAll(expr, '`', '') ILIKE ?)",
|
||||
expectedArgs: []any{
|
||||
telemetrylogs.DBName,
|
||||
telemetrylogs.LogsV2LocalTableName,
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
schema "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
type conditionBuilder struct {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -35,7 +35,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorILike,
|
||||
value: "%admin%",
|
||||
expectedSQL: "WHERE if(mapContains(attributes, ?), LOWER(attributes['user.id']) LIKE LOWER(?), true)",
|
||||
expectedSQL: "WHERE if(mapContains(attributes, ?), attributes['user.id'] ILIKE ?, true)",
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
@@ -47,7 +47,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorNotILike,
|
||||
value: "%admin%",
|
||||
expectedSQL: "WHERE if(mapContains(attributes, ?), LOWER(attributes['user.id']) NOT LIKE LOWER(?), true)",
|
||||
expectedSQL: "WHERE if(mapContains(attributes, ?), attributes['user.id'] NOT ILIKE ?, true)",
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
schema "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/hanzoai/o11y/pkg/datastoresql"
|
||||
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"github.com/hanzoai/o11y/pkg/errors"
|
||||
|
||||
@@ -3,7 +3,7 @@ package telemetrymetadata
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/hanzoai/datastore-sql-parser/parser"
|
||||
"github.com/hanzo-ds/sqlparser/parser"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/types/metrictypes"
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
type meterQueryStatementBuilder struct {
|
||||
|
||||
@@ -51,7 +51,7 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, `service.name`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(86400)) AS ts, JSONExtractString(labels, 'service.name') AS `service.name`, max(value) AS per_series_value FROM o11y_meter.distributed_samples AS points WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? AND JSONExtractString(labels, 'service.name') = ? AND LOWER(temporality) LIKE LOWER(?) GROUP BY fingerprint, ts, `service.name` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `service.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `service.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `service.name`, ts",
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, `service.name`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(86400)) AS ts, JSONExtractString(labels, 'service.name') AS `service.name`, max(value) AS per_series_value FROM o11y_meter.distributed_samples AS points WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? AND JSONExtractString(labels, 'service.name') = ? AND temporality ILIKE ? GROUP BY fingerprint, ts, `service.name` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `service.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `service.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `service.name`, ts",
|
||||
Args: []any{"o11y_calls_total", uint64(1747785600000), uint64(1747983420000), "cartservice", "cumulative", 0},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -84,7 +84,7 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __spatial_aggregation_cte AS (SELECT toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(86400)) AS ts, JSONExtractString(labels, 'service.name') AS `service.name`, sum(value)/86400 AS value FROM o11y_meter.distributed_samples AS points WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? AND JSONExtractString(labels, 'service.name') = ? AND LOWER(temporality) LIKE LOWER(?) GROUP BY ts, `service.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `service.name`, ts",
|
||||
Query: "WITH __spatial_aggregation_cte AS (SELECT toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(86400)) AS ts, JSONExtractString(labels, 'service.name') AS `service.name`, sum(value)/86400 AS value FROM o11y_meter.distributed_samples AS points WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? AND JSONExtractString(labels, 'service.name') = ? AND temporality ILIKE ? GROUP BY ts, `service.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `service.name`, ts",
|
||||
Args: []any{"o11y_calls_total", uint64(1747872000000), uint64(1747983420000), "cartservice", "delta"},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -117,7 +117,7 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(86400)) AS ts, JSONExtractString(labels, 'service.name') AS `service.name`, sum(value)/86400 AS per_series_value FROM o11y_meter.distributed_samples AS points WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? AND JSONExtractString(labels, 'service.name') = ? AND LOWER(temporality) LIKE LOWER(?) GROUP BY fingerprint, ts, `service.name` ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, `service.name`, avg(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `service.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `service.name`, ts",
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(86400)) AS ts, JSONExtractString(labels, 'service.name') AS `service.name`, sum(value)/86400 AS per_series_value FROM o11y_meter.distributed_samples AS points WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? AND JSONExtractString(labels, 'service.name') = ? AND temporality ILIKE ? GROUP BY fingerprint, ts, `service.name` ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, `service.name`, avg(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `service.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `service.name`, ts",
|
||||
Args: []any{"o11y_calls_total", uint64(1747872000000), uint64(1747983420000), "cartservice", "delta", 0},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -150,7 +150,7 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(86400)) AS ts, JSONExtractString(labels, 'host.name') AS `host.name`, avg(value) AS per_series_value FROM o11y_meter.distributed_samples AS points WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? AND JSONExtractString(labels, 'host.name') = ? AND LOWER(temporality) LIKE LOWER(?) GROUP BY fingerprint, ts, `host.name` ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, `host.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `host.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `host.name`, ts",
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(86400)) AS ts, JSONExtractString(labels, 'host.name') AS `host.name`, avg(value) AS per_series_value FROM o11y_meter.distributed_samples AS points WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? AND JSONExtractString(labels, 'host.name') = ? AND temporality ILIKE ? GROUP BY fingerprint, ts, `host.name` ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, `host.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `host.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `host.name`, ts",
|
||||
Args: []any{"system.memory.usage", uint64(1747872000000), uint64(1747983420000), "big-data-node-1", "unspecified", 0},
|
||||
},
|
||||
expectedErr: nil,
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
type conditionBuilder struct {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -82,7 +82,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorILike,
|
||||
value: "%admin%",
|
||||
expectedSQL: "LOWER(JSONExtractString(labels, 'user.id')) LIKE LOWER(?)",
|
||||
expectedSQL: "JSONExtractString(labels, 'user.id') ILIKE ?",
|
||||
expectedArgs: []any{"%admin%"},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -95,7 +95,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorNotILike,
|
||||
value: "%admin%",
|
||||
expectedSQL: "LOWER(JSONExtractString(labels, 'user.id')) NOT LIKE LOWER(?)",
|
||||
expectedSQL: "JSONExtractString(labels, 'user.id') NOT ILIKE ?",
|
||||
expectedArgs: []any{"%admin%"},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -108,7 +108,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorContains,
|
||||
value: "admin",
|
||||
expectedSQL: "LOWER(JSONExtractString(labels, 'user.id')) LIKE LOWER(?)",
|
||||
expectedSQL: "JSONExtractString(labels, 'user.id') ILIKE ?",
|
||||
expectedArgs: []any{"%admin%"},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -144,7 +144,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorContains,
|
||||
value: 521509198310,
|
||||
expectedSQL: "LOWER(JSONExtractString(labels, 'user.id')) LIKE LOWER(?)",
|
||||
expectedSQL: "JSONExtractString(labels, 'user.id') ILIKE ?",
|
||||
expectedArgs: []any{"%521509198310%"},
|
||||
expectedError: nil,
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
schema "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestReducedStatementBuilder(t *testing.T) {
|
||||
name: "gauge_sum_latest",
|
||||
query: reducedQuery("test.metric", metrictypes.GaugeType, metrictypes.Unspecified, metrictypes.TimeAggregationLatest, metrictypes.SpaceAggregationSum),
|
||||
expected: qbtypes.Statement{
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, anyLast(last) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, argMax(value, unix_milli) AS per_series_value FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`sum_last`, computed_at) AS value FROM o11y_metrics.distributed_samples_v4_reduced_last_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, anyLast(last) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, argMax(value, unix_milli) AS per_series_value FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`sum_last`, computed_at) AS value FROM o11y_metrics.distributed_samples_v4_reduced_last_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Args: []any{"test.metric", uint64(1746921600000), uint64(1747172760000), "unspecified", false, "test.metric", uint64(1746999900000), uint64(1747172760000), 0, "test.metric", uint64(1746999900000), uint64(1747172760000), "test.metric", uint64(1746999900000), uint64(1747172760000), false},
|
||||
},
|
||||
},
|
||||
@@ -47,7 +47,7 @@ func TestReducedStatementBuilder(t *testing.T) {
|
||||
name: "gauge_avg_avg",
|
||||
query: reducedQuery("test.metric", metrictypes.GaugeType, metrictypes.Unspecified, metrictypes.TimeAggregationAvg, metrictypes.SpaceAggregationAvg),
|
||||
expected: qbtypes.Statement{
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, sum(sum) / sum(count) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, avg(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, avg(value) AS per_series_value, avg(weight) AS per_series_weight FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`sum_last`, computed_at) AS value, argMax(`count_series`, computed_at) AS weight FROM o11y_metrics.distributed_samples_v4_reduced_last_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) / sum(per_series_weight) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, sum(sum) / sum(count) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, avg(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, avg(value) AS per_series_value, avg(weight) AS per_series_weight FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`sum_last`, computed_at) AS value, argMax(`count_series`, computed_at) AS weight FROM o11y_metrics.distributed_samples_v4_reduced_last_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) / sum(per_series_weight) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Args: []any{"test.metric", uint64(1746921600000), uint64(1747172760000), "unspecified", false, "test.metric", uint64(1746999900000), uint64(1747172760000), 0, "test.metric", uint64(1746999900000), uint64(1747172760000), "test.metric", uint64(1746999900000), uint64(1747172760000), false},
|
||||
},
|
||||
},
|
||||
@@ -55,7 +55,7 @@ func TestReducedStatementBuilder(t *testing.T) {
|
||||
name: "gauge_min_min",
|
||||
query: reducedQuery("test.metric", metrictypes.GaugeType, metrictypes.Unspecified, metrictypes.TimeAggregationMin, metrictypes.SpaceAggregationMin),
|
||||
expected: qbtypes.Statement{
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, min(min) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, min(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, min(value) AS per_series_value FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`min`, computed_at) AS value FROM o11y_metrics.distributed_samples_v4_reduced_last_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, min(per_series_value) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, min(min) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, min(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, min(value) AS per_series_value FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`min`, computed_at) AS value FROM o11y_metrics.distributed_samples_v4_reduced_last_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, min(per_series_value) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Args: []any{"test.metric", uint64(1746921600000), uint64(1747172760000), "unspecified", false, "test.metric", uint64(1746999900000), uint64(1747172760000), 0, "test.metric", uint64(1746999900000), uint64(1747172760000), "test.metric", uint64(1746999900000), uint64(1747172760000), false},
|
||||
},
|
||||
},
|
||||
@@ -63,7 +63,7 @@ func TestReducedStatementBuilder(t *testing.T) {
|
||||
name: "gauge_max_max",
|
||||
query: reducedQuery("test.metric", metrictypes.GaugeType, metrictypes.Unspecified, metrictypes.TimeAggregationMax, metrictypes.SpaceAggregationMax),
|
||||
expected: qbtypes.Statement{
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, max(max) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, max(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, max(value) AS per_series_value FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`max`, computed_at) AS value FROM o11y_metrics.distributed_samples_v4_reduced_last_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, max(per_series_value) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, max(max) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, max(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, max(value) AS per_series_value FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`max`, computed_at) AS value FROM o11y_metrics.distributed_samples_v4_reduced_last_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, max(per_series_value) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Args: []any{"test.metric", uint64(1746921600000), uint64(1747172760000), "unspecified", false, "test.metric", uint64(1746999900000), uint64(1747172760000), 0, "test.metric", uint64(1746999900000), uint64(1747172760000), "test.metric", uint64(1746999900000), uint64(1747172760000), false},
|
||||
},
|
||||
},
|
||||
@@ -71,7 +71,7 @@ func TestReducedStatementBuilder(t *testing.T) {
|
||||
name: "counter_sum_rate",
|
||||
query: reducedQuery("test.metric.sum", metrictypes.SumType, metrictypes.Cumulative, metrictypes.TimeAggregationRate, metrictypes.SpaceAggregationSum),
|
||||
expected: qbtypes.Statement{
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT ts, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, max(max) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, sum(value) / 300 AS per_series_value FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`sum`, computed_at) AS value FROM o11y_metrics.distributed_samples_v4_reduced_sum_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT ts, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, max(max) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, sum(value) / 300 AS per_series_value FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`sum`, computed_at) AS value FROM o11y_metrics.distributed_samples_v4_reduced_sum_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Args: []any{"test.metric.sum", uint64(1746921600000), uint64(1747172760000), "cumulative", false, "test.metric.sum", uint64(1746999600000), uint64(1747172760000), 0, "test.metric.sum", uint64(1746999600000), uint64(1747172760000), "test.metric.sum", uint64(1746999600000), uint64(1747172760000), false},
|
||||
},
|
||||
},
|
||||
@@ -79,7 +79,7 @@ func TestReducedStatementBuilder(t *testing.T) {
|
||||
name: "counter_avg_increase",
|
||||
query: reducedQuery("test.metric", metrictypes.SumType, metrictypes.Cumulative, metrictypes.TimeAggregationIncrease, metrictypes.SpaceAggregationAvg),
|
||||
expected: qbtypes.Statement{
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT ts, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value, per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, max(max) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, avg(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, sum(value) AS per_series_value, avg(weight) AS per_series_weight FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`sum`, computed_at) AS value, argMax(`count_series`, computed_at) AS weight FROM o11y_metrics.distributed_samples_v4_reduced_sum_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) / sum(per_series_weight) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT ts, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value, per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, max(max) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, avg(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, sum(value) AS per_series_value, avg(weight) AS per_series_weight FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`sum`, computed_at) AS value, argMax(`count_series`, computed_at) AS weight FROM o11y_metrics.distributed_samples_v4_reduced_sum_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) / sum(per_series_weight) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Args: []any{"test.metric", uint64(1746921600000), uint64(1747172760000), "cumulative", false, "test.metric", uint64(1746999600000), uint64(1747172760000), 0, "test.metric", uint64(1746999600000), uint64(1747172760000), "test.metric", uint64(1746999600000), uint64(1747172760000), false},
|
||||
},
|
||||
},
|
||||
@@ -87,7 +87,7 @@ func TestReducedStatementBuilder(t *testing.T) {
|
||||
name: "counter_min_omitted",
|
||||
query: reducedQuery("test.metric", metrictypes.SumType, metrictypes.Cumulative, metrictypes.TimeAggregationRate, metrictypes.SpaceAggregationMin),
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, max(max) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, min(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts",
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, max(max) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, min(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts",
|
||||
Args: []any{"test.metric", uint64(1746921600000), uint64(1747172760000), "cumulative", false, "test.metric", uint64(1746999600000), uint64(1747172760000), 0},
|
||||
},
|
||||
},
|
||||
@@ -95,7 +95,7 @@ func TestReducedStatementBuilder(t *testing.T) {
|
||||
name: "counter_max_omitted",
|
||||
query: reducedQuery("test.metric", metrictypes.SumType, metrictypes.Cumulative, metrictypes.TimeAggregationRate, metrictypes.SpaceAggregationMax),
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, max(max) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, max(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts",
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, max(max) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, max(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts",
|
||||
Args: []any{"test.metric", uint64(1746921600000), uint64(1747172760000), "cumulative", false, "test.metric", uint64(1746999600000), uint64(1747172760000), 0},
|
||||
},
|
||||
},
|
||||
@@ -103,7 +103,7 @@ func TestReducedStatementBuilder(t *testing.T) {
|
||||
name: "histogram_p99",
|
||||
query: reducedQuery("test.metric.bucket", metrictypes.HistogramType, metrictypes.Cumulative, metrictypes.TimeAggregationUnspecified, metrictypes.SpaceAggregationPercentile99),
|
||||
expected: qbtypes.Statement{
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT ts, `le`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, `le`, max(max) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'le') AS `le` FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? GROUP BY fingerprint, `le`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `le` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `le`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `le`) SELECT ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.990) AS value FROM __spatial_aggregation_cte GROUP BY ts ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, `le`, sum(value) / 300 AS per_series_value FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`sum`, computed_at) AS value FROM o11y_metrics.distributed_samples_v4_reduced_sum_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'le') AS `le` FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint, `le`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts, `le`), __spatial_aggregation_cte AS (SELECT ts, `le`, sum(per_series_value) AS value FROM __temporal_aggregation_cte GROUP BY ts, `le`) SELECT ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.990) AS value FROM __spatial_aggregation_cte GROUP BY ts ORDER BY ts) ORDER BY ts",
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT ts, `le`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, `le`, max(max) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'le') AS `le` FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? GROUP BY fingerprint, `le`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `le` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `le`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `le`) SELECT ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.990) AS value FROM __spatial_aggregation_cte GROUP BY ts ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, `le`, sum(value) / 300 AS per_series_value FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`sum`, computed_at) AS value FROM o11y_metrics.distributed_samples_v4_reduced_sum_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'le') AS `le` FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint, `le`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts, `le`), __spatial_aggregation_cte AS (SELECT ts, `le`, sum(per_series_value) AS value FROM __temporal_aggregation_cte GROUP BY ts, `le`) SELECT ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.990) AS value FROM __spatial_aggregation_cte GROUP BY ts ORDER BY ts) ORDER BY ts",
|
||||
Args: []any{"test.metric.bucket", uint64(1746921600000), uint64(1747172760000), "cumulative", false, "test.metric.bucket", uint64(1746999900000), uint64(1747172760000), 0, "test.metric.bucket", uint64(1746999900000), uint64(1747172760000), "test.metric.bucket", uint64(1746999900000), uint64(1747172760000), false},
|
||||
},
|
||||
},
|
||||
@@ -111,7 +111,7 @@ func TestReducedStatementBuilder(t *testing.T) {
|
||||
name: "summary_avg",
|
||||
query: reducedQuery("test.metric", metrictypes.SummaryType, metrictypes.Unspecified, metrictypes.TimeAggregationAvg, metrictypes.SpaceAggregationAvg),
|
||||
expected: qbtypes.Statement{
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, sum(sum) / sum(count) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, avg(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, avg(value) AS per_series_value, avg(weight) AS per_series_weight FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`sum_last`, computed_at) AS value, argMax(`count_series`, computed_at) AS weight FROM o11y_metrics.distributed_samples_v4_reduced_last_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) / sum(per_series_weight) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Query: "SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, sum(sum) / sum(count) AS per_series_value FROM o11y_metrics.distributed_samples_v4_agg_5m AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_1day WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, avg(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) UNION ALL SELECT * FROM (WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(300)) AS ts, avg(value) AS per_series_value, avg(weight) AS per_series_weight FROM (SELECT reduced_fingerprint AS fingerprint, unix_milli, argMax(`sum_last`, computed_at) AS value, argMax(`count_series`, computed_at) AS weight FROM o11y_metrics.distributed_samples_v4_reduced_last_60s WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY reduced_fingerprint, unix_milli) AS points INNER JOIN (SELECT fingerprint FROM o11y_metrics.time_series_v4_reduced WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND __normalized = ? GROUP BY fingerprint) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint GROUP BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, sum(per_series_value) / sum(per_series_weight) AS value FROM __temporal_aggregation_cte GROUP BY ts) SELECT * FROM __spatial_aggregation_cte ORDER BY ts) ORDER BY ts",
|
||||
Args: []any{"test.metric", uint64(1746921600000), uint64(1747172760000), "unspecified", false, "test.metric", uint64(1746999900000), uint64(1747172760000), 0, "test.metric", uint64(1746999900000), uint64(1747172760000), "test.metric", uint64(1746999900000), uint64(1747172760000), false},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/types/metrictypes"
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, `service.name`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `service.name`, max(value) AS per_series_value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'service.name') AS `service.name` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? AND JSONExtractString(labels, 'service.name') = ? GROUP BY fingerprint, `service.name`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `service.name` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `service.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `service.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `service.name`, ts",
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, `service.name`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `service.name`, max(value) AS per_series_value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'service.name') AS `service.name` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? AND JSONExtractString(labels, 'service.name') = ? GROUP BY fingerprint, `service.name`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `service.name` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `service.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `service.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `service.name`, ts",
|
||||
Args: []any{"o11y_calls_total", uint64(1747936800000), uint64(1747983420000), "cumulative", false, "cartservice", "o11y_calls_total", uint64(1747947360000), uint64(1747983420000), 0},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -83,7 +83,7 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, `service.name`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `service.name`, max(value) AS per_series_value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'service.name') AS `service.name` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? AND (match(JSONExtractString(labels, 'materialized.key.name'), ?) OR JSONExtractString(labels, 'service.name') = ?) GROUP BY fingerprint, `service.name`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `service.name` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `service.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `service.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `service.name`, ts",
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, `service.name`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `service.name`, max(value) AS per_series_value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'service.name') AS `service.name` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? AND (match(JSONExtractString(labels, 'materialized.key.name'), ?) OR JSONExtractString(labels, 'service.name') = ?) GROUP BY fingerprint, `service.name`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `service.name` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `service.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `service.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `service.name`, ts",
|
||||
Args: []any{"o11y_calls_total", uint64(1747936800000), uint64(1747983420000), "cumulative", false, "cartservice", "cartservice", "o11y_calls_total", uint64(1747947360000), uint64(1747983420000), 0},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -116,7 +116,7 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __spatial_aggregation_cte AS (SELECT toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `service.name`, sum(value)/30 AS value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'service.name') AS `service.name` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? AND JSONExtractString(labels, 'service.name') = ? GROUP BY fingerprint, `service.name`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY ts, `service.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `service.name`, ts",
|
||||
Query: "WITH __spatial_aggregation_cte AS (SELECT toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `service.name`, sum(value)/30 AS value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'service.name') AS `service.name` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? AND JSONExtractString(labels, 'service.name') = ? GROUP BY fingerprint, `service.name`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY ts, `service.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `service.name`, ts",
|
||||
Args: []any{"o11y_calls_total", uint64(1747936800000), uint64(1747983420000), "delta", false, "cartservice", "o11y_calls_total", uint64(1747947390000), uint64(1747983420000)},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -149,7 +149,7 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __spatial_aggregation_cte AS (SELECT toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `service.name`, `le`, sum(value)/30 AS value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'service.name') AS `service.name`, JSONExtractString(labels, 'le') AS `le` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? AND JSONExtractString(labels, 'service.name') = ? GROUP BY fingerprint, `service.name`, `le`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY ts, `service.name`, `le`) SELECT ts, `service.name`, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.950) AS value FROM __spatial_aggregation_cte GROUP BY `service.name`, ts ORDER BY `service.name`, ts",
|
||||
Query: "WITH __spatial_aggregation_cte AS (SELECT toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `service.name`, `le`, sum(value)/30 AS value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'service.name') AS `service.name`, JSONExtractString(labels, 'le') AS `le` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? AND JSONExtractString(labels, 'service.name') = ? GROUP BY fingerprint, `service.name`, `le`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY ts, `service.name`, `le`) SELECT ts, `service.name`, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.950) AS value FROM __spatial_aggregation_cte GROUP BY `service.name`, ts ORDER BY `service.name`, ts",
|
||||
Args: []any{"o11y_latency", uint64(1747936800000), uint64(1747983420000), "delta", false, "cartservice", "o11y_latency", uint64(1747947390000), uint64(1747983420000)},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -182,7 +182,7 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `host.name`, avg(value) AS per_series_value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'host.name') AS `host.name` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? AND JSONExtractString(labels, 'host.name') = ? GROUP BY fingerprint, `host.name`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `host.name` ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, `host.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `host.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `host.name`, ts",
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `host.name`, avg(value) AS per_series_value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'host.name') AS `host.name` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? AND JSONExtractString(labels, 'host.name') = ? GROUP BY fingerprint, `host.name`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `host.name` ORDER BY fingerprint, ts), __spatial_aggregation_cte AS (SELECT ts, `host.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `host.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `host.name`, ts",
|
||||
Args: []any{"system.memory.usage", uint64(1747936800000), uint64(1747983420000), "unspecified", false, "big-data-node-1", "system.memory.usage", uint64(1747947390000), uint64(1747983420000), 0},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -212,7 +212,7 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, `service.name`, `le`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `service.name`, `le`, max(value) AS per_series_value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'service.name') AS `service.name`, JSONExtractString(labels, 'le') AS `le` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? GROUP BY fingerprint, `service.name`, `le`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `service.name`, `le` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `service.name`, `le`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `service.name`, `le`) SELECT ts, `service.name`, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.950) AS value FROM __spatial_aggregation_cte GROUP BY `service.name`, ts ORDER BY `service.name`, ts",
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, `service.name`, `le`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `service.name`, `le`, max(value) AS per_series_value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'service.name') AS `service.name`, JSONExtractString(labels, 'le') AS `le` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? GROUP BY fingerprint, `service.name`, `le`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `service.name`, `le` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `service.name`, `le`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `service.name`, `le`) SELECT ts, `service.name`, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.950) AS value FROM __spatial_aggregation_cte GROUP BY `service.name`, ts ORDER BY `service.name`, ts",
|
||||
Args: []any{"http_server_duration_bucket", uint64(1747936800000), uint64(1747983420000), "cumulative", false, "http_server_duration_bucket", uint64(1747947360000), uint64(1747983420000), 0},
|
||||
},
|
||||
expectedErr: nil,
|
||||
@@ -244,7 +244,7 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, `k8s.statefulset.name`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `k8s.statefulset.name`, max(value) AS per_series_value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'k8s.statefulset.name') AS `k8s.statefulset.name` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND __normalized = ? AND JSONExtractString(labels, 'k8s.statefulset.name') = ? GROUP BY fingerprint, `k8s.statefulset.name`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `k8s.statefulset.name` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `k8s.statefulset.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `k8s.statefulset.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `k8s.statefulset.name`, ts",
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, `k8s.statefulset.name`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `k8s.statefulset.name`, max(value) AS per_series_value FROM o11y_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'k8s.statefulset.name') AS `k8s.statefulset.name` FROM o11y_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND temporality ILIKE ? AND __normalized = ? AND JSONExtractString(labels, 'k8s.statefulset.name') = ? GROUP BY fingerprint, `k8s.statefulset.name`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `k8s.statefulset.name` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `k8s.statefulset.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `k8s.statefulset.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `k8s.statefulset.name`, ts",
|
||||
Args: []any{"o11y_calls_total", uint64(1747936800000), uint64(1747983420000), "cumulative", false, "my-statefulset", "o11y_calls_total", uint64(1747947360000), uint64(1747983420000), 0},
|
||||
},
|
||||
expectedErr: nil,
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/querybuilder"
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
type defaultConditionBuilder struct {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -54,7 +54,7 @@ func TestConditionBuilder(t *testing.T) {
|
||||
},
|
||||
op: qbtypes.FilterOperatorLike,
|
||||
value: "_mango%",
|
||||
expected: "LOWER(simpleJSONExtractString(labels, 'k8s.namespace.name')) LIKE LOWER(?) AND labels LIKE ? AND LOWER(labels) LIKE LOWER(?)",
|
||||
expected: "simpleJSONExtractString(labels, 'k8s.namespace.name') ILIKE ? AND labels LIKE ? AND labels ILIKE ?",
|
||||
expectedArgs: []any{"_mango%", "%k8s.namespace.name%", `%k8s.namespace.name%_mango%%`},
|
||||
},
|
||||
{
|
||||
@@ -65,7 +65,7 @@ func TestConditionBuilder(t *testing.T) {
|
||||
},
|
||||
op: qbtypes.FilterOperatorNotLike,
|
||||
value: "_mango%",
|
||||
expected: "LOWER(simpleJSONExtractString(labels, 'k8s.namespace.name')) NOT LIKE LOWER(?)",
|
||||
expected: "simpleJSONExtractString(labels, 'k8s.namespace.name') NOT ILIKE ?",
|
||||
expectedArgs: []any{"_mango%"},
|
||||
},
|
||||
{
|
||||
@@ -76,7 +76,7 @@ func TestConditionBuilder(t *testing.T) {
|
||||
},
|
||||
op: qbtypes.FilterOperatorContains,
|
||||
value: "banana",
|
||||
expected: "LOWER(simpleJSONExtractString(labels, 'k8s.namespace.name')) LIKE LOWER(?) AND labels LIKE ? AND LOWER(labels) LIKE LOWER(?)",
|
||||
expected: "simpleJSONExtractString(labels, 'k8s.namespace.name') ILIKE ? AND labels LIKE ? AND labels ILIKE ?",
|
||||
expectedArgs: []any{"%banana%", "%k8s.namespace.name%", `%k8s.namespace.name%banana%`},
|
||||
},
|
||||
{
|
||||
@@ -88,7 +88,7 @@ func TestConditionBuilder(t *testing.T) {
|
||||
},
|
||||
op: qbtypes.FilterOperatorContains,
|
||||
value: 521509198310,
|
||||
expected: "LOWER(simpleJSONExtractString(labels, 'company.id')) LIKE LOWER(?) AND labels LIKE ? AND LOWER(labels) LIKE LOWER(?)",
|
||||
expected: "simpleJSONExtractString(labels, 'company.id') ILIKE ? AND labels LIKE ? AND labels ILIKE ?",
|
||||
expectedArgs: []any{"%521509198310%", "%company.id%", `%company.id%521509198310%`},
|
||||
},
|
||||
{
|
||||
@@ -99,7 +99,7 @@ func TestConditionBuilder(t *testing.T) {
|
||||
},
|
||||
op: qbtypes.FilterOperatorNotContains,
|
||||
value: "banana",
|
||||
expected: "LOWER(simpleJSONExtractString(labels, 'k8s.namespace.name')) NOT LIKE LOWER(?)",
|
||||
expected: "simpleJSONExtractString(labels, 'k8s.namespace.name') NOT ILIKE ?",
|
||||
expectedArgs: []any{"%banana%"},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/o11y/pkg/valuer"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
// resourceFilterStatementBuilder builds resource fingerprint filter CTEs.
|
||||
|
||||
@@ -183,7 +183,7 @@ func TestResourceFilterStatementBuilder_Traces(t *testing.T) {
|
||||
start: testStartNs,
|
||||
end: testEndNs,
|
||||
expected: &qbtypes.Statement{
|
||||
Query: "SELECT fingerprint FROM o11y_traces.distributed_traces_v3_resource WHERE (LOWER(simpleJSONExtractString(labels, 'service.name')) LIKE LOWER(?) AND labels LIKE ? AND LOWER(labels) LIKE LOWER(?)) AND seen_at_ts_bucket_start >= ? AND seen_at_ts_bucket_start <= ? GROUP BY fingerprint",
|
||||
Query: "SELECT fingerprint FROM o11y_traces.distributed_traces_v3_resource WHERE (simpleJSONExtractString(labels, 'service.name') ILIKE ? AND labels LIKE ? AND labels ILIKE ?) AND seen_at_ts_bucket_start >= ? AND seen_at_ts_bucket_start <= ? GROUP BY fingerprint",
|
||||
Args: []any{"redis%", "%service.name%", "%service.name%redis%%", expectedBucketStart, expectedBucketEnd},
|
||||
},
|
||||
},
|
||||
@@ -258,7 +258,7 @@ func TestResourceFilterStatementBuilder_Traces(t *testing.T) {
|
||||
start: testStartNs,
|
||||
end: testEndNs,
|
||||
expected: &qbtypes.Statement{
|
||||
Query: "SELECT fingerprint FROM o11y_traces.distributed_traces_v3_resource WHERE (LOWER(simpleJSONExtractString(labels, 'service.name')) LIKE LOWER(?) AND labels LIKE ? AND LOWER(labels) LIKE LOWER(?)) AND seen_at_ts_bucket_start >= ? AND seen_at_ts_bucket_start <= ? GROUP BY fingerprint",
|
||||
Query: "SELECT fingerprint FROM o11y_traces.distributed_traces_v3_resource WHERE (simpleJSONExtractString(labels, 'service.name') ILIKE ? AND labels LIKE ? AND labels ILIKE ?) AND seen_at_ts_bucket_start >= ? AND seen_at_ts_bucket_start <= ? GROUP BY fingerprint",
|
||||
Args: []any{"%redis%", "%service.name%", "%service.name%redis%", expectedBucketStart, expectedBucketEnd},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// Package datastoremock exposes the datastore mock connection surface behind a
|
||||
// brand-neutral interface, so o11y test doubles depend on a local Datastore
|
||||
// contract rather than the mock driver's exported type name.
|
||||
package datastoremock
|
||||
|
||||
import dsmock "github.com/hanzoai/datastore-go-mock"
|
||||
|
||||
// Conn is the subset of the datastore mock driver used to set query
|
||||
// expectations in tests. The mock connection satisfies it structurally.
|
||||
type Conn interface {
|
||||
ExpectQuery(sql string) *dsmock.ExpectedQuery
|
||||
ExpectQueryRow(sql string) *dsmock.ExpectedQueryRow
|
||||
ExpectSelect(sql string) *dsmock.ExpectedSelect
|
||||
ExpectExec(sql string) *dsmock.ExpectedExec
|
||||
ExpectPrepareBatch(sql string) *dsmock.ExpectedPrepareBatch
|
||||
ExpectationsWereMet() error
|
||||
MatchExpectationsInOrder(bool)
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
dsmock "github.com/hanzoai/datastore-go-mock"
|
||||
"github.com/hanzoai/o11y/pkg/telemetrystore/datastoremock"
|
||||
"github.com/hanzoai/datastore-go/v2"
|
||||
"github.com/hanzoai/o11y/pkg/telemetrystore"
|
||||
"github.com/hanzoai/o11y/pkg/telemetrystore/datastoretelemetrystore"
|
||||
@@ -15,7 +16,7 @@ var _ telemetrystore.TelemetryStore = (*Provider)(nil)
|
||||
|
||||
// Provider represents a mock telemetry store provider for testing.
|
||||
type Provider struct {
|
||||
datastoreDB dsmock.ClickConnMockCommon
|
||||
datastoreDB datastoremock.Conn
|
||||
}
|
||||
|
||||
// New creates a new mock telemetry store provider.
|
||||
@@ -56,6 +57,6 @@ func (p *Provider) Indexes(ctx context.Context, stmt string, args ...any) (telem
|
||||
}
|
||||
|
||||
// Mock returns the underlying Datastore mock instance for setting expectations.
|
||||
func (p *Provider) Mock() dsmock.ClickConnMockCommon {
|
||||
func (p *Provider) Mock() datastoremock.Conn {
|
||||
return p.datastoreDB
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
schema "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -98,7 +98,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorILike,
|
||||
value: "%admin%",
|
||||
expectedSQL: "(LOWER(attributes_string['user.id']) LIKE LOWER(?) AND mapContains(attributes_string, 'user.id') = ?)",
|
||||
expectedSQL: "(attributes_string['user.id'] ILIKE ? AND mapContains(attributes_string, 'user.id') = ?)",
|
||||
expectedArgs: []any{"%admin%", true},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -111,7 +111,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorNotILike,
|
||||
value: "%admin%",
|
||||
expectedSQL: "WHERE LOWER(attributes_string['user.id']) NOT LIKE LOWER(?)",
|
||||
expectedSQL: "WHERE attributes_string['user.id'] NOT ILIKE ?",
|
||||
expectedArgs: []any{"%admin%", true},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -124,7 +124,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorContains,
|
||||
value: 521509198310,
|
||||
expectedSQL: "LOWER(attributes_string['user.id']) LIKE LOWER(?)",
|
||||
expectedSQL: "attributes_string['user.id'] ILIKE ?",
|
||||
expectedArgs: []any{"%521509198310%", true},
|
||||
expectedError: nil,
|
||||
},
|
||||
@@ -246,7 +246,7 @@ func TestConditionFor(t *testing.T) {
|
||||
},
|
||||
operator: qbtypes.FilterOperatorContains,
|
||||
value: "admin",
|
||||
expectedSQL: "(LOWER(attributes_string['user.id']) LIKE LOWER(?) AND mapContains(attributes_string, 'user.id') = ?)",
|
||||
expectedSQL: "(attributes_string['user.id'] ILIKE ? AND mapContains(attributes_string, 'user.id') = ?)",
|
||||
expectedArgs: []any{"%admin%", true},
|
||||
expectedError: nil,
|
||||
},
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
schema "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
@@ -201,7 +201,7 @@ func (m *defaultFieldMapper) getColumn(
|
||||
}
|
||||
|
||||
// TODO(srikanthccv): remove this when it's safe to remove
|
||||
// issue with CH aliasing
|
||||
// issue with Datastore aliasing
|
||||
|
||||
/*
|
||||
NOTE: There are fields which are deprecated for only to not show up as user suggestion and is possible that
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/instrumentation/instrumentationtest"
|
||||
"github.com/hanzoai/o11y/pkg/querybuilder"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/telemetrystore"
|
||||
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -848,7 +848,7 @@ func (b *traceQueryStatementBuilder) expandRawSelectFields(query qbtypes.QueryBu
|
||||
{Name: SpanSpanIDColumn, FieldContext: telemetrytypes.FieldContextSpan},
|
||||
}
|
||||
for _, field := range query.SelectFields {
|
||||
// TODO(tvats): If a user specifies attribute.timestamp in the select fields, this loop will basically ignore it, as we already added a field by default. This can be fixed once we close https://github.com/SigNoz/engineering-pod/issues/3693
|
||||
// TODO: If a user specifies attribute.timestamp in the select fields, this loop will basically ignore it, as we already added a field by default.
|
||||
if field.Name == SpanTimestampColumn || field.Name == SpanTraceIDColumn || field.Name == SpanSpanIDColumn {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/hanzoai/o11y/pkg/datastoresql"
|
||||
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
|
||||
"github.com/hanzoai/o11y/pkg/errors"
|
||||
"github.com/hanzoai/o11y/pkg/querybuilder"
|
||||
|
||||
@@ -144,12 +144,12 @@ type seriesLookup struct {
|
||||
|
||||
// FormulaEvaluator handles formula evaluation b/w time series from different aggregations
|
||||
// Why do we evaluate the formula expression in query-service?
|
||||
// In the initial iteration, we let the CH take care of the formula evaluation.
|
||||
// In the initial iteration, we let the Datastore take care of the formula evaluation.
|
||||
// Look at the query here https://github.com/hanzoai/o11y/blob/ad2d4ed56cf8457a0feee2b6947aed95c355c957/pkg/query-service/app/queryBuilder/query_builder_test.go#L459
|
||||
// This was achieved using the INNER JOIN between the query results.
|
||||
//
|
||||
// What are the issues with this approach?
|
||||
// The way CH handles the join evaluation is not the best suited for us in this scenario.
|
||||
// The way Datastore handles the join evaluation is not the best suited for us in this scenario.
|
||||
// It runs the right most side of the join before running anything else and progressively
|
||||
// completes the join from right to left. This becomes inefficient for simple cases like apdex (A+B/2)/C.
|
||||
// There is no need to wait for the right most side to complete before starting the evaluation for A and B.
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/hanzoai/o11y/pkg/errors"
|
||||
"github.com/hanzoai/o11y/pkg/types/telemetrytypes"
|
||||
schema "github.com/hanzoai/otel-collector/cmd/o11yschemamigrator/schema_migrator"
|
||||
"github.com/hanzoai/sqlbuilder"
|
||||
"github.com/hanzo-ds/sqlbuilder"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package spantypestest
|
||||
|
||||
import (
|
||||
dsmock "github.com/hanzoai/datastore-go-mock"
|
||||
"github.com/hanzoai/o11y/pkg/telemetrystore/datastoremock"
|
||||
"github.com/hanzoai/o11y/pkg/types/spantypes"
|
||||
)
|
||||
|
||||
// TraceStoreTest pairs a TraceStore with the Datastore mock.
|
||||
type TraceStoreTest struct {
|
||||
store spantypes.TraceStore
|
||||
mock dsmock.ClickConnMockCommon
|
||||
mock datastoremock.Conn
|
||||
}
|
||||
|
||||
func New(store spantypes.TraceStore, mock dsmock.ClickConnMockCommon) *TraceStoreTest {
|
||||
func New(store spantypes.TraceStore, mock datastoremock.Conn) *TraceStoreTest {
|
||||
return &TraceStoreTest{store: store, mock: mock}
|
||||
}
|
||||
|
||||
@@ -19,4 +19,4 @@ func New(store spantypes.TraceStore, mock dsmock.ClickConnMockCommon) *TraceStor
|
||||
func (t *TraceStoreTest) Store() spantypes.TraceStore { return t.store }
|
||||
|
||||
// Mock returns the Datastore mock for setting query expectations.
|
||||
func (t *TraceStoreTest) Mock() dsmock.ClickConnMockCommon { return t.mock }
|
||||
func (t *TraceStoreTest) Mock() datastoremock.Conn { return t.mock }
|
||||
|
||||
@@ -3,7 +3,7 @@ package datastore
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/hanzoai/datastore-sql-parser/parser"
|
||||
"github.com/hanzo-ds/sqlparser/parser"
|
||||
"github.com/hanzoai/o11y/pkg/errors"
|
||||
)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/hanzoai/datastore-sql-parser/parser"
|
||||
"github.com/hanzo-ds/sqlparser/parser"
|
||||
"github.com/hanzoai/o11y/pkg/variables"
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user