From 8bb588a06570bd45ced31527113e1535e34a21e3 Mon Sep 17 00:00:00 2001 From: Phil Winder Date: Tue, 21 Mar 2017 15:52:49 +0000 Subject: [PATCH] Refactor to use middleware from weaveworks/common. --- .travis.yml | 2 +- cmd/cataloguesvc/main.go | 18 ++- docker/catalogue/Dockerfile | 2 +- middleware/instrument.go | 94 ---------------- middleware/middleware.go | 33 ------ scripts/build.sh | 1 - test/unit.py | 2 +- vendor/manifest | 214 +++++++++++++++++++++++++++++++++++- 8 files changed, 229 insertions(+), 137 deletions(-) delete mode 100644 middleware/instrument.go delete mode 100644 middleware/middleware.go diff --git a/.travis.yml b/.travis.yml index d93d0498..fbead0b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ sudo: required services: - docker go: - - 1.6 + - 1.7 before_install: - go get -u github.com/FiloSottile/gvt - gvt restore diff --git a/cmd/cataloguesvc/main.go b/cmd/cataloguesvc/main.go index cee10a68..779e2797 100644 --- a/cmd/cataloguesvc/main.go +++ b/cmd/cataloguesvc/main.go @@ -18,7 +18,8 @@ import ( _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" "github.com/microservices-demo/catalogue" - "github.com/microservices-demo/catalogue/middleware" + "github.com/prometheus/client_golang/prometheus" + "github.com/weaveworks/common/middleware" "golang.org/x/net/context" ) @@ -26,6 +27,18 @@ const ( ServiceName = "catalogue" ) +var ( + HTTPLatency = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "request_duration_seconds", + Help: "Time (in seconds) spent serving HTTP requests.", + Buckets: prometheus.DefBuckets, + }, []string{"service", "method", "route", "status_code"}) +) + +func init() { + prometheus.MustRegister(HTTPLatency) +} + func main() { var ( port = flag.String("port", "8081", "Port to bind HTTP listener") // TODO(pb): should be -addr, default ":8081" @@ -110,9 +123,8 @@ func main() { httpMiddleware := []middleware.Interface{ middleware.Instrument{ - Duration: middleware.HTTPLatency, + Duration: HTTPLatency, RouteMatcher: router, - Service: ServiceName, }, } diff --git a/docker/catalogue/Dockerfile b/docker/catalogue/Dockerfile index 34ae7ce3..1d60a96a 100644 --- a/docker/catalogue/Dockerfile +++ b/docker/catalogue/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.6 +FROM golang:1.7 RUN mkdir /app COPY . /go/src/github.com/microservices-demo/catalogue/ diff --git a/middleware/instrument.go b/middleware/instrument.go deleted file mode 100644 index 3ec1b921..00000000 --- a/middleware/instrument.go +++ /dev/null @@ -1,94 +0,0 @@ -package middleware - -import ( - "net/http" - "regexp" - "strconv" - "strings" - "time" - - "github.com/felixge/httpsnoop" - "github.com/gorilla/mux" - "github.com/prometheus/client_golang/prometheus" -) - -var ( - HTTPLatency = prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Name: "request_duration_seconds", - Help: "Time (in seconds) spent serving HTTP requests.", - Buckets: prometheus.DefBuckets, - }, []string{"service", "method", "route", "status_code"}) -) - -func init() { - prometheus.MustRegister(HTTPLatency) -} - -// RouteMatcher matches routes -type RouteMatcher interface { - Match(*http.Request, *mux.RouteMatch) bool -} - -// Instrument is a Middleware which records timings for every HTTP request -type Instrument struct { - RouteMatcher RouteMatcher - Duration *prometheus.HistogramVec - Service string -} - -// Wrap implements middleware.Interface -func (i Instrument) Wrap(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - begin := time.Now() - interceptor := httpsnoop.CaptureMetrics(next, w, r) - route := i.getRouteName(r) - var ( - status = strconv.Itoa(interceptor.Code) - took = time.Since(begin) - ) - i.Duration.WithLabelValues(i.Service, r.Method, route, status).Observe(took.Seconds()) - }) -} - -// Return a name identifier for ths request. There are three options: -// 1. The request matches a gorilla mux route, with a name. Use that. -// 2. The request matches an unamed gorilla mux router. Munge the path -// template such that templates like '/api/{org}/foo' come out as -// 'api_org_foo'. -// 3. The request doesn't match a mux route. Munge the Path in the same -// manner as (2). -// We do all this as we do not wish to emit high cardinality labels to -// prometheus. -func (i Instrument) getRouteName(r *http.Request) string { - var routeMatch mux.RouteMatch - if i.RouteMatcher != nil && i.RouteMatcher.Match(r, &routeMatch) { - if name := routeMatch.Route.GetName(); name != "" { - return name - } - if tmpl, err := routeMatch.Route.GetPathTemplate(); err == nil { - return MakeLabelValue(tmpl) - } - } - return MakeLabelValue(r.URL.Path) -} - -var invalidChars = regexp.MustCompile(`[^a-zA-Z0-9]+`) - -// MakeLabelValue converts a Gorilla mux path to a string suitable for use in -// a Prometheus label value. -func MakeLabelValue(path string) string { - // Convert non-alnums to underscores. - result := invalidChars.ReplaceAllString(path, "_") - - // Trim leading and trailing underscores. - result = strings.Trim(result, "_") - - // Make it all lowercase - result = strings.ToLower(result) - - // Special case. - if result == "" { - result = "root" - } - return result -} diff --git a/middleware/middleware.go b/middleware/middleware.go deleted file mode 100644 index ad8925ac..00000000 --- a/middleware/middleware.go +++ /dev/null @@ -1,33 +0,0 @@ -package middleware - -import ( - "net/http" -) - -// Interface is the shared contract for all middlesware, and allows middlesware -// to wrap handlers. -type Interface interface { - Wrap(http.Handler) http.Handler -} - -// Func is to Interface as http.HandlerFunc is to http.Handler -type Func func(http.Handler) http.Handler - -// Wrap implements Interface -func (m Func) Wrap(next http.Handler) http.Handler { - return m(next) -} - -// Identity is an Interface which doesn't do anything. -var Identity Interface = Func(func(h http.Handler) http.Handler { return h }) - -// Merge produces a middleware that applies multiple middlesware in turn; -// ie Merge(f,g,h).Wrap(handler) == f.Wrap(g.Wrap(h.Wrap(handler))) -func Merge(middlesware ...Interface) Interface { - return Func(func(next http.Handler) http.Handler { - for i := len(middlesware) - 1; i >= 0; i-- { - next = middlesware[i].Wrap(next) - } - return next - }) -} diff --git a/scripts/build.sh b/scripts/build.sh index cfd24423..f73e6a56 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -27,7 +27,6 @@ echo $CODE_DIR cp -r $CODE_DIR/images/ $CODE_DIR/docker/catalogue/images/ cp -r $CODE_DIR/cmd/ $CODE_DIR/docker/catalogue/cmd/ -cp -r $CODE_DIR/middleware/ $CODE_DIR/docker/catalogue/middleware/ cp $CODE_DIR/*.go $CODE_DIR/docker/catalogue/ mkdir -p $CODE_DIR/docker/catalogue/vendor && cp $CODE_DIR/vendor/manifest $CODE_DIR/docker/catalogue/vendor/ diff --git a/test/unit.py b/test/unit.py index 9c9305a8..fc1ed6fc 100755 --- a/test/unit.py +++ b/test/unit.py @@ -11,7 +11,7 @@ def test_go(self): code_dir = script_dir + "/.." home = expanduser("~") goPath = os.environ['GOPATH'] - command = ['docker', 'run', '--rm', '-v', goPath + ':/go/src/', '-v', code_dir + ':/go/src/github.com/microservices-demo/catalogue', '-w', '/go/src/github.com/microservices-demo/catalogue', '-e', 'GOPATH=/go/', 'golang:1.6', 'go', 'test', '-v', '-covermode=count', '-coverprofile=coverage.out'] + command = ['docker', 'run', '--rm', '-v', goPath + ':/go/src/', '-v', code_dir + ':/go/src/github.com/microservices-demo/catalogue', '-w', '/go/src/github.com/microservices-demo/catalogue', '-e', 'GOPATH=/go/', 'golang:1.7', 'go', 'test', '-v', '-covermode=count', '-coverprofile=coverage.out'] print(Docker().execute(command)) diff --git a/vendor/manifest b/vendor/manifest index cde1db69..8c1d1491 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -1,6 +1,24 @@ { "version": 0, "dependencies": [ + { + "importpath": "cloud.google.com/go/compute/metadata", + "repository": "https://code.googlesource.com/gocloud", + "vcs": "git", + "revision": "daf945bb8684eb8df711af0c3e3a07930a2a01b0", + "branch": "master", + "path": "/compute/metadata", + "notests": true + }, + { + "importpath": "cloud.google.com/go/internal", + "repository": "https://code.googlesource.com/gocloud", + "vcs": "git", + "revision": "daf945bb8684eb8df711af0c3e3a07930a2a01b0", + "branch": "master", + "path": "internal", + "notests": true + }, { "importpath": "github.com/Shopify/sarama", "repository": "https://github.com/Shopify/sarama", @@ -9,6 +27,14 @@ "branch": "master", "notests": true }, + { + "importpath": "github.com/Sirupsen/logrus", + "repository": "https://github.com/Sirupsen/logrus", + "vcs": "git", + "revision": "10f801ebc38b33738c9d17d50860f484a0988ff5", + "branch": "master", + "notests": true + }, { "importpath": "github.com/VividCortex/gohistogram", "repository": "https://github.com/VividCortex/gohistogram", @@ -216,6 +242,23 @@ "path": "types", "notests": true }, + { + "importpath": "github.com/golang/glog", + "repository": "https://github.com/golang/glog", + "vcs": "git", + "revision": "23def4e6c14b4da8ac2ed8007337bc5eb5007998", + "branch": "master", + "notests": true + }, + { + "importpath": "github.com/golang/mock/gomock", + "repository": "https://github.com/golang/mock", + "vcs": "git", + "revision": "bd3c8e81be01eef76d4b503f5e687d2d1354d2d9", + "branch": "master", + "path": "/gomock", + "notests": true + }, { "importpath": "github.com/golang/protobuf/proto", "repository": "https://github.com/golang/protobuf", @@ -225,6 +268,15 @@ "path": "/proto", "notests": true }, + { + "importpath": "github.com/golang/protobuf/protoc-gen-go/descriptor", + "repository": "https://github.com/golang/protobuf", + "vcs": "git", + "revision": "c9c7427a2a70d2eb3bafa0ab2dc163e45f143317", + "branch": "master", + "path": "/protoc-gen-go/descriptor", + "notests": true + }, { "importpath": "github.com/golang/protobuf/ptypes/any", "repository": "https://github.com/golang/protobuf", @@ -242,6 +294,14 @@ "branch": "master", "notests": true }, + { + "importpath": "github.com/googleapis/gax-go", + "repository": "https://github.com/googleapis/gax-go", + "vcs": "git", + "revision": "9af46dd5a1713e8b5cd71106287eba3cefdde50b", + "branch": "master", + "notests": true + }, { "importpath": "github.com/gorilla/context", "repository": "https://github.com/gorilla/context", @@ -516,6 +576,60 @@ "notests": true, "allfiles": true }, + { + "importpath": "github.com/weaveworks/common/errors", + "repository": "https://github.com/weaveworks/common", + "vcs": "git", + "revision": "f94043b3da140c7a735b1f2f286d72d19014b200", + "branch": "master", + "path": "errors", + "notests": true + }, + { + "importpath": "github.com/weaveworks/common/middleware", + "repository": "https://github.com/weaveworks/common", + "vcs": "git", + "revision": "f94043b3da140c7a735b1f2f286d72d19014b200", + "branch": "master", + "path": "/middleware", + "notests": true + }, + { + "importpath": "github.com/weaveworks/common/user", + "repository": "https://github.com/weaveworks/common", + "vcs": "git", + "revision": "f94043b3da140c7a735b1f2f286d72d19014b200", + "branch": "master", + "path": "user", + "notests": true + }, + { + "importpath": "go4.org/syncutil/singleflight", + "repository": "https://github.com/camlistore/go4", + "vcs": "git", + "revision": "169ea6cabe2a4888dba958edaecc9e9751adc711", + "branch": "master", + "path": "/syncutil/singleflight", + "notests": true + }, + { + "importpath": "golang.org/x/crypto/acme", + "repository": "https://go.googlesource.com/crypto", + "vcs": "git", + "revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7", + "branch": "master", + "path": "acme", + "notests": true + }, + { + "importpath": "golang.org/x/crypto/ssh/terminal", + "repository": "https://go.googlesource.com/crypto", + "vcs": "git", + "revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7", + "branch": "master", + "path": "/ssh/terminal", + "notests": true + }, { "importpath": "golang.org/x/net/context", "repository": "https://go.googlesource.com/net", @@ -525,6 +639,24 @@ "path": "/context", "notests": true }, + { + "importpath": "golang.org/x/net/http2", + "repository": "https://go.googlesource.com/net", + "vcs": "git", + "revision": "a6577fac2d73be281a500b310739095313165611", + "branch": "master", + "path": "http2", + "notests": true + }, + { + "importpath": "golang.org/x/net/idna", + "repository": "https://go.googlesource.com/net", + "vcs": "git", + "revision": "a6577fac2d73be281a500b310739095313165611", + "branch": "master", + "path": "idna", + "notests": true + }, { "importpath": "golang.org/x/net/internal/timeseries", "repository": "https://go.googlesource.com/net", @@ -534,6 +666,15 @@ "path": "internal/timeseries", "notests": true }, + { + "importpath": "golang.org/x/net/lex/httplex", + "repository": "https://go.googlesource.com/net", + "vcs": "git", + "revision": "a6577fac2d73be281a500b310739095313165611", + "branch": "master", + "path": "lex/httplex", + "notests": true + }, { "importpath": "golang.org/x/net/trace", "repository": "https://go.googlesource.com/net", @@ -543,6 +684,23 @@ "path": "/trace", "notests": true }, + { + "importpath": "golang.org/x/oauth2", + "repository": "https://go.googlesource.com/oauth2", + "vcs": "git", + "revision": "7fdf09982454086d5570c7db3e11f360194830ca", + "branch": "master", + "notests": true + }, + { + "importpath": "golang.org/x/sys/unix", + "repository": "https://go.googlesource.com/sys", + "vcs": "git", + "revision": "99f16d856c9836c42d24e7ab64ea72916925fa97", + "branch": "master", + "path": "/unix", + "notests": true + }, { "importpath": "golang.org/x/tools/cmd/cover", "repository": "https://go.googlesource.com/tools", @@ -562,12 +720,46 @@ "notests": true }, { - "importpath": "google.golang.org/grpc/metadata", + "importpath": "google.golang.org/api/compute/v1", + "repository": "https://code.googlesource.com/google-api-go-client", + "vcs": "git", + "revision": "16ab375f94503bfa0d19db78e96bffbe1a34354f", + "branch": "master", + "path": "/compute/v1", + "notests": true + }, + { + "importpath": "google.golang.org/api/gensupport", + "repository": "https://code.googlesource.com/google-api-go-client", + "vcs": "git", + "revision": "16ab375f94503bfa0d19db78e96bffbe1a34354f", + "branch": "master", + "path": "gensupport", + "notests": true + }, + { + "importpath": "google.golang.org/api/googleapi", + "repository": "https://code.googlesource.com/google-api-go-client", + "vcs": "git", + "revision": "16ab375f94503bfa0d19db78e96bffbe1a34354f", + "branch": "master", + "path": "googleapi", + "notests": true + }, + { + "importpath": "google.golang.org/appengine", + "repository": "https://github.com/golang/appengine", + "vcs": "git", + "revision": "b79c28f0197795b4050bfcd7c4c2209136c594b1", + "branch": "master", + "notests": true + }, + { + "importpath": "google.golang.org/grpc", "repository": "https://github.com/grpc/grpc-go", "vcs": "git", - "revision": "9d682f9293b408c42d17c587d0e2a31237ac3f10", + "revision": "cdee119ee21e61eef7093a41ba148fa83585e143", "branch": "master", - "path": "/metadata", "notests": true }, { @@ -577,6 +769,22 @@ "revision": "d4cd2ca2ad1cc2130bba385aab072218f131f636", "branch": "master", "notests": true + }, + { + "importpath": "gopkg.in/airbrake/gobrake.v2", + "repository": "https://gopkg.in/airbrake/gobrake.v2", + "vcs": "git", + "revision": "668876711219e8b0206e2994bf0a59d889c775aa", + "branch": "master", + "notests": true + }, + { + "importpath": "gopkg.in/gemnasium/logrus-airbrake-hook.v2", + "repository": "https://gopkg.in/gemnasium/logrus-airbrake-hook.v2", + "vcs": "git", + "revision": "bfee1239d796830ca346767650cce5ba90d58c57", + "branch": "master", + "notests": true } ] } \ No newline at end of file