Skip to content

Commit 093094e

Browse files
committed
Add TrackTiming, TrackErrorResponses, httpsnoop dependency
1 parent f62449f commit 093094e

File tree

6 files changed

+139
-2
lines changed

6 files changed

+139
-2
lines changed

.release-please-manifest.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
".": "7.13.1",
33
"ldotel": "1.3.0",
4-
"ldai": "0.7.1"
4+
"ldai": "0.7.1",
5+
"ldmiddleware": "0.1.0"
56
}

ldmiddleware/go.mod

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module github.com/launchdarkly/go-server-sdk/ldmiddleware
2+
3+
go 1.23.0
4+
5+
require (
6+
github.com/felixge/httpsnoop v1.0.4
7+
github.com/google/uuid v1.1.1
8+
github.com/launchdarkly/go-sdk-common/v3 v3.4.0
9+
github.com/launchdarkly/go-server-sdk/v7 v7.13.0
10+
)
11+
12+
require (
13+
github.com/gregjones/httpcache v0.0.0-20171119193500-2bcd89a1743f // indirect
14+
github.com/josharian/intern v1.0.0 // indirect
15+
github.com/launchdarkly/ccache v1.1.0 // indirect
16+
github.com/launchdarkly/eventsource v1.10.0 // indirect
17+
github.com/launchdarkly/go-jsonstream/v3 v3.1.0 // indirect
18+
github.com/launchdarkly/go-sdk-events/v3 v3.5.0 // indirect
19+
github.com/launchdarkly/go-semver v1.0.3 // indirect
20+
github.com/launchdarkly/go-server-sdk-evaluation/v3 v3.0.1 // indirect
21+
github.com/mailru/easyjson v0.7.7 // indirect
22+
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
23+
golang.org/x/sync v0.8.0 // indirect
24+
)

ldmiddleware/go.sum

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
5+
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
6+
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
7+
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
8+
github.com/gregjones/httpcache v0.0.0-20171119193500-2bcd89a1743f h1:kOkUP6rcVVqC+KlKKENKtgfFfJyDySYhqL9srXooghY=
9+
github.com/gregjones/httpcache v0.0.0-20171119193500-2bcd89a1743f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
10+
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
11+
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
12+
github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003 h1:vJ0Snvo+SLMY72r5J4sEfkuE7AFbixEP2qRbEcum/wA=
13+
github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003/go.mod h1:zNBxMY8P21owkeogJELCLeHIt+voOSduHYTFUbwRAV8=
14+
github.com/launchdarkly/ccache v1.1.0 h1:voD1M+ZJXR3MREOKtBwgTF9hYHl1jg+vFKS/+VAkR2k=
15+
github.com/launchdarkly/ccache v1.1.0/go.mod h1:TlxzrlnzvYeXiLHmesMuvoZetu4Z97cV1SsdqqBJi1Q=
16+
github.com/launchdarkly/eventsource v1.10.0 h1:H9Tp6AfGu/G2qzBJC26iperrvwhzdbiA/gx7qE2nDFI=
17+
github.com/launchdarkly/eventsource v1.10.0/go.mod h1:J3oa50bPvJesZqNAJtb5btSIo5N6roDWhiAS3IpsKck=
18+
github.com/launchdarkly/go-jsonstream/v3 v3.1.0 h1:U/7/LplZO72XefBQ+FzHf6o4FwLHVqBE+4V58Ornu/E=
19+
github.com/launchdarkly/go-jsonstream/v3 v3.1.0/go.mod h1:2Pt4BR5AwWgsuVTCcIpB6Os04JFIKWfoA+7faKkZB5E=
20+
github.com/launchdarkly/go-sdk-common/v3 v3.4.0 h1:GTRulE0G43xdWY1QdjAXJ7QnZ8PMFU8pOWZICCydEtM=
21+
github.com/launchdarkly/go-sdk-common/v3 v3.4.0/go.mod h1:6MNeeP8b2VtsM6I3TbShCHW/+tYh2c+p5dB+ilS69sg=
22+
github.com/launchdarkly/go-sdk-events/v3 v3.5.0 h1:Yav8Thm70dZbO8U1foYwZPf3w60n/lNBRaYeeNM/qg4=
23+
github.com/launchdarkly/go-sdk-events/v3 v3.5.0/go.mod h1:oepYWQ2RvvjfL2WxkE1uJJIuRsIMOP4WIVgUpXRPcNI=
24+
github.com/launchdarkly/go-semver v1.0.3 h1:agIy/RN3SqeQDIfKkl+oFslEdeIs7pgsJBs3CdCcGQM=
25+
github.com/launchdarkly/go-semver v1.0.3/go.mod h1:xFmMwXba5Mb+3h72Z+VeSs9ahCvKo2QFUTHRNHVqR28=
26+
github.com/launchdarkly/go-server-sdk-evaluation/v3 v3.0.1 h1:rTgcYAFraGFj7sBMB2b7JCYCm0b9kph4FaMX02t4osQ=
27+
github.com/launchdarkly/go-server-sdk-evaluation/v3 v3.0.1/go.mod h1:fPS5d+zOsgFnMunj+Ki6jjlZtFvo4h9iNbtNXxzYn58=
28+
github.com/launchdarkly/go-server-sdk/v7 v7.13.0 h1:ajiZOPBwmWVFFgP+EMdy3oS1Xl9wNDlEd/7Zn/0I2JU=
29+
github.com/launchdarkly/go-server-sdk/v7 v7.13.0/go.mod h1:6krbDWp417H7lIg+3ehh/A/AW5xwHtiUFg06fvNYHAk=
30+
github.com/launchdarkly/go-test-helpers/v3 v3.1.0 h1:E3bxJMzMoA+cJSF3xxtk2/chr1zshl1ZWa0/oR+8bvg=
31+
github.com/launchdarkly/go-test-helpers/v3 v3.1.0/go.mod h1:Ake5+hZFS/DmIGKx/cizhn5W9pGA7pplcR7xCxWiLIo=
32+
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
33+
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
34+
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
35+
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
36+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
37+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
38+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
39+
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
40+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
41+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
42+
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 h1:3UeQBvD0TFrlVjOeLOBz+CPAI8dnbqNSVwUwRrkp7vQ=
43+
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM=
44+
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
45+
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
46+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
47+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
48+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
49+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

