chore: add tag type filter support in attribute keys (#7522)

This commit is contained in:
Srikanth Chekuri 2025-04-14 18:43:15 +05:30 committed by GitHub
parent 5dd02a5b8e
commit c3fa7144ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 83 additions and 17 deletions

View File

@ -3928,11 +3928,16 @@ func (r *ClickHouseReader) GetLogAttributeKeys(ctx context.Context, req *v3.Filt
var rows driver.Rows var rows driver.Rows
var response v3.FilterAttributeKeyResponse var response v3.FilterAttributeKeyResponse
tagTypeFilter := `tag_type != 'logfield'`
if req.TagType != "" {
tagTypeFilter = fmt.Sprintf(`tag_type != 'logfield' and tag_type = '%s'`, req.TagType)
}
if len(req.SearchText) != 0 { if len(req.SearchText) != 0 {
query = fmt.Sprintf("select distinct tag_key, tag_type, tag_data_type from %s.%s where tag_type != 'logfield' and tag_key ILIKE $1 limit $2", r.logsDB, r.logsTagAttributeTableV2) query = fmt.Sprintf("select distinct tag_key, tag_type, tag_data_type from %s.%s where %s and tag_key ILIKE $1 limit $2", r.logsDB, r.logsTagAttributeTableV2, tagTypeFilter)
rows, err = r.db.Query(ctx, query, fmt.Sprintf("%%%s%%", req.SearchText), req.Limit) rows, err = r.db.Query(ctx, query, fmt.Sprintf("%%%s%%", req.SearchText), req.Limit)
} else { } else {
query = fmt.Sprintf("select distinct tag_key, tag_type, tag_data_type from %s.%s where tag_type != 'logfield' limit $1", r.logsDB, r.logsTagAttributeTableV2) query = fmt.Sprintf("select distinct tag_key, tag_type, tag_data_type from %s.%s where %s limit $1", r.logsDB, r.logsTagAttributeTableV2, tagTypeFilter)
rows, err = r.db.Query(ctx, query, req.Limit) rows, err = r.db.Query(ctx, query, req.Limit)
} }
@ -3967,7 +3972,9 @@ func (r *ClickHouseReader) GetLogAttributeKeys(ctx context.Context, req *v3.Filt
response.AttributeKeys = append(response.AttributeKeys, key) response.AttributeKeys = append(response.AttributeKeys, key)
} }
// add other attributes // add other attributes only when the tagType is not specified
// i.e retrieve all attributes
if req.TagType == "" {
for _, f := range constants.StaticFieldsLogsV3 { for _, f := range constants.StaticFieldsLogsV3 {
if (v3.AttributeKey{} == f) { if (v3.AttributeKey{} == f) {
continue continue
@ -3976,6 +3983,7 @@ func (r *ClickHouseReader) GetLogAttributeKeys(ctx context.Context, req *v3.Filt
response.AttributeKeys = append(response.AttributeKeys, f) response.AttributeKeys = append(response.AttributeKeys, f)
} }
} }
}
return &response, nil return &response, nil
} }
@ -4715,7 +4723,12 @@ func (r *ClickHouseReader) GetTraceAttributeKeys(ctx context.Context, req *v3.Fi
var rows driver.Rows var rows driver.Rows
var response v3.FilterAttributeKeyResponse var response v3.FilterAttributeKeyResponse
query = fmt.Sprintf("SELECT DISTINCT(tag_key), tag_type, tag_data_type FROM %s.%s WHERE tag_key ILIKE $1 and tag_type != 'spanfield' LIMIT $2", r.TraceDB, r.spanAttributeTableV2) tagTypeFilter := `tag_type != 'spanfield'`
if req.TagType != "" {
tagTypeFilter = fmt.Sprintf(`tag_type != 'spanfield' and tag_type = '%s'`, req.TagType)
}
query = fmt.Sprintf("SELECT DISTINCT(tag_key), tag_type, tag_data_type FROM %s.%s WHERE tag_key ILIKE $1 and %s LIMIT $2", r.TraceDB, r.spanAttributeTableV2, tagTypeFilter)
rows, err = r.db.Query(ctx, query, fmt.Sprintf("%%%s%%", req.SearchText), req.Limit) rows, err = r.db.Query(ctx, query, fmt.Sprintf("%%%s%%", req.SearchText), req.Limit)
@ -4760,7 +4773,9 @@ func (r *ClickHouseReader) GetTraceAttributeKeys(ctx context.Context, req *v3.Fi
fields = constants.DeprecatedStaticFieldsTraces fields = constants.DeprecatedStaticFieldsTraces
} }
// add the new static fields // add the new static fields only when the tagType is not specified
// i.e retrieve all attributes
if req.TagType == "" {
for _, f := range fields { for _, f := range fields {
if (v3.AttributeKey{} == f) { if (v3.AttributeKey{} == f) {
continue continue
@ -4769,6 +4784,7 @@ func (r *ClickHouseReader) GetTraceAttributeKeys(ctx context.Context, req *v3.Fi
response.AttributeKeys = append(response.AttributeKeys, f) response.AttributeKeys = append(response.AttributeKeys, f)
} }
} }
}
return &response, nil return &response, nil
} }

