Skip to content
This repository was archived by the owner on Dec 23, 2024. It is now read-only.

Commit 9befe3a

Browse files
authored
Merge pull request #36 from InVisionApp/send-metrics-to-client-statter
Adding custom statter option for clients to optionally use
2 parents c54f0c8 + c86a3aa commit 9befe3a

3 files changed

Lines changed: 109 additions & 9 deletions

File tree

middleware_static_filesystem_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ var _ = Describe("Static File Middleware", func() {
3131
It("should return a response", func() {
3232
path = "/static-examples/dist/"
3333

34-
request, _ := http.NewRequest("GET", "/dist/test.html", nil)
34+
request, _ = http.NewRequest("GET", "/dist/test.html", nil)
3535

3636
resp := NewStaticFilesystem(testPath+path, "/dist/")(response, request)
3737
Expect(resp).To(BeNil())

rye.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"time"
1313

1414
//log "github.com/sirupsen/logrus"
15+
1516
"github.com/cactus/go-statsd-client/statsd"
1617
)
1718

@@ -24,6 +25,12 @@ type MWHandler struct {
2425
beforeHandlers []Handler
2526
}
2627

28+
// CustomStatter allows the client to log any additional statsD metrics Rye
29+
// computes around the request handler.
30+
type CustomStatter interface {
31+
ReportStats(handlerName string, elapsedTime time.Duration, req *http.Request, resp *Response) error
32+
}
33+
2734
// Config struct allows you to set a reference to a statsd.Statter and include it's stats rate.
2835
type Config struct {
2936
Statter statsd.Statter
@@ -33,6 +40,9 @@ type Config struct {
3340
NoErrStats bool
3441
NoDurationStats bool
3542
NoStatusCodeStats bool
43+
44+
// Customer Statter for the client
45+
CustomStatter CustomStatter
3646
}
3747

3848
// JSONStatus is a simple container used for conveying status messages.
@@ -148,6 +158,12 @@ func (m *MWHandler) do(w http.ResponseWriter, r *http.Request, handler Handler)
148158
// Record status code metric (default 2xx)
149159
go m.reportStatusCode(handlerName, statusCode)
150160
}
161+
162+
// If a CustomStatter is set, send the handler metrics to it.
163+
// This allows the client to handle these metrics however it wants.
164+
if m.Config.CustomStatter != nil && resp != nil {
165+
go m.Config.CustomStatter.ReportStats(handlerName, time.Since(startTime), r, resp)
166+
}
151167
}()
152168

153169
// stop executing rest of the

rye_test.go

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,33 @@ type statsTiming struct {
3636
StatRate float32
3737
}
3838

39+
var reportedStats = make(chan fakeReportedStats)
40+
41+
type fakeReportedStats struct {
42+
HandlerName string
43+
Duration time.Duration
44+
Request *http.Request
45+
Response *Response
46+
}
47+
48+
type fakeCustomStatter struct{}
49+
50+
func (fcs *fakeCustomStatter) ReportStats(handler string, dur time.Duration, req *http.Request, res *Response) error {
51+
reportedStats <- fakeReportedStats{handler, dur, req, res}
52+
return nil
53+
}
54+
3955
var _ = Describe("Rye", func() {
4056

4157
var (
42-
request *http.Request
43-
response *httptest.ResponseRecorder
44-
mwHandler *MWHandler
45-
ryeConfig Config
46-
fakeStatter *statsdfakes.FakeStatter
47-
inc chan statsInc
48-
timing chan statsTiming
58+
request *http.Request
59+
response *httptest.ResponseRecorder
60+
mwHandler *MWHandler
61+
ryeConfig Config
62+
fakeStatter *statsdfakes.FakeStatter
63+
fakeClientStatter *fakeCustomStatter
64+
inc chan statsInc
65+
timing chan statsTiming
4966
)
5067

5168
const (
@@ -54,6 +71,7 @@ var _ = Describe("Rye", func() {
5471

5572
BeforeEach(func() {
5673
fakeStatter = &statsdfakes.FakeStatter{}
74+
fakeClientStatter = &fakeCustomStatter{}
5775
ryeConfig = Config{
5876
Statter: fakeStatter,
5977
StatRate: STATRATE,
@@ -81,7 +99,6 @@ var _ = Describe("Rye", func() {
8199
timing <- statsTiming{name, time, statrate}
82100
return nil
83101
}
84-
85102
})
86103

87104
AfterEach(func() {
@@ -329,6 +346,64 @@ var _ = Describe("Rye", func() {
329346
Expect(fakeStatter.IncCallCount()).To(Equal(2))
330347
})
331348
})
349+
350+
Context("when a custom statter is supplied", func() {
351+
It("should call the ReportStats method", func() {
352+
ryeConfig := Config{
353+
Statter: fakeStatter,
354+
StatRate: STATRATE,
355+
CustomStatter: fakeClientStatter,
356+
}
357+
358+
handler := NewMWHandler(ryeConfig)
359+
h := handler.Handle([]Handler{successWithResponse})
360+
h.ServeHTTP(response, request)
361+
362+
Expect(h).ToNot(BeNil())
363+
Expect(h).To(BeAssignableToTypeOf(func(http.ResponseWriter, *http.Request) {}))
364+
365+
Eventually(inc).Should(Receive(Equal(statsInc{"handlers.successWithResponse.200", 1, float32(STATRATE)})))
366+
Eventually(timing).Should(Receive(HaveTiming("handlers.successWithResponse.runtime", float32(STATRATE))))
367+
368+
var receivedReportedStats fakeReportedStats
369+
var resp *Response
370+
371+
Eventually(reportedStats).Should(Receive(&receivedReportedStats))
372+
Expect(receivedReportedStats.HandlerName).To(Equal("successWithResponse"))
373+
Expect(receivedReportedStats.Duration.Seconds()/1000 > 0).To(Equal(true))
374+
Expect(receivedReportedStats.Request).To(BeAssignableToTypeOf(request))
375+
Expect(receivedReportedStats.Response).To(BeAssignableToTypeOf(resp))
376+
Expect(receivedReportedStats.Response.StatusCode).To(Equal(200))
377+
})
378+
})
379+
380+
Context("when a custom statter is NOT supplied", func() {
381+
It("should not call the ReportStats method", func() {
382+
ryeConfig := Config{
383+
Statter: fakeStatter,
384+
StatRate: STATRATE,
385+
}
386+
387+
handler := NewMWHandler(ryeConfig)
388+
h := handler.Handle([]Handler{successWithResponse})
389+
h.ServeHTTP(response, request)
390+
391+
Expect(h).ToNot(BeNil())
392+
Expect(h).To(BeAssignableToTypeOf(func(http.ResponseWriter, *http.Request) {}))
393+
394+
Eventually(inc).Should(Receive(Equal(statsInc{"handlers.successWithResponse.200", 1, float32(STATRATE)})))
395+
Eventually(timing).Should(Receive(HaveTiming("handlers.successWithResponse.runtime", float32(STATRATE))))
396+
397+
time.Sleep(time.Millisecond * 10)
398+
399+
var receivedReportedStats fakeReportedStats
400+
401+
Expect(receivedReportedStats.HandlerName).To(Equal(""))
402+
Expect(receivedReportedStats.Duration.Nanoseconds()).To(Equal(int64(0)))
403+
Expect(receivedReportedStats.Request).To(BeNil())
404+
Expect(receivedReportedStats.Response).To(BeNil())
405+
})
406+
})
332407
})
333408

334409
Describe("getFuncName", func() {
@@ -385,6 +460,15 @@ func success2Handler(rw http.ResponseWriter, r *http.Request) *Response {
385460
return nil
386461
}
387462

463+
func successWithResponse(rw http.ResponseWriter, r *http.Request) *Response {
464+
return &Response{
465+
StatusCode: 200,
466+
Err: nil,
467+
StopExecution: false,
468+
Context: context.Background(),
469+
}
470+
}
471+
388472
func badResponseHandler(rw http.ResponseWriter, r *http.Request) *Response {
389473
return &Response{}
390474
}

0 commit comments

Comments
 (0)