Skip to content

Commit 4a46434

Browse files
authored
Add Gin compatible middleware (#25)
Add Gin compatible middleware
2 parents 448665b + 2a28b5c commit 4a46434

File tree

10 files changed

+267
-4
lines changed

10 files changed

+267
-4
lines changed

.github/workflows/go.yml renamed to .github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Go
1+
name: CI
22
on: [push]
33
jobs:
44
test:

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
- Gin compatible middleware.
8+
59
## [0.4.0] - 2019-03-27
610

711
### Breaking changes

Readme.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ The middleware is mainly focused to be compatible with Go std library using http
4141
- [Negroni][negroni-example]
4242
- [httprouter][httprouter-example]
4343
- [go-restful][gorestful-example]
44+
- [Gin][gin-example]
4445

4546
## Getting Started
4647

@@ -202,7 +203,7 @@ BenchmarkMiddlewareHandler/benchmark_with_grouped_status_code.-4 1000000
202203
BenchmarkMiddlewareHandler/benchmark_with_predefined_handler_ID-4 1000000 1258 ns/op 256 B/op 6 allocs/op
203204
```
204205

205-
[github-actions-image]: https://github.com/slok/go-http-metrics/workflows/Go/badge.svg
206+
[github-actions-image]: https://github.com/slok/go-http-metrics/workflows/CI/badge.svg
206207
[github-actions-url]: https://github.com/slok/go-http-metrics/actions
207208
[goreport-image]: https://goreportcard.com/badge/github.com/slok/go-http-metrics
208209
[goreport-url]: https://goreportcard.com/report/github.com/slok/go-http-metrics
@@ -217,5 +218,6 @@ BenchmarkMiddlewareHandler/benchmark_with_predefined_handler_ID-4 1000000
217218
[negroni-example]: examples/negroni
218219
[httprouter-example]: examples/httprouter
219220
[gorestful-example]: examples/gorestful
221+
[gin-example]: examples/gin
220222
[prometheus-recorder]: metrics/prometheus
221223
[opencensus-recorder]: metrics/opencensus

examples/gin/main.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"net/http"
6+
"os"
7+
"os/signal"
8+
"syscall"
9+
10+
"github.com/gin-gonic/gin"
11+
"github.com/prometheus/client_golang/prometheus/promhttp"
12+
metrics "github.com/slok/go-http-metrics/metrics/prometheus"
13+
"github.com/slok/go-http-metrics/middleware"
14+
ginmiddleware "github.com/slok/go-http-metrics/middleware/gin"
15+
)
16+
17+
const (
18+
srvAddr = ":8080"
19+
metricsAddr = ":8081"
20+
)
21+
22+
func main() {
23+
// Create our middleware.
24+
mdlw := middleware.New(middleware.Config{
25+
Recorder: metrics.NewRecorder(metrics.Config{}),
26+
})
27+
28+
// Create Gin engine and global middleware.
29+
engine := gin.New()
30+
engine.Use(ginmiddleware.Handler("", mdlw))
31+
32+
// Add our handler.
33+
engine.GET("/", func(c *gin.Context) {
34+
c.String(http.StatusOK, "Hello world")
35+
})
36+
engine.GET("/wrong", func(c *gin.Context) {
37+
c.String(http.StatusTooManyRequests, "oops")
38+
})
39+
40+
// Serve our handler.
41+
go func() {
42+
log.Printf("server listening at %s", srvAddr)
43+
if err := http.ListenAndServe(srvAddr, engine); err != nil {
44+
log.Panicf("error while serving: %s", err)
45+
}
46+
}()
47+
48+
// Serve our metrics.
49+
go func() {
50+
log.Printf("metrics listening at %s", metricsAddr)
51+
if err := http.ListenAndServe(metricsAddr, promhttp.Handler()); err != nil {
52+
log.Panicf("error while serving metrics: %s", err)
53+
}
54+
}()
55+
56+
// Wait until some signal is captured.
57+
sigC := make(chan os.Signal, 1)
58+
signal.Notify(sigC, syscall.SIGTERM, syscall.SIGINT)
59+
<-sigC
60+
}

examples/gorestful/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func main() {
4646
// Serve our handler.
4747
go func() {
4848
log.Printf("server listening at %s", srvAddr)
49-
if err := http.ListenAndServe(":8080", c); err != nil {
49+
if err := http.ListenAndServe(srvAddr, c); err != nil {
5050
log.Panicf("error while serving: %s", err)
5151
}
5252
}()

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ module github.com/slok/go-http-metrics
33
require (
44
contrib.go.opencensus.io/exporter/prometheus v0.1.0
55
github.com/emicklei/go-restful v2.9.6+incompatible
6+
github.com/gin-gonic/gin v1.5.0
67
github.com/julienschmidt/httprouter v1.2.0
78
github.com/prometheus/client_golang v1.0.0
8-
github.com/stretchr/testify v1.3.0
9+
github.com/stretchr/testify v1.4.0
910
github.com/urfave/negroni v1.0.0
1011
go.opencensus.io v0.22.0
1112
)
13+
14+
go 1.13

go.sum

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,16 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
1414
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1515
github.com/emicklei/go-restful v2.9.6+incompatible h1:tfrHha8zJ01ywiOEC1miGY8st1/igzWB8OmvPgoYX7w=
1616
github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
17+
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
18+
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
19+
github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc=
20+
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
1721
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
1822
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
23+
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
24+
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
25+
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
26+
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
1927
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
2028
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
2129
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -24,24 +32,34 @@ github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM
2432
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
2533
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
2634
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
35+
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
36+
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
2737
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
2838
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
2939
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
3040
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
41+
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
3142
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
3243
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
3344
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
3445
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
3546
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
3647
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
48+
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
3749
github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
3850
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
3951
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
4052
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
53+
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
54+
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
55+
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
56+
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
4157
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
4258
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
59+
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
4360
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
4461
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
62+
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
4563
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
4664
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
4765
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -71,6 +89,12 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1
7189
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
7290
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
7391
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
92+
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
93+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
94+
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
95+
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
96+
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
97+
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
7498
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
7599
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
76100
go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
@@ -105,6 +129,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv
105129
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
106130
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd h1:r7DufRZuZbWB7j439YfAzP8RPDa9unLkpwQKUYbIMPI=
107131
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
132+
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
108133
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
109134
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
110135
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -121,6 +146,11 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
121146
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
122147
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
123148
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
149+
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
150+
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
151+
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
124152
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
125153
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
154+
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
155+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
126156
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

middleware/gin/example_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package gin_test
2+
3+
import (
4+
"log"
5+
"net/http"
6+
7+
"github.com/gin-gonic/gin"
8+
"github.com/prometheus/client_golang/prometheus/promhttp"
9+
10+
metrics "github.com/slok/go-http-metrics/metrics/prometheus"
11+
"github.com/slok/go-http-metrics/middleware"
12+
ginmiddleware "github.com/slok/go-http-metrics/middleware/gin"
13+
)
14+
15+
// GinMiddleware shows how you would create a default middleware factory and use it
16+
// to create a Gin compatible middleware.
17+
func Example_ginMiddleware() {
18+
// Create our middleware factory with the default settings.
19+
mdlw := middleware.New(middleware.Config{
20+
Recorder: metrics.NewRecorder(metrics.Config{}),
21+
})
22+
23+
// Create our gin instance.
24+
engine := gin.New()
25+
26+
// Add our handler and middleware
27+
h := func(c *gin.Context) {
28+
c.String(http.StatusOK, "Hello world")
29+
}
30+
engine.GET("/", ginmiddleware.Handler("", mdlw), h)
31+
32+
// Serve metrics from the default prometheus registry.
33+
log.Printf("serving metrics at: %s", ":8081")
34+
go http.ListenAndServe(":8081", promhttp.Handler())
35+
36+
// Serve our handler.
37+
log.Printf("listening at: %s", ":8080")
38+
if err := http.ListenAndServe(":8080", engine); err != nil {
39+
log.Panicf("error while serving: %s", err)
40+
}
41+
}

middleware/gin/gin.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Package gin is a helper package to get a gin compatible
2+
// handler/middleware from the standard net/http Middleware factory.
3+
package gin
4+
5+
import (
6+
"net/http"
7+
8+
"github.com/gin-gonic/gin"
9+
10+
"github.com/slok/go-http-metrics/middleware"
11+
)
12+
13+
// Handler returns a Gin compatible middleware from a Middleware factory instance.
14+
// The first handlerID argument is the same argument passed on Middleware.Handler method.
15+
func Handler(handlerID string, m middleware.Middleware) gin.HandlerFunc {
16+
// Create a dummy handler to wrap the middleware chain of Gin, this way Middleware
17+
// interface can wrap the Gin chain.
18+
return func(c *gin.Context) {
19+
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
20+
c.Writer = &ginResponseWriter{
21+
ResponseWriter: c.Writer,
22+
middlewareRW: w,
23+
}
24+
c.Next()
25+
})
26+
m.Handler(handlerID, h).ServeHTTP(c.Writer, c.Request)
27+
}
28+
}
29+
30+
// ginResponseWriter is a helper type that intercepts the middleware ResponseWriter
31+
// interceptor.
32+
// This is required because gin's context Writer (c.Writer) is a gin.ResponseWriter
33+
// interface and we can't access to the internal object http.ResponseWriter, so
34+
// we already know that our middleware intercepts the regular http.ResponseWriter,
35+
// and doesn't change anything, just intercepts to read information. So in order to
36+
// get this information on our interceptor we create a gin.ResponseWriter implementation
37+
// that will call the real gin.Context.Writer and our interceptor. This way Gin gets the
38+
// information and our interceptor also.
39+
type ginResponseWriter struct {
40+
middlewareRW http.ResponseWriter
41+
gin.ResponseWriter
42+
}
43+
44+
func (w *ginResponseWriter) WriteHeader(statusCode int) {
45+
w.middlewareRW.WriteHeader(statusCode)
46+
w.ResponseWriter.WriteHeader(statusCode)
47+
}
48+
49+
func (w *ginResponseWriter) Write(p []byte) (int, error) {
50+
w.middlewareRW.Write(p)
51+
return w.ResponseWriter.Write(p)
52+
}

middleware/gin/gin_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package gin_test
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
8+
"github.com/gin-gonic/gin"
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/mock"
11+
12+
mmetrics "github.com/slok/go-http-metrics/internal/mocks/metrics"
13+
"github.com/slok/go-http-metrics/middleware"
14+
ginmiddleware "github.com/slok/go-http-metrics/middleware/gin"
15+
)
16+
17+
func getTestHandler(statusCode int) gin.HandlerFunc {
18+
return func(c *gin.Context) {
19+
c.String(statusCode, "Hello world")
20+
}
21+
}
22+
23+
func TestMiddlewareIntegration(t *testing.T) {
24+
tests := []struct {
25+
name string
26+
handlerID string
27+
statusCode int
28+
req *http.Request
29+
config middleware.Config
30+
expHandlerID string
31+
expMethod string
32+
expStatusCode string
33+
}{
34+
{
35+
name: "A default HTTP middleware should call the recorder to measure.",
36+
statusCode: http.StatusAccepted,
37+
req: httptest.NewRequest(http.MethodPost, "/test", nil),
38+
expHandlerID: "/test",
39+
expMethod: http.MethodPost,
40+
expStatusCode: "202",
41+
},
42+
}
43+
44+
for _, test := range tests {
45+
t.Run(test.name, func(t *testing.T) {
46+
assert := assert.New(t)
47+
48+
// Mocks.
49+
mr := &mmetrics.Recorder{}
50+
mr.On("ObserveHTTPRequestDuration", mock.Anything, test.expHandlerID, mock.Anything, test.expMethod, test.expStatusCode).Once()
51+
mr.On("ObserveHTTPResponseSize", mock.Anything, test.expHandlerID, mock.Anything, test.expMethod, test.expStatusCode).Once()
52+
mr.On("AddInflightRequests", mock.Anything, test.expHandlerID, 1).Once()
53+
mr.On("AddInflightRequests", mock.Anything, test.expHandlerID, -1).Once()
54+
55+
// Create our instance with the middleware.
56+
mdlw := middleware.New(middleware.Config{Recorder: mr})
57+
engine := gin.New()
58+
engine.POST("/test",
59+
ginmiddleware.Handler("", mdlw),
60+
getTestHandler(test.statusCode))
61+
62+
// Make the request.
63+
resp := httptest.NewRecorder()
64+
engine.ServeHTTP(resp, test.req)
65+
66+
// Check.
67+
mr.AssertExpectations(t)
68+
assert.Equal(test.statusCode, resp.Result().StatusCode)
69+
})
70+
}
71+
}

0 commit comments

Comments
 (0)