chore: use attributes table for metric keys and values (#7680)

This commit is contained in:
Srikanth Chekuri 2025-04-23 14:35:56 +05:30 committed by GitHub
parent 131759ec96
commit 9eb2196617
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 281 additions and 151 deletions

View File

@ -28,8 +28,7 @@ func NewAPI(telemetryStore telemetrystore.TelemetryStore) *API {
telemetrytraces.TagAttributesV2TableName, telemetrytraces.TagAttributesV2TableName,
telemetrytraces.SpanIndexV3TableName, telemetrytraces.SpanIndexV3TableName,
telemetrymetrics.DBName, telemetrymetrics.DBName,
telemetrymetrics.TimeseriesV41weekTableName, telemetrymetrics.AttributesMetadataTableName,
telemetrymetrics.TimeseriesV41weekLocalTableName,
telemetrylogs.DBName, telemetrylogs.DBName,
telemetrylogs.LogsV2TableName, telemetrylogs.LogsV2TableName,
telemetrylogs.TagAttributesV2TableName, telemetrylogs.TagAttributesV2TableName,

View File

@ -20,18 +20,18 @@ import (
type WhereClauseVisitor struct { type WhereClauseVisitor struct {
conditionBuilder qbtypes.ConditionBuilder conditionBuilder qbtypes.ConditionBuilder
warnings []error warnings []error
fieldKeys map[string][]telemetrytypes.TelemetryFieldKey fieldKeys map[string][]*telemetrytypes.TelemetryFieldKey
errors []error errors []error
builder *sqlbuilder.SelectBuilder builder *sqlbuilder.SelectBuilder
fullTextColumn telemetrytypes.TelemetryFieldKey fullTextColumn *telemetrytypes.TelemetryFieldKey
} }
// NewWhereClauseVisitor creates a new WhereClauseVisitor // NewWhereClauseVisitor creates a new WhereClauseVisitor
func NewWhereClauseVisitor( func NewWhereClauseVisitor(
conditionBuilder qbtypes.ConditionBuilder, conditionBuilder qbtypes.ConditionBuilder,
fieldKeys map[string][]telemetrytypes.TelemetryFieldKey, fieldKeys map[string][]*telemetrytypes.TelemetryFieldKey,
builder *sqlbuilder.SelectBuilder, builder *sqlbuilder.SelectBuilder,
fullTextColumn telemetrytypes.TelemetryFieldKey, fullTextColumn *telemetrytypes.TelemetryFieldKey,
) *WhereClauseVisitor { ) *WhereClauseVisitor {
return &WhereClauseVisitor{ return &WhereClauseVisitor{
conditionBuilder: conditionBuilder, conditionBuilder: conditionBuilder,
@ -72,10 +72,10 @@ func (l *ErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol
// PrepareWhereClause generates a ClickHouse compatible WHERE clause from the filter query // PrepareWhereClause generates a ClickHouse compatible WHERE clause from the filter query
func PrepareWhereClause( func PrepareWhereClause(
query string, query string,
fieldKeys map[string][]telemetrytypes.TelemetryFieldKey, fieldKeys map[string][]*telemetrytypes.TelemetryFieldKey,
conditionBuilder qbtypes.ConditionBuilder, conditionBuilder qbtypes.ConditionBuilder,
fullTextColumn telemetrytypes.TelemetryFieldKey, fullTextColumn *telemetrytypes.TelemetryFieldKey,
) (string, []any, []error, error) { ) (*sqlbuilder.WhereClause, []error, error) {
// Setup the ANTLR parsing pipeline // Setup the ANTLR parsing pipeline
input := antlr.NewInputStream(query) input := antlr.NewInputStream(query)
lexer := NewFilterQueryLexer(input) lexer := NewFilterQueryLexer(input)
@ -107,7 +107,7 @@ func PrepareWhereClause(
len(parserErrorListener.Errors), len(parserErrorListener.Errors),
parserErrorListener.Errors, parserErrorListener.Errors,
) )
return "", nil, nil, combinedErrors return nil, nil, combinedErrors
} }
// Visit the parse tree with our ClickHouse visitor // Visit the parse tree with our ClickHouse visitor
@ -122,12 +122,12 @@ func PrepareWhereClause(
len(visitor.errors), len(visitor.errors),
visitor.errors, visitor.errors,
) )
return "", nil, nil, combinedErrors return nil, nil, combinedErrors
} }
whereClause, args := visitor.builder.Where(cond).BuildWithFlavor(sqlbuilder.ClickHouse) whereClause := sqlbuilder.NewWhereClause().AddWhereExpr(visitor.builder.Args, cond)
return whereClause, args, visitor.warnings, nil return whereClause, visitor.warnings, nil
} }
// Visit dispatches to the specific visit method based on node type // Visit dispatches to the specific visit method based on node type
@ -250,7 +250,7 @@ func (v *WhereClauseVisitor) VisitPrimary(ctx *PrimaryContext) any {
if keyCtx, ok := child.(*KeyContext); ok { if keyCtx, ok := child.(*KeyContext); ok {
// create a full text search condition on the body field // create a full text search condition on the body field
keyText := keyCtx.GetText() keyText := keyCtx.GetText()
cond, err := v.conditionBuilder.GetCondition(context.Background(), &v.fullTextColumn, qbtypes.FilterOperatorRegexp, keyText, v.builder) cond, err := v.conditionBuilder.GetCondition(context.Background(), v.fullTextColumn, qbtypes.FilterOperatorRegexp, keyText, v.builder)
if err != nil { if err != nil {
return "" return ""
} }
@ -263,7 +263,7 @@ func (v *WhereClauseVisitor) VisitPrimary(ctx *PrimaryContext) any {
// VisitComparison handles all comparison operators // VisitComparison handles all comparison operators
func (v *WhereClauseVisitor) VisitComparison(ctx *ComparisonContext) any { func (v *WhereClauseVisitor) VisitComparison(ctx *ComparisonContext) any {
keys := v.Visit(ctx.Key()).([]telemetrytypes.TelemetryFieldKey) keys := v.Visit(ctx.Key()).([]*telemetrytypes.TelemetryFieldKey)
// Handle EXISTS specially // Handle EXISTS specially
if ctx.EXISTS() != nil { if ctx.EXISTS() != nil {
@ -273,7 +273,7 @@ func (v *WhereClauseVisitor) VisitComparison(ctx *ComparisonContext) any {
} }
var conds []string var conds []string
for _, key := range keys { for _, key := range keys {
condition, err := v.conditionBuilder.GetCondition(context.Background(), &key, op, nil, v.builder) condition, err := v.conditionBuilder.GetCondition(context.Background(), key, op, nil, v.builder)
if err != nil { if err != nil {
return "" return ""
} }
@ -291,7 +291,7 @@ func (v *WhereClauseVisitor) VisitComparison(ctx *ComparisonContext) any {
} }
var conds []string var conds []string
for _, key := range keys { for _, key := range keys {
condition, err := v.conditionBuilder.GetCondition(context.Background(), &key, op, values, v.builder) condition, err := v.conditionBuilder.GetCondition(context.Background(), key, op, values, v.builder)
if err != nil { if err != nil {
return "" return ""
} }
@ -317,7 +317,7 @@ func (v *WhereClauseVisitor) VisitComparison(ctx *ComparisonContext) any {
var conds []string var conds []string
for _, key := range keys { for _, key := range keys {
condition, err := v.conditionBuilder.GetCondition(context.Background(), &key, op, []any{value1, value2}, v.builder) condition, err := v.conditionBuilder.GetCondition(context.Background(), key, op, []any{value1, value2}, v.builder)
if err != nil { if err != nil {
return "" return ""
} }
@ -366,7 +366,7 @@ func (v *WhereClauseVisitor) VisitComparison(ctx *ComparisonContext) any {
var conds []string var conds []string
for _, key := range keys { for _, key := range keys {
condition, err := v.conditionBuilder.GetCondition(context.Background(), &key, op, value, v.builder) condition, err := v.conditionBuilder.GetCondition(context.Background(), key, op, value, v.builder)
if err != nil { if err != nil {
return "" return ""
} }
@ -404,7 +404,7 @@ func (v *WhereClauseVisitor) VisitValueList(ctx *ValueListContext) any {
func (v *WhereClauseVisitor) VisitFullText(ctx *FullTextContext) any { func (v *WhereClauseVisitor) VisitFullText(ctx *FullTextContext) any {
// remove quotes from the quotedText // remove quotes from the quotedText
quotedText := strings.Trim(ctx.QUOTED_TEXT().GetText(), "\"'") quotedText := strings.Trim(ctx.QUOTED_TEXT().GetText(), "\"'")
cond, err := v.conditionBuilder.GetCondition(context.Background(), &v.fullTextColumn, qbtypes.FilterOperatorRegexp, quotedText, v.builder) cond, err := v.conditionBuilder.GetCondition(context.Background(), v.fullTextColumn, qbtypes.FilterOperatorRegexp, quotedText, v.builder)
if err != nil { if err != nil {
return "" return ""
} }
@ -443,7 +443,7 @@ func (v *WhereClauseVisitor) VisitFunctionCall(ctx *FunctionCallContext) any {
return "" return ""
} }
keys, ok := params[0].([]telemetrytypes.TelemetryFieldKey) keys, ok := params[0].([]*telemetrytypes.TelemetryFieldKey)
if !ok { if !ok {
v.errors = append(v.errors, errors.Newf( v.errors = append(v.errors, errors.Newf(
errors.TypeInvalidInput, errors.TypeInvalidInput,
@ -459,9 +459,9 @@ func (v *WhereClauseVisitor) VisitFunctionCall(ctx *FunctionCallContext) any {
var fieldName string var fieldName string
if strings.HasPrefix(key.Name, telemetrylogs.BodyJSONStringSearchPrefix) { if strings.HasPrefix(key.Name, telemetrylogs.BodyJSONStringSearchPrefix) {
fieldName, _ = telemetrylogs.GetBodyJSONKey(context.Background(), &key, qbtypes.FilterOperatorUnknown, value) fieldName, _ = telemetrylogs.GetBodyJSONKey(context.Background(), key, qbtypes.FilterOperatorUnknown, value)
} else { } else {
fieldName, _ = v.conditionBuilder.GetTableFieldName(context.Background(), &key) fieldName, _ = v.conditionBuilder.GetTableFieldName(context.Background(), key)
} }
var cond string var cond string
@ -557,7 +557,7 @@ func (v *WhereClauseVisitor) VisitKey(ctx *KeyContext) any {
// Since it will ORed with the fieldKeysForName, it will not result empty // Since it will ORed with the fieldKeysForName, it will not result empty
// when either of them have values // when either of them have values
if strings.HasPrefix(fieldKey.Name, telemetrylogs.BodyJSONStringSearchPrefix) { if strings.HasPrefix(fieldKey.Name, telemetrylogs.BodyJSONStringSearchPrefix) {
fieldKeysForName = append(fieldKeysForName, fieldKey) fieldKeysForName = append(fieldKeysForName, &fieldKey)
} }
// TODO(srikanthccv): do we want to return an error here? // TODO(srikanthccv): do we want to return an error here?

View File

@ -8,19 +8,20 @@ import (
"github.com/SigNoz/signoz/pkg/telemetrylogs" "github.com/SigNoz/signoz/pkg/telemetrylogs"
"github.com/SigNoz/signoz/pkg/telemetrytraces" "github.com/SigNoz/signoz/pkg/telemetrytraces"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes" "github.com/SigNoz/signoz/pkg/types/telemetrytypes"
sqlbuilder "github.com/huandu/go-sqlbuilder"
) )
func TestConvertToClickHouseLogsQuery(t *testing.T) { func TestConvertToClickHouseLogsQuery(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
fieldKeys map[string][]telemetrytypes.TelemetryFieldKey fieldKeys map[string][]*telemetrytypes.TelemetryFieldKey
query string query string
expectedSearchString string expectedSearchString string
expectedSearchArgs []any expectedSearchArgs []any
}{ }{
{ {
name: "test-simple-service-name-filter", name: "test-simple-service-name-filter",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"service.name": { "service.name": {
{ {
Name: "service.name", Name: "service.name",
@ -36,7 +37,7 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
}, },
{ {
name: "test-simple-service-name-filter-with-materialised-column", name: "test-simple-service-name-filter-with-materialised-column",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"service.name": { "service.name": {
{ {
Name: "service.name", Name: "service.name",
@ -53,7 +54,7 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
}, },
{ {
name: "http-status-code-multiple-data-types", name: "http-status-code-multiple-data-types",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"http.status_code": { "http.status_code": {
{ {
Name: "http.status_code", Name: "http.status_code",
@ -75,7 +76,7 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
}, },
{ {
name: "http-status-code-multiple-data-types-between-operator", name: "http-status-code-multiple-data-types-between-operator",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"http.status_code": { "http.status_code": {
{ {
Name: "http.status_code", Name: "http.status_code",
@ -97,7 +98,7 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
}, },
{ {
name: "response-body-multiple-data-types-string-contains", name: "response-body-multiple-data-types-string-contains",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"response.body": { "response.body": {
{ {
Name: "response.body", Name: "response.body",
@ -119,7 +120,7 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
}, },
{ {
name: "search-on-top-level-key", name: "search-on-top-level-key",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"severity_text": { "severity_text": {
{ {
Name: "severity_text", Name: "severity_text",
@ -135,7 +136,7 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
}, },
{ {
name: "search-on-top-level-key-conflict-with-attribute", name: "search-on-top-level-key-conflict-with-attribute",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"severity_text": { "severity_text": {
{ {
Name: "severity_text", Name: "severity_text",
@ -157,7 +158,7 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
}, },
{ {
name: "collision-with-attribute-field-and-resource-attribute", name: "collision-with-attribute-field-and-resource-attribute",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"k8s.namespace.name": { "k8s.namespace.name": {
{ {
Name: "k8s.namespace.name", Name: "k8s.namespace.name",
@ -179,7 +180,7 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
}, },
{ {
name: "collision-with-attribute-field-and-resource-attribute-materialised-column", name: "collision-with-attribute-field-and-resource-attribute-materialised-column",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"k8s.namespace.name": { "k8s.namespace.name": {
{ {
Name: "k8s.namespace.name", Name: "k8s.namespace.name",
@ -202,7 +203,7 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
}, },
{ {
name: "boolean-collision-with-attribute-field-and-data-type-boolean", name: "boolean-collision-with-attribute-field-and-data-type-boolean",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"did_user_login": { "did_user_login": {
{ {
Name: "did_user_login", Name: "did_user_login",
@ -224,7 +225,7 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
}, },
{ {
name: "regexp-search", name: "regexp-search",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"k8s.namespace.name": { "k8s.namespace.name": {
{ {
Name: "k8s.namespace.name", Name: "k8s.namespace.name",
@ -248,42 +249,42 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
}, },
{ {
name: "full-text-search-multiple-words", name: "full-text-search-multiple-words",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{},
query: "waiting for response", query: "waiting for response",
expectedSearchString: "WHERE ((match(body, ?)) AND (match(body, ?)) AND (match(body, ?)))", expectedSearchString: "WHERE ((match(body, ?)) AND (match(body, ?)) AND (match(body, ?)))",
expectedSearchArgs: []any{"waiting", "for", "response"}, expectedSearchArgs: []any{"waiting", "for", "response"},
}, },
{ {
name: "full-text-search-with-phrase-search", name: "full-text-search-with-phrase-search",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{},
query: `"waiting for response"`, query: `"waiting for response"`,
expectedSearchString: "WHERE (match(body, ?))", expectedSearchString: "WHERE (match(body, ?))",
expectedSearchArgs: []any{"waiting for response"}, expectedSearchArgs: []any{"waiting for response"},
}, },
{ {
name: "full-text-search-with-word-and-not-word", name: "full-text-search-with-word-and-not-word",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{},
query: "error NOT buggy_app", query: "error NOT buggy_app",
expectedSearchString: "WHERE ((match(body, ?)) AND NOT ((match(body, ?))))", expectedSearchString: "WHERE ((match(body, ?)) AND NOT ((match(body, ?))))",
expectedSearchArgs: []any{"error", "buggy_app"}, expectedSearchArgs: []any{"error", "buggy_app"},
}, },
{ {
name: "full-text-search-with-word-and-not-word-and-not-word", name: "full-text-search-with-word-and-not-word-and-not-word",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{},
query: "error NOT buggy_app NOT redis", query: "error NOT buggy_app NOT redis",
expectedSearchString: "WHERE ((match(body, ?)) AND NOT ((match(body, ?))) AND NOT ((match(body, ?))))", expectedSearchString: "WHERE ((match(body, ?)) AND NOT ((match(body, ?))) AND NOT ((match(body, ?))))",
expectedSearchArgs: []any{"error", "buggy_app", "redis"}, expectedSearchArgs: []any{"error", "buggy_app", "redis"},
}, },
{ {
name: "full-text-search-with-word-and-not-word-and-not-word-tricky", name: "full-text-search-with-word-and-not-word-and-not-word-tricky",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{},
query: "error NOT buggy_app OR redis", query: "error NOT buggy_app OR redis",
expectedSearchString: "WHERE (((match(body, ?)) AND NOT ((match(body, ?)))) OR (match(body, ?)))", expectedSearchString: "WHERE (((match(body, ?)) AND NOT ((match(body, ?)))) OR (match(body, ?)))",
expectedSearchArgs: []any{"error", "buggy_app", "redis"}, expectedSearchArgs: []any{"error", "buggy_app", "redis"},
}, },
{ {
name: "has-function", name: "has-function",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"service.name": { "service.name": {
{ {
Name: "service.name", Name: "service.name",
@ -305,14 +306,14 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
}, },
{ {
name: "has-from-list-of-values", name: "has-from-list-of-values",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{},
query: "has(body.payload.user_ids[*], 'u1292')", query: "has(body.payload.user_ids[*], 'u1292')",
expectedSearchString: "WHERE (has(JSONExtract(JSON_QUERY(body, '$.payload.user_ids[*]'), 'Array(String)'), ?))", expectedSearchString: "WHERE (has(JSONExtract(JSON_QUERY(body, '$.payload.user_ids[*]'), 'Array(String)'), ?))",
expectedSearchArgs: []any{"u1292"}, expectedSearchArgs: []any{"u1292"},
}, },
{ {
name: "body-json-search-that-also-has-attribute-with-same-name", name: "body-json-search-that-also-has-attribute-with-same-name",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"http.status_code": { "http.status_code": {
{ {
Name: "http.status_code", Name: "http.status_code",
@ -331,15 +332,18 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Logf("running test %s", c.name) t.Logf("running test %s", c.name)
chQuery, chQueryArgs, _, err := PrepareWhereClause(c.query, c.fieldKeys, telemetrylogs.NewConditionBuilder(), telemetrytypes.TelemetryFieldKey{ whereClause, _, err := PrepareWhereClause(c.query, c.fieldKeys, telemetrylogs.NewConditionBuilder(), &telemetrytypes.TelemetryFieldKey{
Name: "body", Name: "body",
Signal: telemetrytypes.SignalLogs, Signal: telemetrytypes.SignalLogs,
FieldContext: telemetrytypes.FieldContextLog, FieldContext: telemetrytypes.FieldContextLog,
FieldDataType: telemetrytypes.FieldDataTypeString, FieldDataType: telemetrytypes.FieldDataTypeString,
}) })
if err != nil { if err != nil {
t.Errorf("Error converting query to ClickHouse: %v", err) t.Errorf("Error converting query to ClickHouse: %v", err)
} }
chQuery, chQueryArgs := whereClause.BuildWithFlavor(sqlbuilder.ClickHouse)
if chQuery != c.expectedSearchString { if chQuery != c.expectedSearchString {
t.Errorf("Expected %s, got %s", c.expectedSearchString, chQuery) t.Errorf("Expected %s, got %s", c.expectedSearchString, chQuery)
} }
@ -355,14 +359,14 @@ func TestConvertToClickHouseLogsQuery(t *testing.T) {
func TestConvertToClickHouseSpansQuery(t *testing.T) { func TestConvertToClickHouseSpansQuery(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
fieldKeys map[string][]telemetrytypes.TelemetryFieldKey fieldKeys map[string][]*telemetrytypes.TelemetryFieldKey
query string query string
expectedSearchString string expectedSearchString string
expectedSearchArgs []any expectedSearchArgs []any
}{ }{
{ {
name: "test-simple-service-name-filter", name: "test-simple-service-name-filter",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"service.name": { "service.name": {
{ {
Name: "service.name", Name: "service.name",
@ -378,7 +382,7 @@ func TestConvertToClickHouseSpansQuery(t *testing.T) {
}, },
{ {
name: "test-simple-service-name-filter-with-materialised-column", name: "test-simple-service-name-filter-with-materialised-column",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"service.name": { "service.name": {
{ {
Name: "service.name", Name: "service.name",
@ -395,7 +399,7 @@ func TestConvertToClickHouseSpansQuery(t *testing.T) {
}, },
{ {
name: "http-status-code-multiple-data-types", name: "http-status-code-multiple-data-types",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"http.status_code": { "http.status_code": {
{ {
Name: "http.status_code", Name: "http.status_code",
@ -417,7 +421,7 @@ func TestConvertToClickHouseSpansQuery(t *testing.T) {
}, },
{ {
name: "http-status-code-multiple-data-types-between-operator", name: "http-status-code-multiple-data-types-between-operator",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"http.status_code": { "http.status_code": {
{ {
Name: "http.status_code", Name: "http.status_code",
@ -439,7 +443,7 @@ func TestConvertToClickHouseSpansQuery(t *testing.T) {
}, },
{ {
name: "response-body-multiple-data-types-string-contains", name: "response-body-multiple-data-types-string-contains",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"response.body": { "response.body": {
{ {
Name: "response.body", Name: "response.body",
@ -461,7 +465,7 @@ func TestConvertToClickHouseSpansQuery(t *testing.T) {
}, },
{ {
name: "collision-with-attribute-field-and-resource-attribute", name: "collision-with-attribute-field-and-resource-attribute",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"k8s.namespace.name": { "k8s.namespace.name": {
{ {
Name: "k8s.namespace.name", Name: "k8s.namespace.name",
@ -483,7 +487,7 @@ func TestConvertToClickHouseSpansQuery(t *testing.T) {
}, },
{ {
name: "collision-with-attribute-field-and-resource-attribute-materialised-column", name: "collision-with-attribute-field-and-resource-attribute-materialised-column",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"k8s.namespace.name": { "k8s.namespace.name": {
{ {
Name: "k8s.namespace.name", Name: "k8s.namespace.name",
@ -506,7 +510,7 @@ func TestConvertToClickHouseSpansQuery(t *testing.T) {
}, },
{ {
name: "boolean-collision-with-attribute-field-and-data-type-boolean", name: "boolean-collision-with-attribute-field-and-data-type-boolean",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"did_user_login": { "did_user_login": {
{ {
Name: "did_user_login", Name: "did_user_login",
@ -528,7 +532,7 @@ func TestConvertToClickHouseSpansQuery(t *testing.T) {
}, },
{ {
name: "regexp-search", name: "regexp-search",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{
"k8s.namespace.name": { "k8s.namespace.name": {
{ {
Name: "k8s.namespace.name", Name: "k8s.namespace.name",
@ -553,7 +557,7 @@ func TestConvertToClickHouseSpansQuery(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
chQuery, chQueryArgs, _, err := PrepareWhereClause(c.query, c.fieldKeys, telemetrytraces.NewConditionBuilder(), telemetrytypes.TelemetryFieldKey{ whereClause, _, err := PrepareWhereClause(c.query, c.fieldKeys, telemetrytraces.NewConditionBuilder(), &telemetrytypes.TelemetryFieldKey{
Name: "dummy", Name: "dummy",
Signal: telemetrytypes.SignalTraces, Signal: telemetrytypes.SignalTraces,
FieldContext: telemetrytypes.FieldContextSpan, FieldContext: telemetrytypes.FieldContextSpan,
@ -562,6 +566,9 @@ func TestConvertToClickHouseSpansQuery(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Error converting query to ClickHouse: %v", err) t.Errorf("Error converting query to ClickHouse: %v", err)
} }
chQuery, chQueryArgs := whereClause.BuildWithFlavor(sqlbuilder.ClickHouse)
if chQuery != c.expectedSearchString { if chQuery != c.expectedSearchString {
t.Errorf("Expected %s, got %s", c.expectedSearchString, chQuery) t.Errorf("Expected %s, got %s", c.expectedSearchString, chQuery)
} }
@ -577,7 +584,7 @@ func TestConvertToClickHouseSpansQuery(t *testing.T) {
func TestConvertToClickHouseSpansQueryWithErrors(t *testing.T) { func TestConvertToClickHouseSpansQueryWithErrors(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
fieldKeys map[string][]telemetrytypes.TelemetryFieldKey fieldKeys map[string][]*telemetrytypes.TelemetryFieldKey
query string query string
expectedSearchString string expectedSearchString string
expectedSearchArgs []any expectedSearchArgs []any
@ -586,7 +593,7 @@ func TestConvertToClickHouseSpansQueryWithErrors(t *testing.T) {
}{ }{
{ {
name: "has-function-with-multiple-values", name: "has-function-with-multiple-values",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{},
query: "key.that.does.not.exist = 'redis'", query: "key.that.does.not.exist = 'redis'",
expectedSearchString: "", expectedSearchString: "",
expectedSearchArgs: []any{}, expectedSearchArgs: []any{},
@ -595,7 +602,7 @@ func TestConvertToClickHouseSpansQueryWithErrors(t *testing.T) {
}, },
{ {
name: "unknown-function", name: "unknown-function",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{},
query: "unknown.function()", query: "unknown.function()",
expectedSearchString: "", expectedSearchString: "",
expectedSearchArgs: []any{}, expectedSearchArgs: []any{},
@ -604,7 +611,7 @@ func TestConvertToClickHouseSpansQueryWithErrors(t *testing.T) {
}, },
{ {
name: "has-function-not-enough-params", name: "has-function-not-enough-params",
fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, fieldKeys: map[string][]*telemetrytypes.TelemetryFieldKey{},
query: "has(key.that.does.not.exist)", query: "has(key.that.does.not.exist)",
expectedSearchString: "", expectedSearchString: "",
expectedSearchArgs: []any{}, expectedSearchArgs: []any{},
@ -614,7 +621,7 @@ func TestConvertToClickHouseSpansQueryWithErrors(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
_, _, warnings, err := PrepareWhereClause(c.query, c.fieldKeys, telemetrytraces.NewConditionBuilder(), telemetrytypes.TelemetryFieldKey{ _, warnings, err := PrepareWhereClause(c.query, c.fieldKeys, telemetrytraces.NewConditionBuilder(), &telemetrytypes.TelemetryFieldKey{
Name: "dummy", Name: "dummy",
Signal: telemetrytypes.SignalTraces, Signal: telemetrytypes.SignalTraces,
FieldContext: telemetrytypes.FieldContextSpan, FieldContext: telemetrytypes.FieldContextSpan,

View File

@ -80,6 +80,8 @@ func (c *conditionBuilder) GetCondition(
return "", nil return "", nil
} }
tblFieldName, value = telemetrytypes.DataTypeCollisionHandledFieldName(key, value, tblFieldName)
// key must exists to apply main filter // key must exists to apply main filter
containsExp := fmt.Sprintf("mapContains(%s, %s)", column.Name, sb.Var(key.Name)) containsExp := fmt.Sprintf("mapContains(%s, %s)", column.Name, sb.Var(key.Name))

View File

@ -3,9 +3,9 @@ package telemetrymetadata
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
"github.com/SigNoz/signoz/pkg/errors" "github.com/SigNoz/signoz/pkg/errors"
parser "github.com/SigNoz/signoz/pkg/parser/grammar"
"github.com/SigNoz/signoz/pkg/telemetrystore" "github.com/SigNoz/signoz/pkg/telemetrystore"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5" qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes" "github.com/SigNoz/signoz/pkg/types/telemetrytypes"
@ -28,7 +28,6 @@ type telemetryMetaStore struct {
indexV3TblName string indexV3TblName string
metricsDBName string metricsDBName string
metricsFieldsTblName string metricsFieldsTblName string
timeseries1WTblName string
logsDBName string logsDBName string
logsFieldsTblName string logsFieldsTblName string
logsV2TblName string logsV2TblName string
@ -45,7 +44,6 @@ func NewTelemetryMetaStore(
indexV3TblName string, indexV3TblName string,
metricsDBName string, metricsDBName string,
metricsFieldsTblName string, metricsFieldsTblName string,
timeseries1WTblName string,
logsDBName string, logsDBName string,
logsV2TblName string, logsV2TblName string,
logsFieldsTblName string, logsFieldsTblName string,
@ -53,13 +51,13 @@ func NewTelemetryMetaStore(
relatedMetadataTblName string, relatedMetadataTblName string,
) telemetrytypes.MetadataStore { ) telemetrytypes.MetadataStore {
return &telemetryMetaStore{ return &telemetryMetaStore{
telemetrystore: telemetrystore, telemetrystore: telemetrystore,
tracesDBName: tracesDBName, tracesDBName: tracesDBName,
tracesFieldsTblName: tracesFieldsTblName, tracesFieldsTblName: tracesFieldsTblName,
indexV3TblName: indexV3TblName, indexV3TblName: indexV3TblName,
metricsDBName: metricsDBName, metricsDBName: metricsDBName,
metricsFieldsTblName: metricsFieldsTblName, metricsFieldsTblName: metricsFieldsTblName,
timeseries1WTblName: timeseries1WTblName,
logsDBName: logsDBName, logsDBName: logsDBName,
logsV2TblName: logsV2TblName, logsV2TblName: logsV2TblName,
logsFieldsTblName: logsFieldsTblName, logsFieldsTblName: logsFieldsTblName,
@ -79,7 +77,16 @@ func (t *telemetryMetaStore) tracesTblStatementToFieldKeys(ctx context.Context)
return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, ErrFailedToGetTblStatement.Error()) return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, ErrFailedToGetTblStatement.Error())
} }
return ExtractFieldKeysFromTblStatement(statements[0].Statement) materialisedKeys, err := ExtractFieldKeysFromTblStatement(statements[0].Statement)
if err != nil {
return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, ErrFailedToGetTracesKeys.Error())
}
for idx := range materialisedKeys {
materialisedKeys[idx].Signal = telemetrytypes.SignalTraces
}
return materialisedKeys, nil
} }
// getTracesKeys returns the keys from the spans that match the field selection criteria // getTracesKeys returns the keys from the spans that match the field selection criteria
@ -175,6 +182,7 @@ func (t *telemetryMetaStore) getTracesKeys(ctx context.Context, fieldKeySelector
if !ok { if !ok {
key = &telemetrytypes.TelemetryFieldKey{ key = &telemetrytypes.TelemetryFieldKey{
Name: name, Name: name,
Signal: telemetrytypes.SignalTraces,
FieldContext: fieldContext, FieldContext: fieldContext,
FieldDataType: fieldDataType, FieldDataType: fieldDataType,
} }
@ -199,7 +207,16 @@ func (t *telemetryMetaStore) logsTblStatementToFieldKeys(ctx context.Context) ([
return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, ErrFailedToGetTblStatement.Error()) return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, ErrFailedToGetTblStatement.Error())
} }
return ExtractFieldKeysFromTblStatement(statements[0].Statement) materialisedKeys, err := ExtractFieldKeysFromTblStatement(statements[0].Statement)
if err != nil {
return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, ErrFailedToGetLogsKeys.Error())
}
for idx := range materialisedKeys {
materialisedKeys[idx].Signal = telemetrytypes.SignalLogs
}
return materialisedKeys, nil
} }
// getLogsKeys returns the keys from the spans that match the field selection criteria // getLogsKeys returns the keys from the spans that match the field selection criteria
@ -293,6 +310,7 @@ func (t *telemetryMetaStore) getLogsKeys(ctx context.Context, fieldKeySelectors
if !ok { if !ok {
key = &telemetrytypes.TelemetryFieldKey{ key = &telemetrytypes.TelemetryFieldKey{
Name: name, Name: name,
Signal: telemetrytypes.SignalLogs,
FieldContext: fieldContext, FieldContext: fieldContext,
FieldDataType: fieldDataType, FieldDataType: fieldDataType,
} }
@ -309,52 +327,60 @@ func (t *telemetryMetaStore) getLogsKeys(ctx context.Context, fieldKeySelectors
} }
// getMetricsKeys returns the keys from the metrics that match the field selection criteria // getMetricsKeys returns the keys from the metrics that match the field selection criteria
// TODO(srikanthccv): update the implementation after the dot metrics migration is done
func (t *telemetryMetaStore) getMetricsKeys(ctx context.Context, fieldKeySelectors []*telemetrytypes.FieldKeySelector) ([]*telemetrytypes.TelemetryFieldKey, error) { func (t *telemetryMetaStore) getMetricsKeys(ctx context.Context, fieldKeySelectors []*telemetrytypes.FieldKeySelector) ([]*telemetrytypes.TelemetryFieldKey, error) {
if len(fieldKeySelectors) == 0 { if len(fieldKeySelectors) == 0 {
return nil, nil return nil, nil
} }
var whereClause, innerWhereClause string sb := sqlbuilder.
Select("attr_name as name", "attr_type as field_context", "attr_datatype as field_data_type", `
CASE
WHEN attr_type = 'resource' THEN 1
WHEN attr_type = 'scope' THEN 2
WHEN attr_type = 'point' THEN 3
ELSE 4
END as priority`).
From(t.metricsDBName + "." + t.metricsFieldsTblName)
var limit int var limit int
args := []any{}
conds := []string{}
for _, fieldKeySelector := range fieldKeySelectors { for _, fieldKeySelector := range fieldKeySelectors {
if fieldKeySelector.MetricContext != nil { fieldConds := []string{}
innerWhereClause += "metric_name IN ? AND"
args = append(args, fieldKeySelector.MetricContext.MetricName)
}
}
innerWhereClause += " __normalized = true"
for idx, fieldKeySelector := range fieldKeySelectors {
if fieldKeySelector.SelectorMatchType == telemetrytypes.FieldSelectorMatchTypeExact { if fieldKeySelector.SelectorMatchType == telemetrytypes.FieldSelectorMatchTypeExact {
whereClause += "(distinctTagKey = ? AND distinctTagKey NOT LIKE '\\_\\_%%')" fieldConds = append(fieldConds, sb.E("attr_name", fieldKeySelector.Name))
args = append(args, fieldKeySelector.Name)
} else { } else {
whereClause += "(distinctTagKey ILIKE ? AND distinctTagKey NOT LIKE '\\_\\_%%')" fieldConds = append(fieldConds, sb.Like("attr_name", "%"+fieldKeySelector.Name+"%"))
args = append(args, fmt.Sprintf("%%%s%%", fieldKeySelector.Name))
} }
if idx != len(fieldKeySelectors)-1 {
whereClause += " OR " if fieldKeySelector.FieldContext != telemetrytypes.FieldContextUnspecified {
fieldConds = append(fieldConds, sb.E("attr_type", fieldKeySelector.FieldContext.TagType()))
} }
if fieldKeySelector.FieldDataType != telemetrytypes.FieldDataTypeUnspecified {
fieldConds = append(fieldConds, sb.E("attr_datatype", fieldKeySelector.FieldDataType.TagDataType()))
}
if fieldKeySelector.MetricContext != nil {
fieldConds = append(fieldConds, sb.E("metric_name", fieldKeySelector.MetricContext.MetricName))
}
conds = append(conds, sb.And(fieldConds...))
limit += fieldKeySelector.Limit limit += fieldKeySelector.Limit
} }
args = append(args, limit) sb.Where(sb.Or(conds...))
query := fmt.Sprintf(` if limit == 0 {
SELECT limit = 1000
arrayJoin(tagKeys) AS distinctTagKey }
FROM (
SELECT JSONExtractKeys(labels) AS tagKeys mainSb := sqlbuilder.Select("name", "field_context", "field_data_type", "max(priority) as priority")
FROM %s.%s mainSb.From(mainSb.BuilderAs(sb, "sub_query"))
WHERE `+innerWhereClause+` mainSb.GroupBy("name", "field_context", "field_data_type")
GROUP BY tagKeys mainSb.OrderBy("priority")
) mainSb.Limit(limit)
WHERE `+whereClause+`
GROUP BY distinctTagKey query, args := mainSb.BuildWithFlavor(sqlbuilder.ClickHouse)
LIMIT ?
`, t.metricsDBName, t.timeseries1WTblName)
rows, err := t.telemetrystore.ClickhouseDB().Query(ctx, query, args...) rows, err := t.telemetrystore.ClickhouseDB().Query(ctx, query, args...)
if err != nil { if err != nil {
@ -365,16 +391,19 @@ func (t *telemetryMetaStore) getMetricsKeys(ctx context.Context, fieldKeySelecto
keys := []*telemetrytypes.TelemetryFieldKey{} keys := []*telemetrytypes.TelemetryFieldKey{}
for rows.Next() { for rows.Next() {
var name string var name string
err = rows.Scan(&name) var fieldContext telemetrytypes.FieldContext
var fieldDataType telemetrytypes.FieldDataType
var priority uint8
err = rows.Scan(&name, &fieldContext, &fieldDataType, &priority)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, ErrFailedToGetMetricsKeys.Error()) return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, ErrFailedToGetMetricsKeys.Error())
} }
key := &telemetrytypes.TelemetryFieldKey{ keys = append(keys, &telemetrytypes.TelemetryFieldKey{
Name: name, Name: name,
FieldContext: telemetrytypes.FieldContextAttribute, Signal: telemetrytypes.SignalMetrics,
FieldDataType: telemetrytypes.FieldDataTypeString, FieldContext: fieldContext,
} FieldDataType: fieldDataType,
keys = append(keys, key) })
} }
if rows.Err() != nil { if rows.Err() != nil {
@ -486,20 +515,10 @@ func (t *telemetryMetaStore) GetKey(ctx context.Context, fieldKeySelector *telem
func (t *telemetryMetaStore) getRelatedValues(ctx context.Context, fieldValueSelector *telemetrytypes.FieldValueSelector) ([]string, error) { func (t *telemetryMetaStore) getRelatedValues(ctx context.Context, fieldValueSelector *telemetrytypes.FieldValueSelector) ([]string, error) {
args := []any{} // nothing to return as "related" value if there is nothing to filter on
if fieldValueSelector.ExistingQuery == "" {
var andConditions []string return nil, nil
andConditions = append(andConditions, `unix_milli >= ?`)
args = append(args, fieldValueSelector.StartUnixMilli)
andConditions = append(andConditions, `unix_milli <= ?`)
args = append(args, fieldValueSelector.EndUnixMilli)
if len(fieldValueSelector.ExistingQuery) != 0 {
// TODO(srikanthccv): add the existing query to the where clause
} }
whereClause := strings.Join(andConditions, " AND ")
key := telemetrytypes.TelemetryFieldKey{ key := telemetrytypes.TelemetryFieldKey{
Name: fieldValueSelector.Name, Name: fieldValueSelector.Name,
@ -508,20 +527,65 @@ func (t *telemetryMetaStore) getRelatedValues(ctx context.Context, fieldValueSel
FieldDataType: fieldValueSelector.FieldDataType, FieldDataType: fieldValueSelector.FieldDataType,
} }
// TODO(srikanthccv): add the select column selectColumn, err := t.conditionBuilder.GetTableFieldName(ctx, &key)
selectColumn, _ := t.conditionBuilder.GetTableFieldName(ctx, &key)
args = append(args, fieldValueSelector.Limit) if err != nil {
filterSubQuery := fmt.Sprintf( // we don't have a explicit column to select from the related metadata table
"SELECT DISTINCT %s FROM %s.%s WHERE %s LIMIT ?", // so we will select either from resource_attributes or attributes table
selectColumn, // in that order
t.relatedMetadataDBName, resourceColumn, _ := t.conditionBuilder.GetTableFieldName(ctx, &telemetrytypes.TelemetryFieldKey{
t.relatedMetadataTblName, Name: key.Name,
whereClause, FieldContext: telemetrytypes.FieldContextResource,
) FieldDataType: telemetrytypes.FieldDataTypeString,
zap.L().Debug("filterSubQuery for related values", zap.String("query", filterSubQuery), zap.Any("args", args)) })
attributeColumn, _ := t.conditionBuilder.GetTableFieldName(ctx, &telemetrytypes.TelemetryFieldKey{
Name: key.Name,
FieldContext: telemetrytypes.FieldContextAttribute,
FieldDataType: telemetrytypes.FieldDataTypeString,
})
selectColumn = fmt.Sprintf("if(notEmpty(%s), %s, %s)", resourceColumn, resourceColumn, attributeColumn)
}
rows, err := t.telemetrystore.ClickhouseDB().Query(ctx, filterSubQuery, args...) sb := sqlbuilder.Select("DISTINCT " + selectColumn).From(t.relatedMetadataDBName + "." + t.relatedMetadataTblName)
if len(fieldValueSelector.ExistingQuery) != 0 {
keysSelectors, err := parser.QueryStringToKeysSelectors(fieldValueSelector.ExistingQuery)
if err == nil {
for idx := range keysSelectors {
keysSelectors[idx].Signal = fieldValueSelector.Signal
}
keys, err := t.GetKeysMulti(ctx, keysSelectors)
if err == nil {
whereClause, _, err := parser.PrepareWhereClause(fieldValueSelector.ExistingQuery, keys, t.conditionBuilder, &telemetrytypes.TelemetryFieldKey{})
if err == nil {
sb.AddWhereClause(whereClause)
} else {
zap.L().Warn("error parsing existing query for related values", zap.Error(err))
}
}
}
}
if fieldValueSelector.StartUnixMilli != 0 {
sb.Where(sb.GE("unix_milli", fieldValueSelector.StartUnixMilli))
}
if fieldValueSelector.EndUnixMilli != 0 {
sb.Where(sb.LE("unix_milli", fieldValueSelector.EndUnixMilli))
}
if fieldValueSelector.Limit != 0 {
sb.Limit(fieldValueSelector.Limit)
} else {
sb.Limit(50)
}
query, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
zap.L().Debug("query for related values", zap.String("query", query), zap.Any("args", args))
rows, err := t.telemetrystore.ClickhouseDB().Query(ctx, query, args...)
if err != nil { if err != nil {
return nil, ErrFailedToGetRelatedValues return nil, ErrFailedToGetRelatedValues
} }
@ -668,9 +732,66 @@ func (t *telemetryMetaStore) getLogFieldValues(ctx context.Context, fieldValueSe
return values, nil return values, nil
} }
func (t *telemetryMetaStore) getMetricFieldValues(_ context.Context, fieldValueSelector *telemetrytypes.FieldValueSelector) (*telemetrytypes.TelemetryFieldValues, error) { func (t *telemetryMetaStore) getMetricFieldValues(ctx context.Context, fieldValueSelector *telemetrytypes.FieldValueSelector) (*telemetrytypes.TelemetryFieldValues, error) {
// TODO(srikanthccv): implement this. use new tables? sb := sqlbuilder.
return nil, nil Select("DISTINCT attr_string_value").
From(t.metricsDBName + "." + t.metricsFieldsTblName)
if fieldValueSelector.Name != "" {
sb.Where(sb.E("attr_name", fieldValueSelector.Name))
}
if fieldValueSelector.FieldContext != telemetrytypes.FieldContextUnspecified {
sb.And(sb.E("attr_type", fieldValueSelector.FieldContext.TagType()))
}
if fieldValueSelector.FieldDataType != telemetrytypes.FieldDataTypeUnspecified {
sb.And(sb.E("attr_datatype", fieldValueSelector.FieldDataType.TagDataType()))
}
if fieldValueSelector.MetricContext != nil {
sb.And(sb.E("metric_name", fieldValueSelector.MetricContext.MetricName))
}
if fieldValueSelector.StartUnixMilli > 0 {
sb.And(sb.GE("last_reported_unix_milli", fieldValueSelector.StartUnixMilli))
}
if fieldValueSelector.EndUnixMilli > 0 {
sb.And(sb.LE("first_reported_unix_milli", fieldValueSelector.EndUnixMilli))
}
if fieldValueSelector.Value != "" {
if fieldValueSelector.SelectorMatchType == telemetrytypes.FieldSelectorMatchTypeExact {
sb.And(sb.E("attr_string_value", fieldValueSelector.Value))
} else {
sb.And(sb.Like("attr_string_value", "%"+fieldValueSelector.Value+"%"))
}
}
if fieldValueSelector.Limit > 0 {
sb.Limit(fieldValueSelector.Limit)
} else {
sb.Limit(50)
}
query, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
rows, err := t.telemetrystore.ClickhouseDB().Query(ctx, query, args...)
if err != nil {
return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, ErrFailedToGetMetricsKeys.Error())
}
defer rows.Close()
values := &telemetrytypes.TelemetryFieldValues{}
for rows.Next() {
var stringValue string
if err := rows.Scan(&stringValue); err != nil {
return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, ErrFailedToGetMetricsKeys.Error())
}
values.StringValues = append(values.StringValues, stringValue)
}
return values, nil
} }
func (t *telemetryMetaStore) GetAllValues(ctx context.Context, fieldValueSelector *telemetrytypes.FieldValueSelector) (*telemetrytypes.TelemetryFieldValues, error) { func (t *telemetryMetaStore) GetAllValues(ctx context.Context, fieldValueSelector *telemetrytypes.FieldValueSelector) (*telemetrytypes.TelemetryFieldValues, error) {

View File

@ -39,8 +39,7 @@ func TestGetKeys(t *testing.T) {
telemetrytraces.TagAttributesV2TableName, telemetrytraces.TagAttributesV2TableName,
telemetrytraces.SpanIndexV3TableName, telemetrytraces.SpanIndexV3TableName,
telemetrymetrics.DBName, telemetrymetrics.DBName,
telemetrymetrics.TimeseriesV41weekTableName, telemetrymetrics.AttributesMetadataTableName,
telemetrymetrics.TimeseriesV41weekTableName,
telemetrylogs.DBName, telemetrylogs.DBName,
telemetrylogs.LogsV2TableName, telemetrylogs.LogsV2TableName,
telemetrylogs.TagAttributesV2TableName, telemetrylogs.TagAttributesV2TableName,

View File

@ -18,4 +18,6 @@ const (
TimeseriesV41dayLocalTableName = "time_series_v4_1day" TimeseriesV41dayLocalTableName = "time_series_v4_1day"
TimeseriesV41weekTableName = "distributed_time_series_v4_1week" TimeseriesV41weekTableName = "distributed_time_series_v4_1week"
TimeseriesV41weekLocalTableName = "time_series_v4_1week" TimeseriesV41weekLocalTableName = "time_series_v4_1week"
AttributesMetadataTableName = "distributed_metadata"
AttributesMetadataLocalTableName = "metadata"
) )