ldmiddleware/http_middleware.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package ldmiddleware
22

33
import (
44
"net/http"
5+
"time"
56

7+
"github.com/felixge/httpsnoop"
68
"github.com/google/uuid"
79
"github.com/launchdarkly/go-sdk-common/v3/ldcontext"
10+
"github.com/launchdarkly/go-sdk-common/v3/ldvalue"
811
ld "github.com/launchdarkly/go-server-sdk/v7"
912
)
1013

@@ -57,3 +60,48 @@ func AddRequestScopedClientWithKeyFn(client *ld.LDClient, keyFn RequestKeyFunc)
5760
})
5861
}
5962
}
63+
64+
// TrackTiming sends a LD event "http.request.duration_ms" with the duration of the request in milliseconds.
65+
// This middleware must be after AddRequestScopedClient in the middleware chain, as it uses the scoped client
66+
// from the request context.
67+
//
68+
// The timing event will include all LaunchDarkly contexts added to the scoped client. You may add more
69+
// contexts to the scoped client _during_ the request, and they will be included in the timing event sent
70+
// when the request completes.
71+
func TrackTiming(next http.Handler) http.Handler {
72+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
73+
startTime := time.Now()
74+
next.ServeHTTP(w, r)
75+
duration := time.Since(startTime)
76+
scoped, ok := ld.GetScopedClient(r.Context())
77+
if !ok {
78+
return
79+
}
80+
scoped.TrackMetric("http.request.duration_ms", float64(duration.Milliseconds()), ldvalue.Null())
81+
})
82+
}
83+
84+
// TrackErrorResponses sends a LD event "http.response.4xx" or "http.response.5xx" if the response code is 4xx or 5xx.
85+
// This middleware must be after AddRequestScopedClient in the middleware chain, as it uses the scoped client
86+
// from the request context.
87+
//
88+
// The error event will include all LaunchDarkly contexts added to the scoped client. You may add more
89+
// contexts to the scoped client _during_ the request, and they will be included in the error event sent
90+
// when the request completes.
91+
func TrackErrorResponses(next http.Handler) http.Handler {
92+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
93+
metrics := httpsnoop.CaptureMetrics(next, w, r)
94+
if metrics.Code < 400 {
95+
return
96+
}
97+
scoped, ok := ld.GetScopedClient(r.Context())
98+
if !ok {
99+
return
100+
}
101+
if metrics.Code < 500 {
102+
_ = scoped.TrackEvent("http.response.4xx")
103+
return
104+
}
105+
_ = scoped.TrackEvent("http.response.5xx")
106+
})
107+
}

ldmiddleware/package_info.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Package ldmiddleware contains HTTP middleware helpers for LaunchDarkly.
2+
package ldmiddleware
3+
4+
// Version is the current version string of the ldmiddleware package. This is updated by our release scripts.
5+
const Version = "0.1.0" // {{ x-release-please-version }}

release-please-config.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
".github",
1616
".vscode",
1717
"ldotel",
18-
"ldai"
18+
"ldai",
19+
"ldmiddleware"
1920
]
2021
},
2122
"ldotel" : {
@@ -36,6 +37,15 @@
3637
"extra-files" : [
3738
"package_info.go"
3839
]
40+
},
41+
"ldmiddleware" : {
42+
"package-name": "ldmiddleware",
43+
"release-type" : "go",
44+
"tag-separator": "/",
45+
"versioning" : "default",
46+
"extra-files" : [
47+
"package_info.go"
48+
]
3949
}
4050
}
4151
}

0 commit comments

Comments
 (0)