package implfields import ( "context" "net/http" "time" "github.com/SigNoz/signoz/pkg/factory" "github.com/SigNoz/signoz/pkg/http/binding" "github.com/SigNoz/signoz/pkg/http/render" "github.com/SigNoz/signoz/pkg/modules/fields" "github.com/SigNoz/signoz/pkg/telemetryschema/aitelemetryschema" "github.com/SigNoz/signoz/pkg/types/authtypes" "github.com/SigNoz/signoz/pkg/types/telemetrytypes" "github.com/SigNoz/signoz/pkg/valuer" ) type handler struct { telemetryMetadataStore telemetrytypes.MetadataStore } func NewHandler(settings factory.ProviderSettings, telemetryMetadataStore telemetrytypes.MetadataStore) fields.Handler { return &handler{ telemetryMetadataStore: telemetryMetadataStore, } } func (handler *handler) GetFieldsKeys(rw http.ResponseWriter, req *http.Request) { ctx := req.Context() var params telemetrytypes.PostableFieldKeysParams if err := binding.Query.BindQuery(req.URL.Query(), ¶ms); err != nil { render.Error(rw, err) return } fieldKeySelector := telemetrytypes.NewFieldKeySelectorFromPostableFieldKeysParams(params) claims, err := authtypes.ClaimsFromContext(ctx) if err != nil { render.Error(rw, err) return } keys, complete, err := handler.telemetryMetadataStore.GetKeys(ctx, valuer.MustNewUUID(claims.OrgID), fieldKeySelector) if err != nil { render.Error(rw, err) return } render.Success(rw, http.StatusOK, &telemetrytypes.GettableFieldKeys{ Keys: keys, Complete: complete, }) } func (handler *handler) GetAIObservabilityFieldsKeys(rw http.ResponseWriter, req *http.Request) { ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second) defer cancel() var params telemetrytypes.PostableFieldKeysParams if err := binding.Query.BindQuery(req.URL.Query(), ¶ms); err != nil { render.Error(rw, err) return } // the explorer lists AI traces, whatever signal the caller asked for params.Signal = telemetrytypes.SignalTraces claims, err := authtypes.ClaimsFromContext(ctx) if err != nil { render.Error(rw, err) return } orgID := valuer.MustNewUUID(claims.OrgID) fieldKeySelector := telemetrytypes.NewFieldKeySelectorFromPostableFieldKeysParams(params) keys := make(map[string][]*telemetrytypes.TelemetryFieldKey) complete := true // the trace context names the computed per-trace aggregates, which no scan can serve if fieldKeySelector.FieldContext != telemetrytypes.FieldContextTrace { keys, complete, err = handler.telemetryMetadataStore.GetKeys(ctx, orgID, fieldKeySelector) if err != nil { render.Error(rw, err) return } } render.Success(rw, http.StatusOK, &telemetrytypes.GettableFieldKeys{ Keys: aitelemetryschema.FieldKeys(keys, fieldKeySelector), Complete: complete, }) } func (handler *handler) GetFieldsValues(rw http.ResponseWriter, req *http.Request) { ctx := req.Context() var params telemetrytypes.PostableFieldValueParams if err := binding.Query.BindQuery(req.URL.Query(), ¶ms); err != nil { render.Error(rw, err) return } fieldValueSelector := telemetrytypes.NewFieldValueSelectorFromPostableFieldValueParams(params) claims, err := authtypes.ClaimsFromContext(ctx) if err != nil { render.Error(rw, err) return } allValues, allComplete, err := handler.telemetryMetadataStore.GetAllValues(ctx, valuer.MustNewUUID(claims.OrgID), fieldValueSelector) if err != nil { render.Error(rw, err) return } relatedValues, relatedComplete, err := handler.telemetryMetadataStore.GetRelatedValues(ctx, valuer.MustNewUUID(claims.OrgID), fieldValueSelector) if err != nil { // we don't want to return error if we fail to get related values for some reason relatedValues = []string{} } values := &telemetrytypes.TelemetryFieldValues{ StringValues: allValues.StringValues, NumberValues: allValues.NumberValues, RelatedValues: relatedValues, } render.Success(rw, http.StatusOK, &telemetrytypes.GettableFieldValues{ Values: values, Complete: allComplete && relatedComplete, }) }