View File

@ -719,6 +719,21 @@ func parseFilterAttributeKeyRequest(r *http.Request) (*v3.FilterAttributeKeyRequ
aggregateOperator := v3.AggregateOperator(r.URL.Query().Get("aggregateOperator")) aggregateOperator := v3.AggregateOperator(r.URL.Query().Get("aggregateOperator"))
aggregateAttribute := r.URL.Query().Get("aggregateAttribute") aggregateAttribute := r.URL.Query().Get("aggregateAttribute")
limit, err := strconv.Atoi(r.URL.Query().Get("limit")) limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
tagType := v3.TagType(r.URL.Query().Get("tagType"))
// empty string is a valid tagType
// i.e retrieve all attributes
if tagType != "" {
// what is happening here?
// if tagType is undefined(uh oh javascript) or any invalid value, set it to empty string
// instead of failing the request. Ideally, we should fail the request.
// but we are not doing that to maintain backward compatibility.
if err := tagType.Validate(); err != nil {
// if the tagType is invalid, set it to empty string
tagType = ""
}
}
if err != nil { if err != nil {
limit = 50 limit = 50
} }
@ -739,6 +754,7 @@ func parseFilterAttributeKeyRequest(r *http.Request) (*v3.FilterAttributeKeyRequ
AggregateAttribute: aggregateAttribute, AggregateAttribute: aggregateAttribute,
Limit: limit, Limit: limit,
SearchText: r.URL.Query().Get("searchText"), SearchText: r.URL.Query().Get("searchText"),
TagType: tagType,
} }
return &req, nil return &req, nil
} }

View File

@ -112,6 +112,7 @@ func TestParseFilterAttributeKeyRequest(t *testing.T) {
expectedSearchText string expectedSearchText string
expectErr bool expectErr bool
errMsg string errMsg string
expectedTagType v3.TagType
}{ }{
{ {
desc: "valid operator and data source", desc: "valid operator and data source",
@ -168,6 +169,38 @@ func TestParseFilterAttributeKeyRequest(t *testing.T) {
expectedDataSource: v3.DataSourceTraces, expectedDataSource: v3.DataSourceTraces,
expectedLimit: 50, expectedLimit: 50,
}, },
{
desc: "invalid tag type",
queryString: "aggregateOperator=avg&dataSource=traces&tagType=invalid",
expectedOperator: v3.AggregateOperatorAvg,
expectedDataSource: v3.DataSourceTraces,
expectedTagType: "",
expectedLimit: 50,
},
{
desc: "valid tag type",
queryString: "aggregateOperator=avg&dataSource=traces&tagType=resource",
expectedOperator: v3.AggregateOperatorAvg,
expectedDataSource: v3.DataSourceTraces,
expectedTagType: v3.TagTypeResource,
expectedLimit: 50,
},
{
desc: "valid tag type",
queryString: "aggregateOperator=avg&dataSource=traces&tagType=scope",
expectedOperator: v3.AggregateOperatorAvg,
expectedDataSource: v3.DataSourceTraces,
expectedTagType: v3.TagTypeInstrumentationScope,
expectedLimit: 50,
},
{
desc: "valid tag type",
queryString: "aggregateOperator=avg&dataSource=traces&tagType=tag",
expectedOperator: v3.AggregateOperatorAvg,
expectedDataSource: v3.DataSourceTraces,
expectedTagType: v3.TagTypeTag,
expectedLimit: 50,
},
} }
for _, reqCase := range reqCases { for _, reqCase := range reqCases {

View File

@ -248,6 +248,7 @@ func (q TagType) Validate() error {
type FilterAttributeKeyRequest struct { type FilterAttributeKeyRequest struct {
DataSource DataSource `json:"dataSource"` DataSource DataSource `json:"dataSource"`
AggregateOperator AggregateOperator `json:"aggregateOperator"` AggregateOperator AggregateOperator `json:"aggregateOperator"`
TagType TagType `json:"tagType"`
AggregateAttribute string `json:"aggregateAttribute"` AggregateAttribute string `json:"aggregateAttribute"`
SearchText string `json:"searchText"` SearchText string `json:"searchText"`
Limit int `json:"limit"` Limit int `json:"limit"`