chore: less strict context for fetching field values (#7807)

This commit is contained in:
Srikanth Chekuri 2025-05-15 19:59:40 +05:30 committed by GitHub
parent b8dff86a56
commit 9fbf111976
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 83 additions and 29 deletions

View File

@ -75,7 +75,8 @@ func (c *conditionBuilder) GetCondition(
return "", nil return "", nil
} }
if key.FieldDataType != telemetrytypes.FieldDataTypeString { if key.FieldDataType != telemetrytypes.FieldDataTypeString &&
key.FieldDataType != telemetrytypes.FieldDataTypeUnspecified {
// if the field data type is not string, we can't build a condition for related values // if the field data type is not string, we can't build a condition for related values
return "", nil return "", nil
} }
@ -83,37 +84,37 @@ func (c *conditionBuilder) GetCondition(
tblFieldName, value = telemetrytypes.DataTypeCollisionHandledFieldName(key, value, tblFieldName) 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)) expr := `if(mapContains(%s, %s), %s, true)`
var cond string
// regular operators // regular operators
switch operator { switch operator {
// regular operators // regular operators
case qbtypes.FilterOperatorEqual: case qbtypes.FilterOperatorEqual:
return sb.And(containsExp, sb.E(tblFieldName, value)), nil cond = sb.E(tblFieldName, value)
case qbtypes.FilterOperatorNotEqual: case qbtypes.FilterOperatorNotEqual:
return sb.And(containsExp, sb.NE(tblFieldName, value)), nil cond = sb.NE(tblFieldName, value)
// like and not like // like and not like
case qbtypes.FilterOperatorLike: case qbtypes.FilterOperatorLike:
return sb.And(containsExp, sb.Like(tblFieldName, value)), nil cond = sb.Like(tblFieldName, value)
case qbtypes.FilterOperatorNotLike: case qbtypes.FilterOperatorNotLike:
return sb.And(containsExp, sb.NotLike(tblFieldName, value)), nil cond = sb.NotLike(tblFieldName, value)
case qbtypes.FilterOperatorILike: case qbtypes.FilterOperatorILike:
return sb.And(containsExp, sb.ILike(tblFieldName, value)), nil cond = sb.ILike(tblFieldName, value)
case qbtypes.FilterOperatorNotILike: case qbtypes.FilterOperatorNotILike:
return sb.And(containsExp, sb.NotILike(tblFieldName, value)), nil cond = sb.NotILike(tblFieldName, value)
case qbtypes.FilterOperatorContains: case qbtypes.FilterOperatorContains:
return sb.And(containsExp, sb.ILike(tblFieldName, fmt.Sprintf("%%%s%%", value))), nil cond = sb.ILike(tblFieldName, fmt.Sprintf("%%%s%%", value))
case qbtypes.FilterOperatorNotContains: case qbtypes.FilterOperatorNotContains:
return sb.And(containsExp, sb.NotILike(tblFieldName, fmt.Sprintf("%%%s%%", value))), nil cond = sb.NotILike(tblFieldName, fmt.Sprintf("%%%s%%", value))
case qbtypes.FilterOperatorRegexp: case qbtypes.FilterOperatorRegexp:
exp := fmt.Sprintf(`match(%s, %s)`, tblFieldName, sb.Var(value)) cond = fmt.Sprintf(`match(%s, %s)`, tblFieldName, sb.Var(value))
return sb.And(containsExp, exp), nil
case qbtypes.FilterOperatorNotRegexp: case qbtypes.FilterOperatorNotRegexp:
exp := fmt.Sprintf(`not match(%s, %s)`, tblFieldName, sb.Var(value)) cond = fmt.Sprintf(`not match(%s, %s)`, tblFieldName, sb.Var(value))
return sb.And(containsExp, exp), nil
// in and not in // in and not in
case qbtypes.FilterOperatorIn: case qbtypes.FilterOperatorIn:
@ -121,13 +122,13 @@ func (c *conditionBuilder) GetCondition(
if !ok { if !ok {
return "", qbtypes.ErrInValues return "", qbtypes.ErrInValues
} }
return sb.And(containsExp, sb.In(tblFieldName, values...)), nil cond = sb.In(tblFieldName, values...)
case qbtypes.FilterOperatorNotIn: case qbtypes.FilterOperatorNotIn:
values, ok := value.([]any) values, ok := value.([]any)
if !ok { if !ok {
return "", qbtypes.ErrInValues return "", qbtypes.ErrInValues
} }
return sb.And(containsExp, sb.NotIn(tblFieldName, values...)), nil cond = sb.NotIn(tblFieldName, values...)
// exists and not exists // exists and not exists
// in the query builder, `exists` and `not exists` are used for // in the query builder, `exists` and `not exists` are used for
@ -140,12 +141,12 @@ func (c *conditionBuilder) GetCondition(
}: }:
leftOperand := fmt.Sprintf("mapContains(%s, '%s')", column.Name, key.Name) leftOperand := fmt.Sprintf("mapContains(%s, '%s')", column.Name, key.Name)
if operator == qbtypes.FilterOperatorExists { if operator == qbtypes.FilterOperatorExists {
return sb.E(leftOperand, true), nil cond = sb.E(leftOperand, true)
} else { } else {
return sb.NE(leftOperand, true), nil cond = sb.NE(leftOperand, true)
} }
} }
} }
return "", nil return fmt.Sprintf(expr, column.Name, sb.Var(key.Name), cond), nil
} }

