mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-11 17:41:47 +08:00

* fix: add settings to allow distributed_product_mode for trace panel * fix: tests fixed * fix: add 10gb memory limit --------- Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
730 lines
30 KiB
Go
730 lines
30 KiB
Go
package v4
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
|
)
|
|
|
|
func Test_getClickHouseTracesColumnType(t *testing.T) {
|
|
type args struct {
|
|
columnType v3.AttributeKeyType
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "tag",
|
|
args: args{
|
|
columnType: v3.AttributeKeyTypeTag,
|
|
},
|
|
want: "attributes",
|
|
},
|
|
{
|
|
name: "resource",
|
|
args: args{
|
|
columnType: v3.AttributeKeyTypeResource,
|
|
},
|
|
want: "resources",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := getClickHouseTracesColumnType(tt.args.columnType); got != tt.want {
|
|
t.Errorf("GetClickhouseTracesColumnType() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_getClickHouseTracesColumnDataType(t *testing.T) {
|
|
type args struct {
|
|
columnDataType v3.AttributeKeyDataType
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "string",
|
|
args: args{
|
|
columnDataType: v3.AttributeKeyDataTypeString,
|
|
},
|
|
want: "string",
|
|
},
|
|
{
|
|
name: "float64",
|
|
args: args{
|
|
columnDataType: v3.AttributeKeyDataTypeFloat64,
|
|
},
|
|
want: "number",
|
|
},
|
|
{
|
|
name: "int64",
|
|
args: args{
|
|
columnDataType: v3.AttributeKeyDataTypeInt64,
|
|
},
|
|
want: "number",
|
|
},
|
|
{
|
|
name: "bool",
|
|
args: args{
|
|
columnDataType: v3.AttributeKeyDataTypeBool,
|
|
},
|
|
want: "bool",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := getClickHouseTracesColumnDataType(tt.args.columnDataType); got != tt.want {
|
|
t.Errorf("getClickhouseTracesColumnDataType() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_getColumnName(t *testing.T) {
|
|
type args struct {
|
|
key v3.AttributeKey
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "tag",
|
|
args: args{
|
|
key: v3.AttributeKey{Key: "data", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag},
|
|
},
|
|
want: "attributes_string['data']",
|
|
},
|
|
{
|
|
name: "column",
|
|
args: args{
|
|
key: v3.AttributeKey{Key: "data", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true},
|
|
},
|
|
want: "`attribute_string_data`",
|
|
},
|
|
{
|
|
name: "static column",
|
|
args: args{
|
|
key: v3.AttributeKey{Key: "spanKind", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true},
|
|
},
|
|
want: "spanKind",
|
|
},
|
|
{
|
|
name: "missing meta",
|
|
args: args{
|
|
key: v3.AttributeKey{Key: "xyz"},
|
|
},
|
|
want: "attributes_string['xyz']",
|
|
},
|
|
{
|
|
name: "new composite column",
|
|
args: args{
|
|
key: v3.AttributeKey{Key: "response_status_code"},
|
|
},
|
|
want: "response_status_code",
|
|
},
|
|
{
|
|
name: "new composite column with metadata",
|
|
args: args{
|
|
key: v3.AttributeKey{Key: "response_status_code", DataType: v3.AttributeKeyDataTypeString, IsColumn: true},
|
|
},
|
|
want: "response_status_code",
|
|
},
|
|
{
|
|
name: "new normal column with metadata",
|
|
args: args{
|
|
key: v3.AttributeKey{Key: "http.route", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true},
|
|
},
|
|
want: "`attribute_string_http$$route`",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := getColumnName(tt.args.key); got != tt.want {
|
|
t.Errorf("getColumnName() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_getSelectLabels(t *testing.T) {
|
|
type args struct {
|
|
groupBy []v3.AttributeKey
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "count",
|
|
args: args{
|
|
groupBy: []v3.AttributeKey{{Key: "user_name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}},
|
|
},
|
|
want: " attributes_string['user_name'] as `user_name`",
|
|
},
|
|
{
|
|
name: "multiple group by",
|
|
args: args{
|
|
groupBy: []v3.AttributeKey{
|
|
{Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true}, // static col
|
|
{Key: "service_name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeResource, IsColumn: true},
|
|
},
|
|
},
|
|
want: " name as `name`, `resource_string_service_name` as `service_name`",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := getSelectLabels(tt.args.groupBy); got != tt.want {
|
|
t.Errorf("getSelectLabels() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_buildTracesFilterQuery(t *testing.T) {
|
|
type args struct {
|
|
fs *v3.FilterSet
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "Test ignore resource",
|
|
args: args{
|
|
fs: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
|
|
{Key: v3.AttributeKey{Key: "service.name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeResource}, Value: []interface{}{"service"}, Operator: v3.FilterOperatorIn},
|
|
},
|
|
}},
|
|
want: "",
|
|
},
|
|
{
|
|
name: "Test buildTracesFilterQuery in, nin",
|
|
args: args{
|
|
fs: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
|
|
{Key: v3.AttributeKey{Key: "method", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: []interface{}{"GET", "POST"}, Operator: v3.FilterOperatorIn},
|
|
{Key: v3.AttributeKey{Key: "method", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: []interface{}{"PUT"}, Operator: v3.FilterOperatorNotIn},
|
|
{Key: v3.AttributeKey{Key: "host", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeResource}, Value: []interface{}{"server"}, Operator: v3.FilterOperatorNotIn},
|
|
{Key: v3.AttributeKey{Key: "status.code", DataType: v3.AttributeKeyDataTypeInt64, Type: v3.AttributeKeyTypeTag}, Value: []interface{}{200}, Operator: v3.FilterOperatorNotIn},
|
|
{Key: v3.AttributeKey{Key: "duration", DataType: v3.AttributeKeyDataTypeFloat64, Type: v3.AttributeKeyTypeTag}, Value: []interface{}{100.0}, Operator: v3.FilterOperatorIn},
|
|
{Key: v3.AttributeKey{Key: "isDone", DataType: v3.AttributeKeyDataTypeBool, Type: v3.AttributeKeyTypeTag}, Value: []interface{}{true}, Operator: v3.FilterOperatorIn},
|
|
}},
|
|
},
|
|
want: "attributes_string['method'] IN ['GET','POST'] AND attributes_string['method'] NOT IN ['PUT'] AND attributes_number['status.code'] NOT IN [200] AND attributes_number['duration'] IN [100] AND attributes_bool['isDone'] IN [true]",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Test buildTracesFilterQuery not eq, neq, gt, lt, gte, lte",
|
|
args: args{
|
|
fs: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
|
|
{Key: v3.AttributeKey{Key: "duration", DataType: v3.AttributeKeyDataTypeInt64, Type: v3.AttributeKeyTypeTag}, Value: 102, Operator: v3.FilterOperatorEqual},
|
|
{Key: v3.AttributeKey{Key: "duration", DataType: v3.AttributeKeyDataTypeInt64, Type: v3.AttributeKeyTypeTag}, Value: 100, Operator: v3.FilterOperatorNotEqual},
|
|
{Key: v3.AttributeKey{Key: "duration", DataType: v3.AttributeKeyDataTypeInt64, Type: v3.AttributeKeyTypeTag}, Value: 10, Operator: v3.FilterOperatorGreaterThan},
|
|
{Key: v3.AttributeKey{Key: "duration", DataType: v3.AttributeKeyDataTypeInt64, Type: v3.AttributeKeyTypeTag}, Value: 200, Operator: v3.FilterOperatorLessThan},
|
|
{Key: v3.AttributeKey{Key: "duration", DataType: v3.AttributeKeyDataTypeFloat64, Type: v3.AttributeKeyTypeTag}, Value: 10.0, Operator: v3.FilterOperatorGreaterThanOrEq},
|
|
{Key: v3.AttributeKey{Key: "duration_str", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: "200", Operator: v3.FilterOperatorLessThanOrEq},
|
|
}},
|
|
},
|
|
want: "attributes_number['duration'] = 102 AND attributes_number['duration'] != 100 AND attributes_number['duration'] > 10 AND attributes_number['duration'] < 200" +
|
|
" AND attributes_number['duration'] >= 10.000000 AND attributes_string['duration_str'] <= '200'",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Test contains, ncontains, like, nlike, regex, nregex",
|
|
args: args{
|
|
fs: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
|
|
{Key: v3.AttributeKey{Key: "host", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: "102.%", Operator: v3.FilterOperatorContains},
|
|
{Key: v3.AttributeKey{Key: "host", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: "103_", Operator: v3.FilterOperatorNotContains},
|
|
{Key: v3.AttributeKey{Key: "host", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: "102.", Operator: v3.FilterOperatorLike},
|
|
{Key: v3.AttributeKey{Key: "host", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: "102", Operator: v3.FilterOperatorNotLike},
|
|
{Key: v3.AttributeKey{Key: "path", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true}, Value: "/mypath", Operator: v3.FilterOperatorRegex},
|
|
{Key: v3.AttributeKey{Key: "path", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true}, Value: "/health.*", Operator: v3.FilterOperatorNotRegex},
|
|
}},
|
|
},
|
|
want: "attributes_string['host'] ILIKE '%102.\\%%' AND attributes_string['host'] NOT ILIKE '%103\\_%' AND attributes_string['host'] ILIKE '102.' AND attributes_string['host'] NOT ILIKE '102' AND " +
|
|
"match(`attribute_string_path`, '/mypath') AND NOT match(`attribute_string_path`, '/health.*')",
|
|
},
|
|
{
|
|
name: "Test exists, nexists",
|
|
args: args{
|
|
fs: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
|
|
{Key: v3.AttributeKey{Key: "host", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Operator: v3.FilterOperatorExists},
|
|
{Key: v3.AttributeKey{Key: "duration", DataType: v3.AttributeKeyDataTypeInt64, Type: v3.AttributeKeyTypeTag}, Operator: v3.FilterOperatorExists},
|
|
{Key: v3.AttributeKey{Key: "isDone", DataType: v3.AttributeKeyDataTypeBool, Type: v3.AttributeKeyTypeTag}, Operator: v3.FilterOperatorNotExists},
|
|
{Key: v3.AttributeKey{Key: "host1", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Operator: v3.FilterOperatorNotExists},
|
|
{Key: v3.AttributeKey{Key: "path", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true}, Operator: v3.FilterOperatorNotExists},
|
|
}},
|
|
},
|
|
want: "mapContains(attributes_string, 'host') AND mapContains(attributes_number, 'duration') AND NOT mapContains(attributes_bool, 'isDone') AND NOT mapContains(attributes_string, 'host1') AND path = ''",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := buildTracesFilterQuery(tt.args.fs)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("buildTracesFilterQuery() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("buildTracesFilterQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_handleEmptyValuesInGroupBy(t *testing.T) {
|
|
type args struct {
|
|
groupBy []v3.AttributeKey
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "Test handleEmptyValuesInGroupBy",
|
|
args: args{
|
|
groupBy: []v3.AttributeKey{{Key: "bytes", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}},
|
|
},
|
|
want: "mapContains(attributes_string, 'bytes')",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Test handleEmptyValuesInGroupBy",
|
|
args: args{
|
|
groupBy: []v3.AttributeKey{{Key: "bytes", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true}},
|
|
},
|
|
want: "",
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := handleEmptyValuesInGroupBy(tt.args.groupBy)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("handleEmptyValuesInGroupBy() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("handleEmptyValuesInGroupBy() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_orderByAttributeKeyTags(t *testing.T) {
|
|
type args struct {
|
|
panelType v3.PanelType
|
|
items []v3.OrderBy
|
|
tags []v3.AttributeKey
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "test",
|
|
args: args{
|
|
panelType: v3.PanelTypeGraph,
|
|
items: []v3.OrderBy{{ColumnName: "name", Order: "ASC"}},
|
|
tags: []v3.AttributeKey{{Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}},
|
|
},
|
|
want: "`name` ASC",
|
|
},
|
|
{
|
|
name: "order by value",
|
|
args: args{
|
|
panelType: v3.PanelTypeGraph,
|
|
items: []v3.OrderBy{{ColumnName: "name", Order: "ASC"}, {ColumnName: constants.SigNozOrderByValue, Order: "DESC"}},
|
|
tags: []v3.AttributeKey{{Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}},
|
|
},
|
|
want: "`name` ASC,value DESC",
|
|
},
|
|
{
|
|
name: "test",
|
|
args: args{
|
|
panelType: v3.PanelTypeList,
|
|
items: []v3.OrderBy{{ColumnName: "status", Order: "DESC", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag},
|
|
{ColumnName: "route", Order: "DESC", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true}},
|
|
},
|
|
want: "attributes_string['status'] DESC,`attribute_string_route` DESC",
|
|
},
|
|
{
|
|
name: "ignore order by in table panel",
|
|
args: args{
|
|
panelType: v3.PanelTypeTable,
|
|
items: []v3.OrderBy{{ColumnName: "timestamp", Order: "DESC"}},
|
|
tags: []v3.AttributeKey{},
|
|
},
|
|
want: "value DESC",
|
|
},
|
|
{
|
|
name: "add default order by ts for list panel",
|
|
args: args{
|
|
panelType: v3.PanelTypeList,
|
|
items: []v3.OrderBy{},
|
|
tags: []v3.AttributeKey{},
|
|
},
|
|
want: "timestamp DESC",
|
|
},
|
|
{
|
|
name: "add default order by value for graph panel",
|
|
args: args{
|
|
panelType: v3.PanelTypeGraph,
|
|
items: []v3.OrderBy{},
|
|
tags: []v3.AttributeKey{},
|
|
},
|
|
want: "value DESC",
|
|
},
|
|
{
|
|
name: "don't add default order by for table panel",
|
|
args: args{
|
|
panelType: v3.PanelTypeTable,
|
|
items: []v3.OrderBy{},
|
|
tags: []v3.AttributeKey{},
|
|
},
|
|
want: "value DESC",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := orderByAttributeKeyTags(tt.args.panelType, tt.args.items, tt.args.tags); got != tt.want {
|
|
t.Errorf("orderByAttributeKeyTags() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_buildTracesQuery(t *testing.T) {
|
|
type args struct {
|
|
start int64
|
|
end int64
|
|
step int64
|
|
mq *v3.BuilderQuery
|
|
panelType v3.PanelType
|
|
options v3.QBOptions
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "Test buildTracesQuery",
|
|
args: args{
|
|
panelType: v3.PanelTypeTable,
|
|
start: 1680066360726210000,
|
|
end: 1680066458000000000,
|
|
step: 1000,
|
|
mq: &v3.BuilderQuery{
|
|
AggregateOperator: v3.AggregateOperatorCount,
|
|
Filters: &v3.FilterSet{
|
|
Items: []v3.FilterItem{
|
|
{
|
|
Key: v3.AttributeKey{Key: "http.method", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag},
|
|
Value: 100,
|
|
Operator: v3.FilterOperatorEqual,
|
|
},
|
|
},
|
|
},
|
|
GroupBy: []v3.AttributeKey{{Key: "http.method", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}},
|
|
OrderBy: []v3.OrderBy{
|
|
{ColumnName: "http.method", Order: "ASC"}},
|
|
},
|
|
},
|
|
want: "SELECT attributes_string['http.method'] as `http.method`, toFloat64(count()) as value from signoz_traces.distributed_signoz_index_v3 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
|
"AND (ts_bucket_start >= 1680064560 AND ts_bucket_start <= 1680066458) AND attributes_string['http.method'] = '100' AND mapContains(attributes_string, 'http.method') " +
|
|
"group by `http.method` order by `http.method` ASC",
|
|
},
|
|
{
|
|
name: "Test buildTracesQuery",
|
|
args: args{
|
|
panelType: v3.PanelTypeTable,
|
|
start: 1680066360726210000,
|
|
end: 1680066458000000000,
|
|
step: 1000,
|
|
mq: &v3.BuilderQuery{
|
|
AggregateOperator: v3.AggregateOperatorCount,
|
|
Filters: &v3.FilterSet{
|
|
Items: []v3.FilterItem{
|
|
{Key: v3.AttributeKey{Key: "bytes", Type: v3.AttributeKeyTypeTag, DataType: v3.AttributeKeyDataTypeInt64}, Value: 100, Operator: ">"},
|
|
{Key: v3.AttributeKey{Key: "service.name", Type: v3.AttributeKeyTypeResource, DataType: v3.AttributeKeyDataTypeString}, Value: "myService", Operator: "="},
|
|
},
|
|
},
|
|
GroupBy: []v3.AttributeKey{{Key: "host", DataType: v3.AttributeKeyDataTypeInt64, Type: v3.AttributeKeyTypeResource}},
|
|
OrderBy: []v3.OrderBy{
|
|
{ColumnName: "host", Order: "ASC"}},
|
|
},
|
|
},
|
|
want: "SELECT resources_number['host'] as `host`, toFloat64(count()) as value from signoz_traces.distributed_signoz_index_v3 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
|
"AND (ts_bucket_start >= 1680064560 AND ts_bucket_start <= 1680066458) AND attributes_number['bytes'] > 100 AND " +
|
|
"(resource_fingerprint GLOBAL IN (SELECT fingerprint FROM signoz_traces.distributed_traces_v3_resource WHERE (seen_at_ts_bucket_start >= 1680064560) AND " +
|
|
"(seen_at_ts_bucket_start <= 1680066458) AND simpleJSONExtractString(labels, 'service.name') = 'myService' AND labels like '%service.name%myService%' AND " +
|
|
"( (simpleJSONHas(labels, 'host') AND labels like '%host%') ))) " +
|
|
"group by `host` order by `host` ASC",
|
|
},
|
|
{
|
|
name: "test noop list view",
|
|
args: args{
|
|
panelType: v3.PanelTypeList,
|
|
start: 1680066360726210000,
|
|
end: 1680066458000000000,
|
|
mq: &v3.BuilderQuery{
|
|
AggregateOperator: v3.AggregateOperatorNoOp,
|
|
Filters: &v3.FilterSet{},
|
|
SelectColumns: []v3.AttributeKey{{Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true}},
|
|
OrderBy: []v3.OrderBy{{ColumnName: "timestamp", Order: "ASC"}},
|
|
},
|
|
},
|
|
want: "SELECT timestamp as timestamp_datetime, spanID, traceID, name as `name` from signoz_traces.distributed_signoz_index_v3 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
|
"AND (ts_bucket_start >= 1680064560 AND ts_bucket_start <= 1680066458) order by timestamp ASC",
|
|
},
|
|
{
|
|
name: "test noop list view-without ts",
|
|
args: args{
|
|
panelType: v3.PanelTypeList,
|
|
start: 1680066360726210000,
|
|
end: 1680066458000000000,
|
|
mq: &v3.BuilderQuery{
|
|
AggregateOperator: v3.AggregateOperatorNoOp,
|
|
Filters: &v3.FilterSet{},
|
|
SelectColumns: []v3.AttributeKey{{Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag, IsColumn: true}},
|
|
},
|
|
},
|
|
want: "SELECT timestamp as timestamp_datetime, spanID, traceID, name as `name` from signoz_traces.distributed_signoz_index_v3 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " +
|
|
"AND (ts_bucket_start >= 1680064560 AND ts_bucket_start <= 1680066458) order by timestamp DESC",
|
|
},
|
|
{
|
|
name: "test noop trace view",
|
|
args: args{
|
|
panelType: v3.PanelTypeTrace,
|
|
start: 1680066360726210000,
|
|
end: 1680066458000000000,
|
|
mq: &v3.BuilderQuery{
|
|
AggregateOperator: v3.AggregateOperatorNoOp,
|
|
Filters: &v3.FilterSet{
|
|
Items: []v3.FilterItem{
|
|
{Key: v3.AttributeKey{Key: "method", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: "GET", Operator: "="},
|
|
{Key: v3.AttributeKey{Key: "service.name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeResource}, Value: "myService", Operator: "="},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: "SELECT subQuery.serviceName, subQuery.name, count() AS span_count, subQuery.durationNano, subQuery.traceID AS traceID FROM signoz_traces.distributed_signoz_index_v3 INNER JOIN " +
|
|
"( SELECT * FROM (SELECT traceID, durationNano, serviceName, name FROM signoz_traces.signoz_index_v3 WHERE parentSpanID = '' AND (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') AND " +
|
|
"(ts_bucket_start >= 1680064560 AND ts_bucket_start <= 1680066458) AND attributes_string['method'] = 'GET' AND (resource_fingerprint GLOBAL IN (SELECT fingerprint FROM signoz_traces.distributed_traces_v3_resource " +
|
|
"WHERE (seen_at_ts_bucket_start >= 1680064560) AND (seen_at_ts_bucket_start <= 1680066458) AND simpleJSONExtractString(labels, 'service.name') = 'myService' AND labels like '%service.name%myService%')) " +
|
|
"ORDER BY durationNano DESC LIMIT 1 BY traceID LIMIT 100) AS inner_subquery ) AS subQuery ON signoz_traces.distributed_signoz_index_v3.traceID = subQuery.traceID WHERE (timestamp >= '1680066360726210000' AND " +
|
|
"timestamp <= '1680066458000000000') AND (ts_bucket_start >= 1680064560 AND ts_bucket_start <= 1680066458) GROUP BY subQuery.traceID, subQuery.durationNano, subQuery.name, subQuery.serviceName ORDER BY " +
|
|
"subQuery.durationNano desc LIMIT 1 BY subQuery.traceID settings distributed_product_mode='allow', max_memory_usage=10000000000",
|
|
},
|
|
{
|
|
name: "Test order by value with having",
|
|
args: args{
|
|
panelType: v3.PanelTypeTable,
|
|
start: 1680066360726210000,
|
|
end: 1680066458000000000,
|
|
mq: &v3.BuilderQuery{
|
|
AggregateOperator: v3.AggregateOperatorCountDistinct,
|
|
Filters: &v3.FilterSet{},
|
|
AggregateAttribute: v3.AttributeKey{Key: "name", IsColumn: true, DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag},
|
|
OrderBy: []v3.OrderBy{{ColumnName: "#SIGNOZ_VALUE", Order: "ASC"}},
|
|
Having: []v3.Having{
|
|
{
|
|
ColumnName: "name",
|
|
Operator: ">",
|
|
Value: 10,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: "SELECT toFloat64(count(distinct(name))) as value from signoz_traces.distributed_signoz_index_v3 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') AND " +
|
|
"(ts_bucket_start >= 1680064560 AND ts_bucket_start <= 1680066458) having value > 10 order by value ASC",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := buildTracesQuery(tt.args.start, tt.args.end, tt.args.step, tt.args.mq, tt.args.panelType, tt.args.options)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("buildTracesQuery() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("buildTracesQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPrepareTracesQuery(t *testing.T) {
|
|
type args struct {
|
|
start int64
|
|
end int64
|
|
panelType v3.PanelType
|
|
mq *v3.BuilderQuery
|
|
options v3.QBOptions
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "test with limit - first",
|
|
args: args{
|
|
start: 1680066360726210000,
|
|
end: 1680066458000000000,
|
|
panelType: v3.PanelTypeTable,
|
|
mq: &v3.BuilderQuery{
|
|
StepInterval: 60,
|
|
AggregateOperator: v3.AggregateOperatorCountDistinct,
|
|
Filters: &v3.FilterSet{},
|
|
AggregateAttribute: v3.AttributeKey{Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag},
|
|
GroupBy: []v3.AttributeKey{{Key: "function", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}},
|
|
Limit: 10,
|
|
OrderBy: []v3.OrderBy{{ColumnName: "#SIGNOZ_VALUE", Order: "DESC"}},
|
|
},
|
|
options: v3.QBOptions{
|
|
GraphLimitQtype: constants.FirstQueryGraphLimit,
|
|
},
|
|
},
|
|
want: "SELECT `function` from (SELECT attributes_string['function'] as `function`, toFloat64(count(distinct(name))) as value from signoz_traces.distributed_signoz_index_v3 " +
|
|
"where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') AND (ts_bucket_start >= 1680064560 AND ts_bucket_start <= 1680066458) AND mapContains(attributes_string, 'function') group by `function` order by value DESC) LIMIT 10",
|
|
},
|
|
{
|
|
name: "test with limit - second",
|
|
args: args{
|
|
start: 1680066360726210000,
|
|
end: 1680066458000000000,
|
|
panelType: v3.PanelTypeTable,
|
|
mq: &v3.BuilderQuery{
|
|
StepInterval: 60,
|
|
AggregateOperator: v3.AggregateOperatorCountDistinct,
|
|
Filters: &v3.FilterSet{},
|
|
AggregateAttribute: v3.AttributeKey{Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag},
|
|
GroupBy: []v3.AttributeKey{{Key: "function", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}},
|
|
OrderBy: []v3.OrderBy{{ColumnName: "#SIGNOZ_VALUE", Order: "DESC"}},
|
|
Limit: 10,
|
|
},
|
|
options: v3.QBOptions{
|
|
GraphLimitQtype: constants.SecondQueryGraphLimit,
|
|
},
|
|
},
|
|
want: "SELECT attributes_string['function'] as `function`, toFloat64(count(distinct(name))) as value from signoz_traces.distributed_signoz_index_v3 where " +
|
|
"(timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') AND (ts_bucket_start >= 1680064560 AND ts_bucket_start <= 1680066458) AND mapContains(attributes_string, 'function') AND (`function`) GLOBAL IN (%s) group by `function` order by value DESC",
|
|
},
|
|
{
|
|
name: "test with limit with resources- first",
|
|
args: args{
|
|
start: 1680066360726210000,
|
|
end: 1680066458000000000,
|
|
panelType: v3.PanelTypeTable,
|
|
mq: &v3.BuilderQuery{
|
|
StepInterval: 60,
|
|
AggregateOperator: v3.AggregateOperatorCountDistinct,
|
|
Filters: &v3.FilterSet{
|
|
Operator: "AND",
|
|
Items: []v3.FilterItem{
|
|
{
|
|
Key: v3.AttributeKey{Key: "line", DataType: v3.AttributeKeyDataTypeInt64, Type: v3.AttributeKeyTypeTag},
|
|
Value: 100,
|
|
Operator: v3.FilterOperatorEqual,
|
|
},
|
|
{
|
|
Key: v3.AttributeKey{Key: "hostname", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeResource},
|
|
Value: "server1",
|
|
Operator: v3.FilterOperatorEqual,
|
|
},
|
|
},
|
|
},
|
|
AggregateAttribute: v3.AttributeKey{Key: "name", IsColumn: true, DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag},
|
|
GroupBy: []v3.AttributeKey{
|
|
{Key: "function", IsColumn: true, DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag},
|
|
{Key: "service.name", IsColumn: true, DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeResource},
|
|
},
|
|
Limit: 10,
|
|
OrderBy: []v3.OrderBy{{ColumnName: "#SIGNOZ_VALUE", Order: "DESC"}},
|
|
},
|
|
options: v3.QBOptions{
|
|
GraphLimitQtype: constants.FirstQueryGraphLimit,
|
|
},
|
|
},
|
|
want: "SELECT `function`,`service.name` from (SELECT `attribute_string_function` as `function`, `resource_string_service$$name` as `service.name`, toFloat64(count(distinct(name))) as value " +
|
|
"from signoz_traces.distributed_signoz_index_v3 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') AND (ts_bucket_start >= 1680064560 AND ts_bucket_start <= 1680066458) " +
|
|
"AND attributes_number['line'] = 100 AND (resource_fingerprint GLOBAL IN (SELECT fingerprint FROM signoz_traces.distributed_traces_v3_resource WHERE " +
|
|
"(seen_at_ts_bucket_start >= 1680064560) AND (seen_at_ts_bucket_start <= 1680066458) AND simpleJSONExtractString(labels, 'hostname') = 'server1' AND labels like '%hostname%server1%' AND " +
|
|
"( (simpleJSONHas(labels, 'service.name') AND labels like '%service.name%') ))) group by `function`,`service.name` order by value DESC) LIMIT 10",
|
|
},
|
|
{
|
|
name: "test with limit with resources - second",
|
|
args: args{
|
|
start: 1680066360726210000,
|
|
end: 1680066458000000000,
|
|
panelType: v3.PanelTypeTable,
|
|
mq: &v3.BuilderQuery{
|
|
StepInterval: 60,
|
|
AggregateOperator: v3.AggregateOperatorCountDistinct,
|
|
Filters: &v3.FilterSet{
|
|
Operator: "AND",
|
|
Items: []v3.FilterItem{
|
|
{
|
|
Key: v3.AttributeKey{Key: "line", DataType: v3.AttributeKeyDataTypeInt64, Type: v3.AttributeKeyTypeTag},
|
|
Value: 100,
|
|
Operator: v3.FilterOperatorEqual,
|
|
},
|
|
{
|
|
Key: v3.AttributeKey{Key: "hostname", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeResource},
|
|
Value: "server1",
|
|
Operator: v3.FilterOperatorEqual,
|
|
},
|
|
},
|
|
},
|
|
AggregateAttribute: v3.AttributeKey{Key: "name", IsColumn: true, DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag},
|
|
GroupBy: []v3.AttributeKey{
|
|
{Key: "function", IsColumn: true, DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag},
|
|
{Key: "serviceName", IsColumn: true, DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag},
|
|
},
|
|
OrderBy: []v3.OrderBy{{ColumnName: "#SIGNOZ_VALUE", Order: "DESC"}},
|
|
Limit: 10,
|
|
},
|
|
options: v3.QBOptions{
|
|
GraphLimitQtype: constants.SecondQueryGraphLimit,
|
|
},
|
|
},
|
|
want: "SELECT `attribute_string_function` as `function`, serviceName as `serviceName`, toFloat64(count(distinct(name))) as value from signoz_traces.distributed_signoz_index_v3 " +
|
|
"where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') AND (ts_bucket_start >= 1680064560 AND ts_bucket_start <= 1680066458) AND attributes_number['line'] = 100 " +
|
|
"AND (resource_fingerprint GLOBAL IN (SELECT fingerprint FROM signoz_traces.distributed_traces_v3_resource WHERE (seen_at_ts_bucket_start >= 1680064560) AND (seen_at_ts_bucket_start <= 1680066458) " +
|
|
"AND simpleJSONExtractString(labels, 'hostname') = 'server1' AND labels like '%hostname%server1%')) AND (`function`,`serviceName`) GLOBAL IN (%s) group by `function`,`serviceName` order by value DESC",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := PrepareTracesQuery(tt.args.start, tt.args.end, tt.args.panelType, tt.args.mq, tt.args.options)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("PrepareTracesQuery() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("PrepareTracesQuery() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|