Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Added

- New middleware helper for the Goji framework.

## [0.7.0] - 2020-06-02

Breaking change: The library has been refactored to be more flexible when adding new framework/libraries.
Expand Down
2 changes: 2 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ The middleware is mainly focused to be compatible with Go std library using http
- [go-restful][gorestful-example]
- [Gin][gin-example]
- [Echo][echo-example]
- [Goji][goji-example]

## Getting Started

Expand Down Expand Up @@ -212,5 +213,6 @@ This Option is used to unregister the Recorder views before are being registered
[gorestful-example]: examples/gorestful
[gin-example]: examples/gin
[echo-example]: examples/echo
[goji-example]: examples/goji
[prometheus-recorder]: metrics/prometheus
[opencensus-recorder]: metrics/opencensus
58 changes: 58 additions & 0 deletions examples/goji/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package main

import (
"log"
"net/http"
"os"
"os/signal"
"syscall"

"github.com/prometheus/client_golang/prometheus/promhttp"
metrics "github.com/slok/go-http-metrics/metrics/prometheus"
"github.com/slok/go-http-metrics/middleware"
gojimiddleware "github.com/slok/go-http-metrics/middleware/goji"
"goji.io"
"goji.io/pat"
)

const (
srvAddr = ":8080"
metricsAddr = ":8081"
)

func main() {
// Create our middleware.
mdlw := middleware.New(middleware.Config{
Recorder: metrics.NewRecorder(metrics.Config{}),
})

// Create our router with the metrics middleware.
mux := goji.NewMux()
mux.Use(gojimiddleware.Handler("", mdlw))

mux.HandleFunc(pat.Get("/"), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("Hello world"))
}))

// Serve our handler.
go func() {
log.Printf("server listening at %s", srvAddr)
if err := http.ListenAndServe(srvAddr, mux); err != nil {
log.Panicf("error while serving: %s", err)
}
}()

// Serve our metrics.
go func() {
log.Printf("metrics listening at %s", metricsAddr)
if err := http.ListenAndServe(metricsAddr, promhttp.Handler()); err != nil {
log.Panicf("error while serving metrics: %s", err)
}
}()

// Wait until some signal is captured.
sigC := make(chan os.Signal, 1)
signal.Notify(sigC, syscall.SIGTERM, syscall.SIGINT)
<-sigC
}
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/stretchr/testify v1.6.0
github.com/urfave/negroni v1.0.0
go.opencensus.io v0.22.3
goji.io v2.0.2+incompatible
)

go 1.13
go 1.14
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg=
contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
Expand Down Expand Up @@ -161,6 +162,8 @@ go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
goji.io v2.0.2+incompatible h1:uIssv/elbKRLznFUy3Xj4+2Mz/qKhek/9aZQDUMae7c=
goji.io v2.0.2+incompatible/go.mod h1:sbqFwrtqZACxLBTQcdgVjFh54yGVCvwq8+w49MVMMIk=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
Expand Down
47 changes: 47 additions & 0 deletions middleware/goji/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package goji_test

import (
"log"
"net/http"

"github.com/prometheus/client_golang/prometheus/promhttp"
"goji.io"
"goji.io/pat"

metrics "github.com/slok/go-http-metrics/metrics/prometheus"
"github.com/slok/go-http-metrics/middleware"
gojimiddleware "github.com/slok/go-http-metrics/middleware/goji"
)

// GojiMiddleware shows how you would create a default middleware factory and use it
// to create a Goji compatible middleware.
func Example_gojiMiddleware() {
// Create our middleware factory with the default settings.
mdlw := middleware.New(middleware.Config{
Recorder: metrics.NewRecorder(metrics.Config{}),
})

// Create our Goji instance.
mux := goji.NewMux()

// Add our middleware.
mux.Use(gojimiddleware.Handler("", mdlw))

// Add our handler.
mux.HandleFunc(pat.Get("/"), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("Hello world"))
}))

// Serve metrics from the default prometheus registry.
log.Printf("serving metrics at: %s", ":8081")
go func() {
_ = http.ListenAndServe(":8081", promhttp.Handler())
}()

// Serve our handler.
log.Printf("listening at: %s", ":8080")
if err := http.ListenAndServe(":8080", mux); err != nil {
log.Panicf("error while serving: %s", err)
}
}
16 changes: 16 additions & 0 deletions middleware/goji/goji.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Package goji is a helper package to get a goji compatible middleware.
package goji

import (
"net/http"

"github.com/slok/go-http-metrics/middleware"
"github.com/slok/go-http-metrics/middleware/std"
)

// Handler returns a Goji measuring middleware.
func Handler(handlerID string, m middleware.Middleware) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return std.Handler(handlerID, m, next)
}
}
91 changes: 91 additions & 0 deletions middleware/goji/goji_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package goji_test

import (
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"goji.io"
"goji.io/pat"

mmetrics "github.com/slok/go-http-metrics/internal/mocks/metrics"
"github.com/slok/go-http-metrics/metrics"
"github.com/slok/go-http-metrics/middleware"
gojimiddleware "github.com/slok/go-http-metrics/middleware/goji"
)