View File

@ -237,7 +237,7 @@ func TestGetCondition(t *testing.T) {
}, },
operator: qbtypes.FilterOperatorILike, operator: qbtypes.FilterOperatorILike,
value: "%admin%", value: "%admin%",
expectedSQL: "WHERE (mapContains(attributes, ?) AND LOWER(attributes['user.id']) LIKE LOWER(?))", expectedSQL: "WHERE if(mapContains(attributes, ?), LOWER(attributes['user.id']) LIKE LOWER(?), true)",
expectedError: nil, expectedError: nil,
}, },
{ {
@ -249,7 +249,7 @@ func TestGetCondition(t *testing.T) {
}, },
operator: qbtypes.FilterOperatorNotILike, operator: qbtypes.FilterOperatorNotILike,
value: "%admin%", value: "%admin%",
expectedSQL: "WHERE (mapContains(attributes, ?) AND LOWER(attributes['user.id']) NOT LIKE LOWER(?))", expectedSQL: "WHERE if(mapContains(attributes, ?), LOWER(attributes['user.id']) NOT LIKE LOWER(?), true)",
expectedError: nil, expectedError: nil,
}, },
} }

View File

@ -635,6 +635,12 @@ func (t *telemetryMetaStore) getSpanFieldValues(ctx context.Context, fieldValueS
} else if fieldValueSelector.FieldDataType == telemetrytypes.FieldDataTypeNumber { } else if fieldValueSelector.FieldDataType == telemetrytypes.FieldDataTypeNumber {
sb.Where(sb.IsNotNull("number_value")) sb.Where(sb.IsNotNull("number_value"))
sb.Where(sb.Like("toString(number_value)", "%"+fieldValueSelector.Value+"%")) sb.Where(sb.Like("toString(number_value)", "%"+fieldValueSelector.Value+"%"))
} else if fieldValueSelector.FieldDataType == telemetrytypes.FieldDataTypeUnspecified {
// or b/w string and number
sb.Where(sb.Or(
sb.Like("string_value", "%"+fieldValueSelector.Value+"%"),
sb.Like("toString(number_value)", "%"+fieldValueSelector.Value+"%"),
))
} }
} }
@ -696,6 +702,12 @@ func (t *telemetryMetaStore) getLogFieldValues(ctx context.Context, fieldValueSe
} else if fieldValueSelector.FieldDataType == telemetrytypes.FieldDataTypeNumber { } else if fieldValueSelector.FieldDataType == telemetrytypes.FieldDataTypeNumber {
sb.Where(sb.IsNotNull("number_value")) sb.Where(sb.IsNotNull("number_value"))
sb.Where(sb.Like("toString(number_value)", "%"+fieldValueSelector.Value+"%")) sb.Where(sb.Like("toString(number_value)", "%"+fieldValueSelector.Value+"%"))
} else if fieldValueSelector.FieldDataType == telemetrytypes.FieldDataTypeUnspecified {
// or b/w string and number
sb.Where(sb.Or(
sb.Like("string_value", "%"+fieldValueSelector.Value+"%"),
sb.Like("toString(number_value)", "%"+fieldValueSelector.Value+"%"),
))
} }
} }
@ -742,30 +754,30 @@ func (t *telemetryMetaStore) getMetricFieldValues(ctx context.Context, fieldValu
} }
if fieldValueSelector.FieldContext != telemetrytypes.FieldContextUnspecified { if fieldValueSelector.FieldContext != telemetrytypes.FieldContextUnspecified {
sb.And(sb.E("attr_type", fieldValueSelector.FieldContext.TagType())) sb.Where(sb.E("attr_type", fieldValueSelector.FieldContext.TagType()))
} }
if fieldValueSelector.FieldDataType != telemetrytypes.FieldDataTypeUnspecified { if fieldValueSelector.FieldDataType != telemetrytypes.FieldDataTypeUnspecified {
sb.And(sb.E("attr_datatype", fieldValueSelector.FieldDataType.TagDataType())) sb.Where(sb.E("attr_datatype", fieldValueSelector.FieldDataType.TagDataType()))
} }
if fieldValueSelector.MetricContext != nil { if fieldValueSelector.MetricContext != nil {
sb.And(sb.E("metric_name", fieldValueSelector.MetricContext.MetricName)) sb.Where(sb.E("metric_name", fieldValueSelector.MetricContext.MetricName))
} }
if fieldValueSelector.StartUnixMilli > 0 { if fieldValueSelector.StartUnixMilli > 0 {
sb.And(sb.GE("last_reported_unix_milli", fieldValueSelector.StartUnixMilli)) sb.Where(sb.GE("last_reported_unix_milli", fieldValueSelector.StartUnixMilli))
} }
if fieldValueSelector.EndUnixMilli > 0 { if fieldValueSelector.EndUnixMilli > 0 {
sb.And(sb.LE("first_reported_unix_milli", fieldValueSelector.EndUnixMilli)) sb.Where(sb.LE("first_reported_unix_milli", fieldValueSelector.EndUnixMilli))
} }
if fieldValueSelector.Value != "" { if fieldValueSelector.Value != "" {
if fieldValueSelector.SelectorMatchType == telemetrytypes.FieldSelectorMatchTypeExact { if fieldValueSelector.SelectorMatchType == telemetrytypes.FieldSelectorMatchTypeExact {
sb.And(sb.E("attr_string_value", fieldValueSelector.Value)) sb.Where(sb.E("attr_string_value", fieldValueSelector.Value))
} else { } else {
sb.And(sb.Like("attr_string_value", "%"+fieldValueSelector.Value+"%")) sb.Where(sb.Like("attr_string_value", "%"+fieldValueSelector.Value+"%"))
} }
} }
@ -794,8 +806,30 @@ func (t *telemetryMetaStore) getMetricFieldValues(ctx context.Context, fieldValu
return values, nil return values, nil
} }
func populateAllUnspecifiedValues(allUnspecifiedValues *telemetrytypes.TelemetryFieldValues, mapOfValues map[any]bool, mapOfRelatedValues map[any]bool, values *telemetrytypes.TelemetryFieldValues) {
for _, value := range values.StringValues {
if _, ok := mapOfValues[value]; !ok {
mapOfValues[value] = true
allUnspecifiedValues.StringValues = append(allUnspecifiedValues.StringValues, value)
}
}
for _, value := range values.NumberValues {
if _, ok := mapOfValues[value]; !ok {
mapOfValues[value] = true
allUnspecifiedValues.NumberValues = append(allUnspecifiedValues.NumberValues, value)
}
}
for _, value := range values.RelatedValues {
if _, ok := mapOfRelatedValues[value]; !ok {
mapOfRelatedValues[value] = true
allUnspecifiedValues.RelatedValues = append(allUnspecifiedValues.RelatedValues, value)
}
}
}
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) {
var values *telemetrytypes.TelemetryFieldValues values := &telemetrytypes.TelemetryFieldValues{}
var err error var err error
switch fieldValueSelector.Signal { switch fieldValueSelector.Signal {
case telemetrytypes.SignalTraces: case telemetrytypes.SignalTraces:
@ -804,6 +838,23 @@ func (t *telemetryMetaStore) GetAllValues(ctx context.Context, fieldValueSelecto
values, err = t.getLogFieldValues(ctx, fieldValueSelector) values, err = t.getLogFieldValues(ctx, fieldValueSelector)
case telemetrytypes.SignalMetrics: case telemetrytypes.SignalMetrics:
values, err = t.getMetricFieldValues(ctx, fieldValueSelector) values, err = t.getMetricFieldValues(ctx, fieldValueSelector)
case telemetrytypes.SignalUnspecified:
mapOfValues := make(map[any]bool)
mapOfRelatedValues := make(map[any]bool)
allUnspecifiedValues := &telemetrytypes.TelemetryFieldValues{}
tracesValues, err := t.getSpanFieldValues(ctx, fieldValueSelector)
if err == nil {
populateAllUnspecifiedValues(allUnspecifiedValues, mapOfValues, mapOfRelatedValues, tracesValues)
}
logsValues, err := t.getLogFieldValues(ctx, fieldValueSelector)
if err == nil {
populateAllUnspecifiedValues(allUnspecifiedValues, mapOfValues, mapOfRelatedValues, logsValues)
}
metricsValues, err := t.getMetricFieldValues(ctx, fieldValueSelector)
if err == nil {
populateAllUnspecifiedValues(allUnspecifiedValues, mapOfValues, mapOfRelatedValues, metricsValues)
}
values = allUnspecifiedValues
} }
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -62,6 +62,7 @@ var (
"resource": FieldContextResource, "resource": FieldContextResource,
"scope": FieldContextScope, "scope": FieldContextScope,
"tag": FieldContextAttribute, "tag": FieldContextAttribute,
"point": FieldContextAttribute,
"attribute": FieldContextAttribute, "attribute": FieldContextAttribute,
"event": FieldContextEvent, "event": FieldContextEvent,
"spanfield": FieldContextSpan, "spanfield": FieldContextSpan,

View File

@ -38,6 +38,7 @@ var (
fieldDataTypes = map[string]FieldDataType{ fieldDataTypes = map[string]FieldDataType{
// String types // String types
"string": FieldDataTypeString, "string": FieldDataTypeString,
"str": FieldDataTypeString,
// Boolean types // Boolean types
"bool": FieldDataTypeBool, "bool": FieldDataTypeBool,