From 981b927868fbd23e5fcfb3a616dbe6b323a4c507 Mon Sep 17 00:00:00 2001 From: Simon Schrottner Date: Fri, 14 Mar 2025 11:22:02 +0100 Subject: [PATCH 1/2] feat: add traces to ofrep endpoint Signed-off-by: Simon Schrottner --- .../service/flag-evaluation/ofrep/handler.go | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/flagd/pkg/service/flag-evaluation/ofrep/handler.go b/flagd/pkg/service/flag-evaluation/ofrep/handler.go index b9ffde686..cebac14a1 100644 --- a/flagd/pkg/service/flag-evaluation/ofrep/handler.go +++ b/flagd/pkg/service/flag-evaluation/ofrep/handler.go @@ -5,12 +5,17 @@ import ( "fmt" "net/http" + "github.com/gorilla/mux" "github.com/open-feature/flagd/core/pkg/evaluator" "github.com/open-feature/flagd/core/pkg/logger" "github.com/open-feature/flagd/core/pkg/model" "github.com/open-feature/flagd/core/pkg/service/ofrep" "github.com/rs/xid" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) const ( @@ -23,6 +28,7 @@ type handler struct { Logger *logger.Logger evaluator evaluator.IEvaluator contextValues map[string]any + tracer trace.Tracer } func NewOfrepHandler(logger *logger.Logger, evaluator evaluator.IEvaluator, contextValues map[string]any) http.Handler { @@ -30,18 +36,21 @@ func NewOfrepHandler(logger *logger.Logger, evaluator evaluator.IEvaluator, cont Logger: logger, evaluator: evaluator, contextValues: contextValues, + tracer: otel.Tracer("flagd.ofrep.v1"), } router := mux.NewRouter() router.HandleFunc(singleEvaluation, h.HandleFlagEvaluation).Methods("POST") router.HandleFunc(bulkEvaluation, h.HandleBulkEvaluation).Methods("POST") - return router + return otelhttp.NewHandler(router, "flagd.ofrep") } func (h *handler) HandleFlagEvaluation(w http.ResponseWriter, r *http.Request) { requestID := xid.New().String() defer h.Logger.ClearFields(requestID) + rCtx, span := h.tracer.Start(r.Context(), "flagEvaluation", trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() // obtain flag key vars := mux.Vars(r) if vars == nil { @@ -57,9 +66,10 @@ func (h *handler) HandleFlagEvaluation(w http.ResponseWriter, r *http.Request) { h.writeJSONToResponse(http.StatusBadRequest, ofrep.ContextErrorResponseFrom(flagKey), w) return } - context := flagdContext(h.Logger, requestID, request, h.contextValues) - evaluation := h.evaluator.ResolveAsAnyValue(r.Context(), requestID, flagKey, context) + evaluation := h.evaluator.ResolveAsAnyValue(rCtx, requestID, flagKey, context) + span.SetAttributes(attribute.String("feature_flag.key", evaluation.FlagKey)) + span.SetAttributes(attribute.String("feature_flag.variant", evaluation.Variant)) if evaluation.Error != nil { status, evaluationError := ofrep.EvaluationErrorResponseFrom(evaluation) h.writeJSONToResponse(status, evaluationError, w) @@ -72,6 +82,8 @@ func (h *handler) HandleBulkEvaluation(w http.ResponseWriter, r *http.Request) { requestID := xid.New().String() defer h.Logger.ClearFields(requestID) + rCtx, span := h.tracer.Start(r.Context(), "bulkEvaluation", trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() request, err := extractOfrepRequest(r) if err != nil { h.writeJSONToResponse(http.StatusBadRequest, ofrep.BulkEvaluationContextError(), w) @@ -79,7 +91,7 @@ func (h *handler) HandleBulkEvaluation(w http.ResponseWriter, r *http.Request) { } context := flagdContext(h.Logger, requestID, request, h.contextValues) - evaluations, metadata, err := h.evaluator.ResolveAllValues(r.Context(), requestID, context) + evaluations, metadata, err := h.evaluator.ResolveAllValues(rCtx, requestID, context) if err != nil { h.Logger.WarnWithID(requestID, fmt.Sprintf("error from resolver: %v", err)) @@ -87,6 +99,7 @@ func (h *handler) HandleBulkEvaluation(w http.ResponseWriter, r *http.Request) { fmt.Sprintf("Bulk evaluation failed. Tracking ID: %s", requestID)) h.writeJSONToResponse(http.StatusInternalServerError, res, w) } else { + span.SetAttributes(attribute.Int("feature_flag.count", len(evaluations))) h.writeJSONToResponse(http.StatusOK, ofrep.BulkEvaluationResponseFrom(evaluations, metadata), w) } } From f6a1cc6c036407538acc6e70f2e9f15909265786 Mon Sep 17 00:00:00 2001 From: Simon Schrottner Date: Fri, 14 Mar 2025 17:52:14 +0100 Subject: [PATCH 2/2] fixup: remove spans and unnecessary events Signed-off-by: Simon Schrottner --- flagd/pkg/service/flag-evaluation/ofrep/handler.go | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/flagd/pkg/service/flag-evaluation/ofrep/handler.go b/flagd/pkg/service/flag-evaluation/ofrep/handler.go index cebac14a1..0b34106c5 100644 --- a/flagd/pkg/service/flag-evaluation/ofrep/handler.go +++ b/flagd/pkg/service/flag-evaluation/ofrep/handler.go @@ -5,7 +5,6 @@ import ( "fmt" "net/http" - "github.com/gorilla/mux" "github.com/open-feature/flagd/core/pkg/evaluator" "github.com/open-feature/flagd/core/pkg/logger" @@ -14,7 +13,6 @@ import ( "github.com/rs/xid" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) @@ -49,8 +47,6 @@ func (h *handler) HandleFlagEvaluation(w http.ResponseWriter, r *http.Request) { requestID := xid.New().String() defer h.Logger.ClearFields(requestID) - rCtx, span := h.tracer.Start(r.Context(), "flagEvaluation", trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() // obtain flag key vars := mux.Vars(r) if vars == nil { @@ -67,9 +63,7 @@ func (h *handler) HandleFlagEvaluation(w http.ResponseWriter, r *http.Request) { return } context := flagdContext(h.Logger, requestID, request, h.contextValues) - evaluation := h.evaluator.ResolveAsAnyValue(rCtx, requestID, flagKey, context) - span.SetAttributes(attribute.String("feature_flag.key", evaluation.FlagKey)) - span.SetAttributes(attribute.String("feature_flag.variant", evaluation.Variant)) + evaluation := h.evaluator.ResolveAsAnyValue(r.Context(), requestID, flagKey, context) if evaluation.Error != nil { status, evaluationError := ofrep.EvaluationErrorResponseFrom(evaluation) h.writeJSONToResponse(status, evaluationError, w) @@ -82,8 +76,6 @@ func (h *handler) HandleBulkEvaluation(w http.ResponseWriter, r *http.Request) { requestID := xid.New().String() defer h.Logger.ClearFields(requestID) - rCtx, span := h.tracer.Start(r.Context(), "bulkEvaluation", trace.WithSpanKind(trace.SpanKindServer)) - defer span.End() request, err := extractOfrepRequest(r) if err != nil { h.writeJSONToResponse(http.StatusBadRequest, ofrep.BulkEvaluationContextError(), w) @@ -91,7 +83,7 @@ func (h *handler) HandleBulkEvaluation(w http.ResponseWriter, r *http.Request) { } context := flagdContext(h.Logger, requestID, request, h.contextValues) - evaluations, metadata, err := h.evaluator.ResolveAllValues(rCtx, requestID, context) + evaluations, metadata, err := h.evaluator.ResolveAllValues(r.Context(), requestID, context) if err != nil { h.Logger.WarnWithID(requestID, fmt.Sprintf("error from resolver: %v", err)) @@ -99,7 +91,6 @@ func (h *handler) HandleBulkEvaluation(w http.ResponseWriter, r *http.Request) { fmt.Sprintf("Bulk evaluation failed. Tracking ID: %s", requestID)) h.writeJSONToResponse(http.StatusInternalServerError, res, w) } else { - span.SetAttributes(attribute.Int("feature_flag.count", len(evaluations))) h.writeJSONToResponse(http.StatusOK, ofrep.BulkEvaluationResponseFrom(evaluations, metadata), w) } }