@@ -5,12 +5,17 @@ import (
5
5
"fmt"
6
6
"net/http"
7
7
8
+
8
9
"github.com/gorilla/mux"
9
10
"github.com/open-feature/flagd/core/pkg/evaluator"
10
11
"github.com/open-feature/flagd/core/pkg/logger"
11
12
"github.com/open-feature/flagd/core/pkg/model"
12
13
"github.com/open-feature/flagd/core/pkg/service/ofrep"
13
14
"github.com/rs/xid"
15
+ "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
16
+ "go.opentelemetry.io/otel"
17
+ "go.opentelemetry.io/otel/attribute"
18
+ "go.opentelemetry.io/otel/trace"
14
19
)
15
20
16
21
const (
@@ -23,25 +28,29 @@ type handler struct {
23
28
Logger * logger.Logger
24
29
evaluator evaluator.IEvaluator
25
30
contextValues map [string ]any
31
+ tracer trace.Tracer
26
32
}
27
33
28
34
func NewOfrepHandler (logger * logger.Logger , evaluator evaluator.IEvaluator , contextValues map [string ]any ) http.Handler {
29
35
h := handler {
30
36
Logger : logger ,
31
37
evaluator : evaluator ,
32
38
contextValues : contextValues ,
39
+ tracer : otel .Tracer ("flagd.ofrep.v1" ),
33
40
}
34
41
35
42
router := mux .NewRouter ()
36
43
router .HandleFunc (singleEvaluation , h .HandleFlagEvaluation ).Methods ("POST" )
37
44
router .HandleFunc (bulkEvaluation , h .HandleBulkEvaluation ).Methods ("POST" )
38
- return router
45
+ return otelhttp . NewHandler ( router , "flagd.ofrep" )
39
46
}
40
47
41
48
func (h * handler ) HandleFlagEvaluation (w http.ResponseWriter , r * http.Request ) {
42
49
requestID := xid .New ().String ()
43
50
defer h .Logger .ClearFields (requestID )
44
51
52
+ rCtx , span := h .tracer .Start (r .Context (), "flagEvaluation" , trace .WithSpanKind (trace .SpanKindServer ))
53
+ defer span .End ()
45
54
// obtain flag key
46
55
vars := mux .Vars (r )
47
56
if vars == nil {
@@ -57,9 +66,10 @@ func (h *handler) HandleFlagEvaluation(w http.ResponseWriter, r *http.Request) {
57
66
h .writeJSONToResponse (http .StatusBadRequest , ofrep .ContextErrorResponseFrom (flagKey ), w )
58
67
return
59
68
}
60
-
61
69
context := flagdContext (h .Logger , requestID , request , h .contextValues )
62
- evaluation := h .evaluator .ResolveAsAnyValue (r .Context (), requestID , flagKey , context )
70
+ evaluation := h .evaluator .ResolveAsAnyValue (rCtx , requestID , flagKey , context )
71
+ span .SetAttributes (attribute .String ("feature_flag.key" , evaluation .FlagKey ))
72
+ span .SetAttributes (attribute .String ("feature_flag.variant" , evaluation .Variant ))
63
73
if evaluation .Error != nil {
64
74
status , evaluationError := ofrep .EvaluationErrorResponseFrom (evaluation )
65
75
h .writeJSONToResponse (status , evaluationError , w )
@@ -72,21 +82,24 @@ func (h *handler) HandleBulkEvaluation(w http.ResponseWriter, r *http.Request) {
72
82
requestID := xid .New ().String ()
73
83
defer h .Logger .ClearFields (requestID )
74
84
85
+ rCtx , span := h .tracer .Start (r .Context (), "bulkEvaluation" , trace .WithSpanKind (trace .SpanKindServer ))
86
+ defer span .End ()
75
87
request , err := extractOfrepRequest (r )
76
88
if err != nil {
77
89
h .writeJSONToResponse (http .StatusBadRequest , ofrep .BulkEvaluationContextError (), w )
78
90
return
79
91
}
80
92
81
93
context := flagdContext (h .Logger , requestID , request , h .contextValues )
82
- evaluations , metadata , err := h .evaluator .ResolveAllValues (r . Context () , requestID , context )
94
+ evaluations , metadata , err := h .evaluator .ResolveAllValues (rCtx , requestID , context )
83
95
if err != nil {
84
96
h .Logger .WarnWithID (requestID , fmt .Sprintf ("error from resolver: %v" , err ))
85
97
86
98
res := ofrep .BulkEvaluationContextErrorFrom (model .GeneralErrorCode ,
87
99
fmt .Sprintf ("Bulk evaluation failed. Tracking ID: %s" , requestID ))
88
100
h .writeJSONToResponse (http .StatusInternalServerError , res , w )
89
101
} else {
102
+ span .SetAttributes (attribute .Int ("feature_flag.count" , len (evaluations )))
90
103
h .writeJSONToResponse (http .StatusOK , ofrep .BulkEvaluationResponseFrom (evaluations , metadata ), w )
91
104
}
92
105
}
0 commit comments