Skip to content

Commit 98bde07

Browse files
authored
[FSSDK-9840] chore: add traceID & spanID to logs (#407)
* add logging for decide api * log traceid for trace api * log traceid for override api * add traceid for error log * add traceid into logs * clean up * clean up * update unit test
1 parent a06246f commit 98bde07

File tree

14 files changed

+73
-31
lines changed

14 files changed

+73
-31
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ require (
2525
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0
2626
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0
2727
go.opentelemetry.io/otel/sdk v1.19.0
28+
go.opentelemetry.io/otel/trace v1.19.0
2829
golang.org/x/crypto v0.11.0
2930
golang.org/x/sync v0.3.0
3031
gopkg.in/yaml.v2 v2.4.0
@@ -42,7 +43,6 @@ require (
4243
github.com/prometheus/common v0.30.0 // indirect
4344
github.com/prometheus/procfs v0.7.3 // indirect
4445
go.opentelemetry.io/otel/metric v1.19.0 // indirect
45-
go.opentelemetry.io/otel/trace v1.19.0 // indirect
4646
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
4747
golang.org/x/net v0.12.0 // indirect
4848
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect

pkg/handlers/activate.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,12 @@ import (
2222
"fmt"
2323
"net/http"
2424

25+
"github.com/go-chi/render"
26+
2527
"github.com/optimizely/agent/pkg/middleware"
2628
"github.com/optimizely/agent/pkg/optimizely"
27-
2829
"github.com/optimizely/go-sdk/pkg/config"
2930
"github.com/optimizely/go-sdk/pkg/entities"
30-
31-
"github.com/go-chi/render"
3231
)
3332

3433
type keyMap map[string]string
@@ -42,12 +41,13 @@ type ActivateBody struct {
4241
// Activate makes feature and experiment decisions for the selected query parameters.
4342
func Activate(w http.ResponseWriter, r *http.Request) {
4443
optlyClient, err := middleware.GetOptlyClient(r)
45-
logger := middleware.GetLogger(r)
4644
if err != nil {
4745
RenderError(err, http.StatusInternalServerError, w, r)
4846
return
4947
}
5048

49+
logger := middleware.GetLogger(r)
50+
5151
uc, err := getUserContext(r)
5252
if err != nil {
5353
RenderError(err, http.StatusBadRequest, w, r)
@@ -108,6 +108,7 @@ func Activate(w http.ResponseWriter, r *http.Request) {
108108
}
109109

110110
decisions = filterDecisions(r, decisions)
111+
logger.Info().Msgf("Made activate decisions for user %s", uc.ID)
111112
render.JSON(w, r, decisions)
112113
}
113114

pkg/handlers/decide.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ import (
2121
"errors"
2222
"net/http"
2323

24-
"github.com/optimizely/agent/pkg/middleware"
24+
"github.com/go-chi/render"
2525

26+
"github.com/optimizely/agent/pkg/middleware"
2627
"github.com/optimizely/go-sdk/pkg/client"
2728
"github.com/optimizely/go-sdk/pkg/decide"
2829
"github.com/optimizely/go-sdk/pkg/decision"
2930
"github.com/optimizely/go-sdk/pkg/odp/segment"
30-
31-
"github.com/go-chi/render"
3231
)
3332

3433
// DecideBody defines the request body for decide API
@@ -108,6 +107,7 @@ func Decide(w http.ResponseWriter, r *http.Request) {
108107
key := keys[0]
109108
logger.Debug().Str("featureKey", key).Msg("fetching feature decision")
110109
d := optimizelyUserContext.Decide(key, decideOptions)
110+
logger.Info().Msgf("Feature %q is enabled for user %s? %t", d.FlagKey, d.UserContext.UserID, d.Enabled)
111111
decideOut := DecideOut{d, d.Variables.ToMap()}
112112
render.JSON(w, r, decideOut)
113113
return
@@ -120,6 +120,7 @@ func Decide(w http.ResponseWriter, r *http.Request) {
120120
for _, d := range decides {
121121
decideOut := DecideOut{d, d.Variables.ToMap()}
122122
decideOuts = append(decideOuts, decideOut)
123+
logger.Info().Msgf("Feature %q is enabled for user %s? %t", d.FlagKey, d.UserContext.UserID, d.Enabled)
123124
}
124125
render.JSON(w, r, decideOuts)
125126
}

pkg/handlers/decide_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,17 @@ import (
2626
"net/http/httptest"
2727
"testing"
2828

29+
"github.com/go-chi/chi/v5"
30+
"github.com/stretchr/testify/assert"
31+
"github.com/stretchr/testify/suite"
32+
2933
"github.com/optimizely/agent/pkg/middleware"
3034
"github.com/optimizely/agent/pkg/optimizely"
3135
"github.com/optimizely/agent/pkg/optimizely/optimizelytest"
32-
3336
"github.com/optimizely/go-sdk/pkg/client"
3437
"github.com/optimizely/go-sdk/pkg/decide"
3538
"github.com/optimizely/go-sdk/pkg/entities"
3639
"github.com/optimizely/go-sdk/pkg/odp/segment"
37-
38-
"github.com/go-chi/chi/v5"
39-
"github.com/stretchr/testify/assert"
40-
"github.com/stretchr/testify/suite"
4140
)
4241

4342
type DecideTestSuite struct {

pkg/handlers/get_datafile.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,15 @@ func GetDatafile(w http.ResponseWriter, r *http.Request) {
3434
return
3535
}
3636

37+
logger := middleware.GetLogger(r)
38+
3739
datafile := optlyClient.GetOptimizelyConfig().GetDatafile()
3840
var raw map[string]interface{}
3941
if err = json.Unmarshal([]byte(datafile), &raw); err != nil {
4042
RenderError(err, http.StatusInternalServerError, w, r)
4143
return
4244
}
45+
46+
logger.Info().Msg("Successfully returned datafile")
4347
render.JSON(w, r, raw)
4448
}

pkg/handlers/lookup.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import (
2121
"errors"
2222
"net/http"
2323

24-
"github.com/optimizely/agent/pkg/middleware"
25-
2624
"github.com/go-chi/render"
25+
26+
"github.com/optimizely/agent/pkg/middleware"
2727
)
2828

2929
type lookupBody struct {
@@ -47,6 +47,8 @@ func Lookup(w http.ResponseWriter, r *http.Request) {
4747
return
4848
}
4949

50+
logger := middleware.GetLogger(r)
51+
5052
if optlyClient.UserProfileService == nil {
5153
RenderError(ErrNoUPS, http.StatusInternalServerError, w, r)
5254
return
@@ -75,5 +77,6 @@ func Lookup(w http.ResponseWriter, r *http.Request) {
7577
experimentBucketMap[k.ExperimentID] = map[string]interface{}{k.Field: v}
7678
}
7779
lookupResponse.ExperimentBucketMap = experimentBucketMap
80+
logger.Info().Msgf("Looked up user profile for user %s", body.UserID)
7881
render.JSON(w, r, lookupResponse)
7982
}

pkg/handlers/optimizely_config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ func OptimizelyConfig(w http.ResponseWriter, r *http.Request) {
3333
return
3434
}
3535

36+
logger := middleware.GetLogger(r)
37+
3638
conf := optlyClient.GetOptimizelyConfig()
39+
logger.Info().Msg("Successfully returned OptimizelyConfig")
3740
render.JSON(w, r, conf)
3841
}

pkg/handlers/override.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ func Override(w http.ResponseWriter, r *http.Request) {
6969
return
7070
}
7171

72-
logger.Debug().Str("experimentKey", experimentKey).Str("variationKey", body.VariationKey).Msg("setting override")
7372
if override, err := optlyClient.SetForcedVariation(r.Context(), experimentKey, body.UserID, body.VariationKey); err != nil {
7473
RenderError(err, http.StatusInternalServerError, w, r)
7574
} else {
75+
logger.Info().Str("experimentKey", experimentKey).Str("variationKey", body.VariationKey).Msg("Successfully set override")
7676
render.JSON(w, r, override)
7777
}
7878
}

pkg/handlers/save.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ package handlers
2020
import (
2121
"net/http"
2222

23+
"github.com/go-chi/render"
24+
2325
"github.com/optimizely/agent/pkg/middleware"
2426
"github.com/optimizely/go-sdk/pkg/decision"
25-
26-
"github.com/go-chi/render"
2727
)
2828

2929
type saveBody struct {
@@ -38,6 +38,8 @@ func Save(w http.ResponseWriter, r *http.Request) {
3838
return
3939
}
4040

41+
logger := middleware.GetLogger(r)
42+
4143
if optlyClient.UserProfileService == nil {
4244
RenderError(ErrNoUPS, http.StatusInternalServerError, w, r)
4345
return
@@ -58,6 +60,7 @@ func Save(w http.ResponseWriter, r *http.Request) {
5860

5961
convertedProfile := convertToUserProfile(body)
6062
optlyClient.UserProfileService.Save(convertedProfile)
63+
logger.Info().Msgf("Saved user profile for user %s", body.UserID)
6164
render.Status(r, http.StatusOK)
6265
}
6366

pkg/handlers/send_odp_event.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ import (
2222
"net/http"
2323

2424
"github.com/go-chi/render"
25-
"github.com/optimizely/go-sdk/pkg/odp/event"
2625

2726
"github.com/optimizely/agent/pkg/middleware"
2827
"github.com/optimizely/agent/pkg/optimizely"
28+
"github.com/optimizely/go-sdk/pkg/odp/event"
2929
)
3030

3131
// SendOdpEvent sends event to ODP platform
@@ -36,6 +36,8 @@ func SendOdpEvent(w http.ResponseWriter, r *http.Request) {
3636
return
3737
}
3838

39+
logger := middleware.GetLogger(r)
40+
3941
body, err := getRequestOdpEvent(r)
4042
if err != nil {
4143
RenderError(err, http.StatusBadRequest, w, r)
@@ -52,6 +54,7 @@ func SendOdpEvent(w http.ResponseWriter, r *http.Request) {
5254
Success: true,
5355
}
5456

57+
logger.Info().Msg("Successfully sent event to ODP platform")
5558
render.JSON(w, r, returnResult)
5659
}
5760

pkg/handlers/track.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ import (
2222
"net/http"
2323

2424
"github.com/go-chi/render"
25-
"github.com/optimizely/go-sdk/pkg/entities"
2625

2726
"github.com/optimizely/agent/pkg/middleware"
27+
"github.com/optimizely/go-sdk/pkg/entities"
2828
)
2929

3030
type trackBody struct {
@@ -40,6 +40,7 @@ func TrackEvent(w http.ResponseWriter, r *http.Request) {
4040
RenderError(err, http.StatusInternalServerError, w, r)
4141
return
4242
}
43+
logger := middleware.GetLogger(r)
4344

4445
var body trackBody
4546
err = ParseRequestBody(r, &body)
@@ -66,6 +67,6 @@ func TrackEvent(w http.ResponseWriter, r *http.Request) {
6667
return
6768
}
6869

69-
middleware.GetLogger(r).Debug().Str("eventKey", eventKey).Msg("tracking event")
70+
logger.Info().Str("eventKey", eventKey).Msg("tracked event")
7071
render.JSON(w, r, track)
7172
}

pkg/handlers/utils.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ type ErrorResponse struct {
3535

3636
// RenderError sets the request status and renders the error message.
3737
func RenderError(err error, status int, w http.ResponseWriter, r *http.Request) {
38-
middleware.GetLogger(r).Info().Err(err).Int("status", status).Msg("render error")
38+
middleware.GetLogger(r).Err(err).Int("status", status).Msg("render error")
3939
render.Status(r, status)
4040
render.JSON(w, r, ErrorResponse{Error: err.Error()})
4141
}
@@ -44,22 +44,24 @@ func RenderError(err error, status int, w http.ResponseWriter, r *http.Request)
4444
// into the provided interface. Note that we're sanitizing the returned error
4545
// so that it is not leaked back to the requestor.
4646
func ParseRequestBody(r *http.Request, v interface{}) error {
47+
logger := middleware.GetLogger(r)
48+
4749
body, err := io.ReadAll(r.Body)
4850
if err != nil {
4951
msg := "error reading request body"
50-
middleware.GetLogger(r).Error().Err(err).Msg(msg)
52+
logger.Err(err).Msg(msg)
5153
return fmt.Errorf("%s", msg)
5254
}
5355

5456
if len(body) == 0 {
55-
middleware.GetLogger(r).Debug().Msg("body was empty skip JSON unmarshal")
57+
logger.Info().Msg("body was empty skip JSON unmarshal")
5658
return nil
5759
}
5860

5961
err = json.Unmarshal(body, &v)
6062
if err != nil {
6163
msg := "error parsing request body"
62-
middleware.GetLogger(r).Error().Err(err).Msg(msg)
64+
logger.Err(err).Msg(msg)
6365
return fmt.Errorf("%s", msg)
6466
}
6567

pkg/middleware/utils.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ import (
2323
"strconv"
2424
"strings"
2525

26-
"github.com/optimizely/agent/pkg/optimizely"
27-
28-
"github.com/optimizely/go-sdk/pkg/config"
29-
3026
"github.com/go-chi/render"
3127
"github.com/rs/zerolog"
3228
"github.com/rs/zerolog/log"
29+
"go.opentelemetry.io/otel/trace"
30+
31+
"github.com/optimizely/agent/pkg/optimizely"
32+
"github.com/optimizely/go-sdk/pkg/config"
3333
)
3434

3535
// ErrorResponse Model
@@ -52,6 +52,12 @@ func GetLogger(r *http.Request) *zerolog.Logger {
5252
reqID := r.Header.Get(OptlyRequestHeader)
5353
logger := log.With().Str("requestId", reqID).Logger()
5454

55+
span := trace.SpanFromContext(r.Context())
56+
if span.SpanContext().TraceID().IsValid() {
57+
logger = logger.With().Str("traceId", span.SpanContext().TraceID().String()).Logger()
58+
logger = logger.With().Str("spanId", span.SpanContext().SpanID().String()).Logger()
59+
}
60+
5561
if optimizely.ShouldIncludeSDKKey {
5662
sdkKey := r.Header.Get(OptlySDKHeader)
5763
sdkKeySplit := strings.Split(sdkKey, ":")

pkg/middleware/utils_test.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ import (
2121
"bytes"
2222
"context"
2323
"encoding/json"
24+
"fmt"
2425
"net/http/httptest"
2526
"testing"
2627

2728
"github.com/stretchr/testify/assert"
29+
"go.opentelemetry.io/otel"
30+
"go.opentelemetry.io/otel/propagation"
2831

2932
"github.com/optimizely/agent/pkg/optimizely"
30-
3133
"github.com/optimizely/go-sdk/pkg/config"
3234
)
3335

@@ -54,22 +56,36 @@ func TestGetLogger(t *testing.T) {
5456
out := &bytes.Buffer{}
5557
req := httptest.NewRequest("GET", "/", nil)
5658

59+
traceId := "0af7651916cd43dd8448eb211c80319c"
60+
spanId := "b9c7c989f97918e1"
61+
5762
req.Header.Set(OptlyRequestHeader, "12345")
5863
req.Header.Set(OptlySDKHeader, "some_key")
59-
logger := GetLogger(req)
64+
req.Header.Set("traceparent", fmt.Sprintf("00-%s-%s-01", traceId, spanId))
65+
66+
otel.SetTextMapPropagator(propagation.TraceContext{})
67+
ctx := otel.GetTextMapPropagator().Extract(req.Context(), propagation.HeaderCarrier(req.Header))
68+
69+
logger := GetLogger(req.WithContext(ctx))
6070
newLogger := logger.Output(out)
6171
newLogger.Info().Msg("some_message")
6272

6373
assert.Contains(t, out.String(), `"requestId":"12345"`)
6474
assert.Contains(t, out.String(), `"sdkKey":"some_key"`)
6575

76+
assert.Contains(t, out.String(), `"traceId":"`+traceId+`"`)
77+
assert.Contains(t, out.String(), `"spanId":"`+spanId+`"`)
78+
6679
optimizely.ShouldIncludeSDKKey = false
6780
out = &bytes.Buffer{}
6881
logger = GetLogger(req)
6982
newLogger = logger.Output(out)
7083
newLogger.Info().Msg("some_message")
7184
assert.Contains(t, out.String(), `"requestId":"12345"`)
7285
assert.NotContains(t, out.String(), `"sdkKey":"some_key"`)
86+
87+
assert.NotContains(t, out.String(), `"traceId":"`+traceId+`"`)
88+
assert.NotContains(t, out.String(), `"spanId":"`+spanId+`"`)
7389
}
7490

7591
func TestGetFeature(t *testing.T) {

0 commit comments

Comments
 (0)