diff --git a/cmd/paymentsvc/main.go b/cmd/paymentsvc/main.go index 5df1288..dfe14ea 100644 --- a/cmd/paymentsvc/main.go +++ b/cmd/paymentsvc/main.go @@ -3,26 +3,67 @@ package main import ( "flag" "fmt" - "github.com/microservices-demo/payment" - "golang.org/x/net/context" "net/http" "os" "os/signal" "syscall" + + "github.com/go-kit/kit/log" + "github.com/microservices-demo/payment" + stdopentracing "github.com/opentracing/opentracing-go" + zipkin "github.com/openzipkin/zipkin-go-opentracing" + "golang.org/x/net/context" +) + +const ( + ServiceName = "payment" ) func main() { var ( port = flag.String("port", "8080", "Port to bind HTTP listener") + zip = flag.String("zipkin", os.Getenv("ZIPKIN"), "Zipkin address") declineAmount = flag.Float64("decline", 100, "Decline payments over certain amount") ) flag.Parse() + var tracer stdopentracing.Tracer + { + // Log domain. + var logger log.Logger + { + logger = log.NewLogfmtLogger(os.Stderr) + logger = log.NewContext(logger).With("ts", log.DefaultTimestampUTC) + logger = log.NewContext(logger).With("caller", log.DefaultCaller) + } + if *zip == "" { + tracer = stdopentracing.NoopTracer{} + } else { + logger := log.NewContext(logger).With("tracer", "Zipkin") + logger.Log("addr", zip) + collector, err := zipkin.NewHTTPCollector( + *zip, + zipkin.HTTPLogger(logger), + ) + if err != nil { + logger.Log("err", err) + os.Exit(1) + } + tracer, err = zipkin.NewTracer( + zipkin.NewRecorder(collector, false, fmt.Sprintf("localhost:%v", port), ServiceName), + ) + if err != nil { + logger.Log("err", err) + os.Exit(1) + } + } + stdopentracing.InitGlobalTracer(tracer) + } // Mechanical stuff. errc := make(chan error) ctx := context.Background() - handler, logger := payment.WireUp(ctx, float32(*declineAmount)) + handler, logger := payment.WireUp(ctx, float32(*declineAmount), tracer) // Create and launch the HTTP server. go func() { diff --git a/component_test.go b/component_test.go index 6249a99..c5daa20 100644 --- a/component_test.go +++ b/component_test.go @@ -8,6 +8,7 @@ import ( "net/http/httptest" "testing" + "github.com/opentracing/opentracing-go" "golang.org/x/net/context" ) @@ -15,7 +16,7 @@ func TestComponent(t *testing.T) { // Mechanical stuff. ctx := context.Background() - handler, logger := WireUp(ctx, float32(99.99)) + handler, logger := WireUp(ctx, float32(99.99), opentracing.GlobalTracer()) ts := httptest.NewServer(handler) defer ts.Close() diff --git a/docker-compose-zipkin.yml b/docker-compose-zipkin.yml new file mode 100644 index 0000000..011ec17 --- /dev/null +++ b/docker-compose-zipkin.yml @@ -0,0 +1,34 @@ +version: '2' + +services: + payment: + image: weaveworksdemos/payment + hostname: payment + restart: always + cap_drop: + - all + cap_add: + - NET_BIND_SERVICE + read_only: true + environment: + - reschedule=on-node-failure + - ZIPKIN=http://zipkin:9411/api/v1/spans + ports: + - "8082:80" + zipkin: + image: openzipkin/zipkin + hostname: zipkin + restart: always + cap_drop: + - all + cap_add: + - CHOWN + - SETGID + - SETUID + read_only: true + tmpfs: + - /tmp:rw,noexec,nosuid + environment: + - reschedule=on-node-failure + ports: + - "9411:9411" diff --git a/endpoints.go b/endpoints.go index 72948ff..0ef4e40 100644 --- a/endpoints.go +++ b/endpoints.go @@ -2,6 +2,8 @@ package payment import ( "github.com/go-kit/kit/endpoint" + "github.com/go-kit/kit/tracing/opentracing" + stdopentracing "github.com/opentracing/opentracing-go" "golang.org/x/net/context" ) @@ -13,16 +15,20 @@ type Endpoints struct { // MakeEndpoints returns an Endpoints structure, where each endpoint is // backed by the given service. -func MakeEndpoints(s Service) Endpoints { +func MakeEndpoints(s Service, tracer stdopentracing.Tracer) Endpoints { return Endpoints{ - AuthoriseEndpoint: MakeAuthoriseEndpoint(s), - HealthEndpoint: MakeHealthEndpoint(s), + AuthoriseEndpoint: opentracing.TraceServer(tracer, "POST /paymentAuth")(MakeAuthoriseEndpoint(s)), + HealthEndpoint: opentracing.TraceServer(tracer, "GET /health")(MakeHealthEndpoint(s)), } } // MakeListEndpoint returns an endpoint via the given service. func MakeAuthoriseEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { + var span stdopentracing.Span + span, ctx = stdopentracing.StartSpanFromContext(ctx, "authorize payment") + span.SetTag("service", "payment") + defer span.Finish() req := request.(AuthoriseRequest) authorisation, err := s.Authorise(req.Amount) return AuthoriseResponse{Authorisation: authorisation, Err: err}, nil @@ -32,6 +38,10 @@ func MakeAuthoriseEndpoint(s Service) endpoint.Endpoint { // MakeHealthEndpoint returns current health of the given service. func MakeHealthEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { + var span stdopentracing.Span + span, ctx = stdopentracing.StartSpanFromContext(ctx, "health check") + span.SetTag("service", "payment") + defer span.Finish() health := s.Health() return healthResponse{Health: health}, nil } diff --git a/transport.go b/transport.go index 337deea..5f41891 100644 --- a/transport.go +++ b/transport.go @@ -8,14 +8,16 @@ import ( "net/http" "github.com/go-kit/kit/log" + "github.com/go-kit/kit/tracing/opentracing" httptransport "github.com/go-kit/kit/transport/http" "github.com/gorilla/mux" + stdopentracing "github.com/opentracing/opentracing-go" "github.com/prometheus/client_golang/prometheus/promhttp" "golang.org/x/net/context" ) // MakeHTTPHandler mounts the endpoints into a REST-y HTTP handler. -func MakeHTTPHandler(ctx context.Context, e Endpoints, logger log.Logger) http.Handler { +func MakeHTTPHandler(ctx context.Context, e Endpoints, logger log.Logger, tracer stdopentracing.Tracer) http.Handler { r := mux.NewRouter().StrictSlash(false) options := []httptransport.ServerOption{ httptransport.ServerErrorLogger(logger), @@ -27,14 +29,14 @@ func MakeHTTPHandler(ctx context.Context, e Endpoints, logger log.Logger) http.H e.AuthoriseEndpoint, decodeAuthoriseRequest, encodeAuthoriseResponse, - options..., + append(options, httptransport.ServerBefore(opentracing.FromHTTPRequest(tracer, "POST /paymentAuth", logger)))..., )) r.Methods("GET").Path("/health").Handler(httptransport.NewServer( ctx, e.HealthEndpoint, decodeHealthRequest, encodeHealthResponse, - options..., + append(options, httptransport.ServerBefore(opentracing.FromHTTPRequest(tracer, "GET /health", logger)))..., )) r.Handle("/metrics", promhttp.Handler()) return r diff --git a/vendor/manifest b/vendor/manifest index dc0ec77..516d98e 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -1,6 +1,14 @@ { "version": 0, "dependencies": [ + { + "importpath": "github.com/Shopify/sarama", + "repository": "https://github.com/Shopify/sarama", + "vcs": "git", + "revision": "0fb560e5f7fbcaee2f75e3c34174320709f69944", + "branch": "master", + "notests": true + }, { "importpath": "github.com/VividCortex/gohistogram", "repository": "https://github.com/VividCortex/gohistogram", @@ -9,6 +17,15 @@ "branch": "master", "notests": true }, + { + "importpath": "github.com/apache/thrift/lib/go/thrift", + "repository": "https://github.com/apache/thrift", + "vcs": "git", + "revision": "d8bb0e3b9ff7e6cecfc85c01a81280dc3d046430", + "branch": "master", + "path": "/lib/go/thrift", + "notests": true + }, { "importpath": "github.com/beorn7/perks/quantile", "repository": "https://github.com/beorn7/perks", @@ -22,7 +39,7 @@ "importpath": "github.com/circonus-labs/circonus-gometrics", "repository": "https://github.com/circonus-labs/circonus-gometrics", "vcs": "git", - "revision": "4d93a8f79cb1e34a38f99dd13e64e8bfd3df1c72", + "revision": "03493d041ec6ba6c77679bbae9f6129e246c08c7", "branch": "master", "notests": true }, @@ -34,11 +51,45 @@ "branch": "master", "notests": true }, + { + "importpath": "github.com/davecgh/go-spew/spew", + "repository": "https://github.com/davecgh/go-spew", + "vcs": "git", + "revision": "346938d642f2ec3594ed81d874461961cd0faa76", + "branch": "master", + "path": "/spew", + "notests": true + }, + { + "importpath": "github.com/eapache/go-resiliency/breaker", + "repository": "https://github.com/eapache/go-resiliency", + "vcs": "git", + "revision": "b86b1ec0dd4209a588dc1285cdd471e73525c0b3", + "branch": "master", + "path": "/breaker", + "notests": true + }, + { + "importpath": "github.com/eapache/go-xerial-snappy", + "repository": "https://github.com/eapache/go-xerial-snappy", + "vcs": "git", + "revision": "bb955e01b9346ac19dc29eb16586c90ded99a98c", + "branch": "master", + "notests": true + }, + { + "importpath": "github.com/eapache/queue", + "repository": "https://github.com/eapache/queue", + "vcs": "git", + "revision": "44cc805cf13205b55f69e14bcb69867d1ae92f98", + "branch": "master", + "notests": true + }, { "importpath": "github.com/go-kit/kit/endpoint", "repository": "https://github.com/go-kit/kit", "vcs": "git", - "revision": "411d3c2e71f00f2c28d573f8e3a0df901297d4a0", + "revision": "905b60253dbac4a14625ce52217ede00d3a3aca7", "branch": "master", "path": "/endpoint", "notests": true @@ -47,7 +98,7 @@ "importpath": "github.com/go-kit/kit/log", "repository": "https://github.com/go-kit/kit", "vcs": "git", - "revision": "411d3c2e71f00f2c28d573f8e3a0df901297d4a0", + "revision": "905b60253dbac4a14625ce52217ede00d3a3aca7", "branch": "master", "path": "log", "notests": true @@ -56,16 +107,25 @@ "importpath": "github.com/go-kit/kit/metrics", "repository": "https://github.com/go-kit/kit", "vcs": "git", - "revision": "411d3c2e71f00f2c28d573f8e3a0df901297d4a0", + "revision": "905b60253dbac4a14625ce52217ede00d3a3aca7", "branch": "master", "path": "metrics", "notests": true }, + { + "importpath": "github.com/go-kit/kit/tracing/opentracing", + "repository": "https://github.com/go-kit/kit", + "vcs": "git", + "revision": "905b60253dbac4a14625ce52217ede00d3a3aca7", + "branch": "master", + "path": "/tracing/opentracing", + "notests": true + }, { "importpath": "github.com/go-kit/kit/transport/http", "repository": "https://github.com/go-kit/kit", "vcs": "git", - "revision": "411d3c2e71f00f2c28d573f8e3a0df901297d4a0", + "revision": "905b60253dbac4a14625ce52217ede00d3a3aca7", "branch": "master", "path": "/transport/http", "notests": true @@ -74,7 +134,7 @@ "importpath": "github.com/go-kit/kit/util/conn", "repository": "https://github.com/go-kit/kit", "vcs": "git", - "revision": "411d3c2e71f00f2c28d573f8e3a0df901297d4a0", + "revision": "905b60253dbac4a14625ce52217ede00d3a3aca7", "branch": "master", "path": "util/conn", "notests": true @@ -95,6 +155,33 @@ "branch": "master", "notests": true }, + { + "importpath": "github.com/gogo/protobuf/proto", + "repository": "https://github.com/gogo/protobuf", + "vcs": "git", + "revision": "84af2615df1ba1d35cc975ba94b64ee67d6c196e", + "branch": "master", + "path": "/proto", + "notests": true + }, + { + "importpath": "github.com/gogo/protobuf/sortkeys", + "repository": "https://github.com/gogo/protobuf", + "vcs": "git", + "revision": "84af2615df1ba1d35cc975ba94b64ee67d6c196e", + "branch": "master", + "path": "sortkeys", + "notests": true + }, + { + "importpath": "github.com/gogo/protobuf/types", + "repository": "https://github.com/gogo/protobuf", + "vcs": "git", + "revision": "84af2615df1ba1d35cc975ba94b64ee67d6c196e", + "branch": "master", + "path": "types", + "notests": true + }, { "importpath": "github.com/golang/protobuf/proto", "repository": "https://github.com/golang/protobuf", @@ -113,6 +200,14 @@ "path": "ptypes/any", "notests": true }, + { + "importpath": "github.com/golang/snappy", + "repository": "https://github.com/golang/snappy", + "vcs": "git", + "revision": "d9eb7a3d35ec988b8585d4a0068e462c27d28380", + "branch": "master", + "notests": true + }, { "importpath": "github.com/gorilla/context", "repository": "https://github.com/gorilla/context", @@ -149,7 +244,7 @@ "importpath": "github.com/influxdata/influxdb/client/v2", "repository": "https://github.com/influxdata/influxdb", "vcs": "git", - "revision": "b0a1e91ad1d0f2b9c8ccf09ab48ce30bdbe17045", + "revision": "c783c3d05fee10575aa612a3ff87d71b4cba02f4", "branch": "master", "path": "/client/v2", "notests": true @@ -158,7 +253,7 @@ "importpath": "github.com/influxdata/influxdb/models", "repository": "https://github.com/influxdata/influxdb", "vcs": "git", - "revision": "b0a1e91ad1d0f2b9c8ccf09ab48ce30bdbe17045", + "revision": "c783c3d05fee10575aa612a3ff87d71b4cba02f4", "branch": "master", "path": "models", "notests": true @@ -167,11 +262,19 @@ "importpath": "github.com/influxdata/influxdb/pkg/escape", "repository": "https://github.com/influxdata/influxdb", "vcs": "git", - "revision": "b0a1e91ad1d0f2b9c8ccf09ab48ce30bdbe17045", + "revision": "c783c3d05fee10575aa612a3ff87d71b4cba02f4", "branch": "master", "path": "pkg/escape", "notests": true }, + { + "importpath": "github.com/klauspost/crc32", + "repository": "https://github.com/klauspost/crc32", + "vcs": "git", + "revision": "cb6bfca970f6908083f26f39a79009d608efd5cd", + "branch": "master", + "notests": true + }, { "importpath": "github.com/kr/logfmt", "repository": "https://github.com/kr/logfmt", @@ -189,6 +292,24 @@ "path": "/pbutil", "notests": true }, + { + "importpath": "github.com/opentracing/opentracing-go", + "repository": "https://github.com/opentracing/opentracing-go", + "vcs": "git", + "revision": "5e5abf838007b08f96ae057bc182636a178da0b9", + "branch": "master", + "notests": true, + "allfiles": true + }, + { + "importpath": "github.com/openzipkin/zipkin-go-opentracing", + "repository": "https://github.com/openzipkin/zipkin-go-opentracing", + "vcs": "git", + "revision": "594640b9ef7e5c994e8d9499359d693c032d738c", + "branch": "master", + "notests": true, + "allfiles": true + }, { "importpath": "github.com/performancecopilot/speed", "repository": "https://github.com/performancecopilot/speed", @@ -197,6 +318,23 @@ "branch": "master", "notests": true }, + { + "importpath": "github.com/pierrec/lz4", + "repository": "https://github.com/pierrec/lz4", + "vcs": "git", + "revision": "5c9560bfa9ace2bf86080bf40d46b34ae44604df", + "branch": "master", + "notests": true + }, + { + "importpath": "github.com/pierrec/xxHash/xxHash32", + "repository": "https://github.com/pierrec/xxHash", + "vcs": "git", + "revision": "5a004441f897722c627870a981d02b29924215fa", + "branch": "master", + "path": "/xxHash32", + "notests": true + }, { "importpath": "github.com/prometheus/client_golang/prometheus", "repository": "https://github.com/prometheus/client_golang", @@ -219,7 +357,7 @@ "importpath": "github.com/prometheus/common/expfmt", "repository": "https://github.com/prometheus/common", "vcs": "git", - "revision": "195bde7883f7c39ea62b0d92ab7359b5327065cb", + "revision": "6d76b79f239843a04e8ad8dfd8fcadfa3920236f", "branch": "master", "path": "/expfmt", "notests": true @@ -228,7 +366,7 @@ "importpath": "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg", "repository": "https://github.com/prometheus/common", "vcs": "git", - "revision": "195bde7883f7c39ea62b0d92ab7359b5327065cb", + "revision": "6d76b79f239843a04e8ad8dfd8fcadfa3920236f", "branch": "master", "path": "internal/bitbucket.org/ww/goautoneg", "notests": true @@ -237,7 +375,7 @@ "importpath": "github.com/prometheus/common/model", "repository": "https://github.com/prometheus/common", "vcs": "git", - "revision": "195bde7883f7c39ea62b0d92ab7359b5327065cb", + "revision": "6d76b79f239843a04e8ad8dfd8fcadfa3920236f", "branch": "master", "path": "model", "notests": true @@ -250,14 +388,97 @@ "branch": "master", "notests": true }, + { + "importpath": "github.com/rcrowley/go-metrics", + "repository": "https://github.com/rcrowley/go-metrics", + "vcs": "git", + "revision": "1f30fe9094a513ce4c700b9a54458bbb0c96996c", + "branch": "master", + "notests": true + }, + { + "importpath": "github.com/stathat/go", + "repository": "https://github.com/stathat/go", + "vcs": "git", + "revision": "74669b9f388d9d788c97399a0824adbfee78400e", + "branch": "master", + "notests": true + }, + { + "importpath": "github.com/stretchr/testify/assert", + "repository": "https://github.com/stretchr/testify", + "vcs": "git", + "revision": "2402e8e7a02fc811447d11f881aa9746cdc57983", + "branch": "master", + "path": "/assert", + "notests": true, + "allfiles": true + }, + { + "importpath": "github.com/stretchr/testify/require", + "repository": "https://github.com/stretchr/testify", + "vcs": "git", + "revision": "2402e8e7a02fc811447d11f881aa9746cdc57983", + "branch": "master", + "path": "require", + "notests": true, + "allfiles": true + }, + { + "importpath": "github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew", + "repository": "https://github.com/stretchr/testify", + "vcs": "git", + "revision": "2402e8e7a02fc811447d11f881aa9746cdc57983", + "branch": "master", + "path": "vendor/github.com/davecgh/go-spew/spew", + "notests": true, + "allfiles": true + }, + { + "importpath": "github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib", + "repository": "https://github.com/stretchr/testify", + "vcs": "git", + "revision": "2402e8e7a02fc811447d11f881aa9746cdc57983", + "branch": "master", + "path": "vendor/github.com/pmezard/go-difflib/difflib", + "notests": true, + "allfiles": true + }, { "importpath": "golang.org/x/net/context", "repository": "https://go.googlesource.com/net", "vcs": "git", - "revision": "cfae461cedfdcab6e261a26eb77db53695623303", + "revision": "8fd7f25955530b92e73e9e1932a41b522b22ccd9", "branch": "master", "path": "/context", "notests": true + }, + { + "importpath": "golang.org/x/net/internal/timeseries", + "repository": "https://go.googlesource.com/net", + "vcs": "git", + "revision": "8fd7f25955530b92e73e9e1932a41b522b22ccd9", + "branch": "master", + "path": "internal/timeseries", + "notests": true + }, + { + "importpath": "golang.org/x/net/trace", + "repository": "https://go.googlesource.com/net", + "vcs": "git", + "revision": "8fd7f25955530b92e73e9e1932a41b522b22ccd9", + "branch": "master", + "path": "/trace", + "notests": true + }, + { + "importpath": "google.golang.org/grpc/metadata", + "repository": "https://github.com/grpc/grpc-go", + "vcs": "git", + "revision": "c8105071640ef29fce843ed96983e864bb18eb0e", + "branch": "master", + "path": "/metadata", + "notests": true } ] } \ No newline at end of file diff --git a/wiring.go b/wiring.go index 2366480..2542d32 100644 --- a/wiring.go +++ b/wiring.go @@ -8,10 +8,11 @@ import ( "golang.org/x/net/context" kitprometheus "github.com/go-kit/kit/metrics/prometheus" + stdopentracing "github.com/opentracing/opentracing-go" stdprometheus "github.com/prometheus/client_golang/prometheus" ) -func WireUp(ctx context.Context, declineAmount float32) (http.Handler, log.Logger) { +func WireUp(ctx context.Context, declineAmount float32, tracer stdopentracing.Tracer) (http.Handler, log.Logger) { // Log domain. var logger log.Logger { @@ -46,8 +47,8 @@ func WireUp(ctx context.Context, declineAmount float32) (http.Handler, log.Logge } // Endpoint domain. - endpoints := MakeEndpoints(service) + endpoints := MakeEndpoints(service, tracer) - handler := MakeHTTPHandler(ctx, endpoints, logger) + handler := MakeHTTPHandler(ctx, endpoints, logger, tracer) return handler, logger }