func TestMiddleware(t *testing.T) {
tests := map[string]struct {
handlerID string
config middleware.Config
req func() *http.Request
mock func(m *mmetrics.Recorder)
handler func() http.Handler
expRespCode int
expRespBody string
}{
"A default HTTP middleware should call the recorder to measure.": {
req: func() *http.Request {
return httptest.NewRequest(http.MethodPost, "/test", nil)
},
mock: func(m *mmetrics.Recorder) {
expHTTPReqProps := metrics.HTTPReqProperties{
ID: "/test",
Service: "",
Method: "POST",
Code: "202",
}
m.On("ObserveHTTPRequestDuration", mock.Anything, expHTTPReqProps, mock.Anything).Once()
m.On("ObserveHTTPResponseSize", mock.Anything, expHTTPReqProps, int64(5)).Once()

expHTTPProps := metrics.HTTPProperties{
ID: "/test",
Service: "",
}
m.On("AddInflightRequests", mock.Anything, expHTTPProps, 1).Once()
m.On("AddInflightRequests", mock.Anything, expHTTPProps, -1).Once()
},
handler: func() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(202)
w.Write([]byte("test1")) // nolint: errcheck
})
},
expRespCode: 202,
expRespBody: "test1",
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
require := require.New(t)

// Mocks.
mr := &mmetrics.Recorder{}
test.mock(mr)

// Create our instance with the middleware.
mdlw := middleware.New(middleware.Config{Recorder: mr})
mux := goji.NewMux()
req := test.req()
mux.Handle(pat.NewWithMethods(req.URL.Path, req.Method), test.handler())
mux.Use(gojimiddleware.Handler(test.handlerID, mdlw))

// Make the request.
resp := httptest.NewRecorder()
mux.ServeHTTP(resp, req)

// Check.
mr.AssertExpectations(t)
assert.Equal(test.expRespCode, resp.Result().StatusCode)
gotBody, err := ioutil.ReadAll(resp.Result().Body)
require.NoError(err)
assert.Equal(test.expRespBody, string(gotBody))
})
}
}
34 changes: 26 additions & 8 deletions test/integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/urfave/negroni"
"goji.io"
"goji.io/pat"

metricsprometheus "github.com/slok/go-http-metrics/metrics/prometheus"
"github.com/slok/go-http-metrics/middleware"
echomiddleware "github.com/slok/go-http-metrics/middleware/echo"
ginmiddleware "github.com/slok/go-http-metrics/middleware/gin"
gojimiddleware "github.com/slok/go-http-metrics/middleware/goji"
gorestfulmiddleware "github.com/slok/go-http-metrics/middleware/gorestful"
httproutermiddleware "github.com/slok/go-http-metrics/middleware/httprouter"
negronimiddleware "github.com/slok/go-http-metrics/middleware/negroni"
Expand Down Expand Up @@ -50,6 +53,7 @@ func TestMiddlewarePrometheus(t *testing.T) {
"Gorestful": {handler: prepareHandlerGorestful},
"Gin": {handler: prepareHandlerGin},
"Echo": {handler: prepareHandlerEcho},
"Goji": {handler: prepareHandlerGoji},
}

for name, test := range tests {
Expand Down Expand Up @@ -139,8 +143,7 @@ func prepareHandlerSTD(m middleware.Middleware, hc []handlerConfig) http.Handler

time.Sleep(h.SleepDuration)
w.WriteHeader(h.Code)
// nolint: errcheck
w.Write([]byte(h.ReturnData))
w.Write([]byte(h.ReturnData)) // nolint: errcheck
}))
}

Expand All @@ -163,8 +166,7 @@ func prepareHandlerNegroni(m middleware.Middleware, hc []handlerConfig) http.Han

time.Sleep(h.SleepDuration)
w.WriteHeader(h.Code)
// nolint: errcheck
w.Write([]byte(h.ReturnData))
w.Write([]byte(h.ReturnData)) // nolint: errcheck
}))
}

Expand All @@ -185,8 +187,7 @@ func prepareHandlerHTTPRouter(m middleware.Middleware, hc []handlerConfig) http.
hr := func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
time.Sleep(h.SleepDuration)
w.WriteHeader(h.Code)
// nolint: errcheck
w.Write([]byte(h.ReturnData))
w.Write([]byte(h.ReturnData)) // nolint: errcheck
}

// Setup middleware on each of the routes.
Expand All @@ -208,8 +209,7 @@ func prepareHandlerGorestful(m middleware.Middleware, hc []handlerConfig) http.H
ws.Route(ws.Method(h.Method).Path(h.Path).To(func(_ *gorestful.Request, resp *gorestful.Response) {
time.Sleep(h.SleepDuration)
resp.WriteHeader(h.Code)
// nolint: errcheck
resp.Write([]byte(h.ReturnData))
resp.Write([]byte(h.ReturnData)) // nolint: errcheck
}))
}
c.Add(ws)
Expand Down Expand Up @@ -250,3 +250,21 @@ func prepareHandlerEcho(m middleware.Middleware, hc []handlerConfig) http.Handle

return e
}

func prepareHandlerGoji(m middleware.Middleware, hc []handlerConfig) http.Handler {
// Setup server and middleware.
mux := goji.NewMux()
mux.Use(gojimiddleware.Handler("", m))

// Setup handlers.
for _, h := range hc {
h := h
mux.HandleFunc(pat.NewWithMethods(h.Path, h.Method), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(h.SleepDuration)
w.WriteHeader(h.Code)
w.Write([]byte(h.ReturnData)) // nolint: errcheck
}))
}

return mux
}