pax_global_header00006660000000000000000000000064136225631240014516gustar00rootroot0000000000000052 comment=cc938d52e0cdf4c811ab203f428fcd06f9d9a148 golang-github-go-kit-kit-0.10.0/000077500000000000000000000000001362256312400163005ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/.build.yml000066400000000000000000000011711362256312400202000ustar00rootroot00000000000000image: debian/stable packages: - wget sources: - https://github.com/go-kit/kit tasks: - go_toolchain: | go_version="$(wget -q -O- https://golang.org/VERSION?m=text)" wget -q https://dl.google.com/go/$go_version.linux-amd64.tar.gz sudo tar -C /usr/local -xzf $go_version.linux-amd64.tar.gz sudo ln -s /usr/local/go/bin/go /usr/bin/go go env - dependencies: | mkdir -p $(go env GOPATH)/src/github.com/go-kit mv kit $(go env GOPATH)/src/github.com/go-kit go get -t github.com/go-kit/kit/... - test: | go test -race -v github.com/go-kit/kit/... golang-github-go-kit-kit-0.10.0/.github/000077500000000000000000000000001362256312400176405ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/.github/FUNDING.yml000066400000000000000000000001061362256312400214520ustar00rootroot00000000000000# These are supported funding model platforms github: [peterbourgon] golang-github-go-kit-kit-0.10.0/.gitignore000066400000000000000000000012441362256312400202710ustar00rootroot00000000000000examples/addsvc/addsvc examples/addsvc/client/client examples/apigateway/apigateway examples/profilesvc/profilesvc examples/stringsvc1/stringsvc1 examples/stringsvc2/stringsvc2 examples/stringsvc3/stringsvc3 *.coverprofile # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test _old* # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe # https://github.com/github/gitignore/blob/master/Global/Vim.gitignore # swap [._]*.s[a-w][a-z] [._]s[a-w][a-z] # session Session.vim # temporary .netrwhist *~ # auto-generated tag files tags golang-github-go-kit-kit-0.10.0/.travis.yml000066400000000000000000000003641362256312400204140ustar00rootroot00000000000000language: go env: - COVERALLS_TOKEN=MYSkSqcsWXd6DmP6TnSeiDhtvuL4u6ndp before_install: - go get github.com/mattn/goveralls - go get github.com/modocache/gover script: - go test -race -v ./... - ./coveralls.bash go: - 1.x - tip golang-github-go-kit-kit-0.10.0/CONTRIBUTING.md000066400000000000000000000015071362256312400205340ustar00rootroot00000000000000# Contributing First, thank you for contributing! We love and encourage pull requests from everyone. Before submitting major changes, here are a few guidelines to follow: 1. Check the [open issues][issues] and [pull requests][prs] for existing discussions. 1. Open an [issue][issues] first, to discuss a new feature or enhancement. 1. Write tests, and make sure the test suite passes locally and on CI. 1. Open a pull request, and reference the relevant issue(s). 1. After receiving feedback, [squash your commits][squash] and add a [great commit message][message]. 1. Have fun! [issues]: https://github.com/go-kit/kit/issues [prs]: https://github.com/go-kit/kit/pulls [squash]: http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html [message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html golang-github-go-kit-kit-0.10.0/LICENSE000066400000000000000000000020711362256312400173050ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Peter Bourgon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-github-go-kit-kit-0.10.0/README.md000066400000000000000000000145321362256312400175640ustar00rootroot00000000000000# Go kit
[![Circle CI](https://circleci.com/gh/go-kit/kit.svg?style=shield)](https://circleci.com/gh/go-kit/kit) [![Travis CI](https://travis-ci.org/go-kit/kit.svg?branch=master)](https://travis-ci.org/go-kit/kit) [![builds.sr.ht status](https://builds.sr.ht/~peterbourgon/kit.svg)](https://builds.sr.ht/~peterbourgon/kit?) [![GoDoc](https://godoc.org/github.com/go-kit/kit?status.svg)](https://godoc.org/github.com/go-kit/kit) [![Coverage Status](https://coveralls.io/repos/go-kit/kit/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-kit/kit?branch=master) [![Go Report Card](https://goreportcard.com/badge/go-kit/kit)](https://goreportcard.com/report/go-kit/kit) [![Sourcegraph](https://sourcegraph.com/github.com/go-kit/kit/-/badge.svg)](https://sourcegraph.com/github.com/go-kit/kit?badge) **Go kit** is a **programming toolkit** for building microservices (or elegant monoliths) in Go. We solve common problems in distributed systems and application architecture so you can focus on delivering business value. - Website: [gokit.io](https://gokit.io) - Mailing list: [go-kit](https://groups.google.com/forum/#!forum/go-kit) - Slack: [gophers.slack.com](https://gophers.slack.com) **#go-kit** ([invite](https://gophersinvite.herokuapp.com/)) ## Sponsors - [OrderMyGear](https://www.ordermygear.com) Click on Sponsor, above, for more information on sponsorship. ## Motivation Go has emerged as the language of the server, but it remains underrepresented in so-called "modern enterprise" companies like Facebook, Twitter, Netflix, and SoundCloud. Many of these organizations have turned to JVM-based stacks for their business logic, owing in large part to libraries and ecosystems that directly support their microservice architectures. To reach its next level of success, Go needs more than simple primitives and idioms. It needs a comprehensive toolkit, for coherent distributed programming in the large. Go kit is a set of packages and best practices, which provide a comprehensive, robust, and trustable way of building microservices for organizations of any size. For more details, see [the website](https://gokit.io), [the motivating blog post](http://peter.bourgon.org/go-kit/) and [the video of the talk](https://www.youtube.com/watch?v=iFR_7AKkJFU). See also the [Go kit talk at GopherCon 2015](https://www.youtube.com/watch?v=1AjaZi4QuGo). ## Goals - Operate in a heterogeneous SOA — expect to interact with mostly non-Go-kit services - RPC as the primary messaging pattern - Pluggable serialization and transport — not just JSON over HTTP - Operate within existing infrastructures — no mandates for specific tools or technologies ## Non-goals - Supporting messaging patterns other than RPC (for now) — e.g. MPI, pub/sub, CQRS, etc. - Re-implementing functionality that can be provided by adapting existing software - Having opinions on operational concerns: deployment, configuration, process supervision, orchestration, etc. ## Contributing Please see [CONTRIBUTING.md](/CONTRIBUTING.md). Thank you, [contributors](https://github.com/go-kit/kit/graphs/contributors)! ## Dependency management Go kit is [modules](https://github.com/golang/go/wiki/Modules) aware, and we encourage users to use the standard modules tooling. But Go kit is at major version 0, so it should be compatible with non-modules environments. ## Related projects Projects with a ★ have had particular influence on Go kit's design (or vice-versa). ### Service frameworks - [gizmo](https://github.com/nytimes/gizmo), a microservice toolkit from The New York Times ★ - [go-micro](https://github.com/myodc/go-micro), a microservices client/server library ★ - [gotalk](https://github.com/rsms/gotalk), async peer communication protocol & library - [Kite](https://github.com/koding/kite), a micro-service framework - [gocircuit](https://github.com/gocircuit/circuit), dynamic cloud orchestration ### Individual components - [afex/hystrix-go](https://github.com/afex/hystrix-go), client-side latency and fault tolerance library - [armon/go-metrics](https://github.com/armon/go-metrics), library for exporting performance and runtime metrics to external metrics systems - [codahale/lunk](https://github.com/codahale/lunk), structured logging in the style of Google's Dapper or Twitter's Zipkin - [eapache/go-resiliency](https://github.com/eapache/go-resiliency), resiliency patterns - [sasbury/logging](https://github.com/sasbury/logging), a tagged style of logging - [grpc/grpc-go](https://github.com/grpc/grpc-go), HTTP/2 based RPC - [inconshreveable/log15](https://github.com/inconshreveable/log15), simple, powerful logging for Go ★ - [mailgun/vulcand](https://github.com/vulcand/vulcand), programmatic load balancer backed by etcd - [mattheath/phosphor](https://github.com/mondough/phosphor), distributed system tracing - [pivotal-golang/lager](https://github.com/pivotal-golang/lager), an opinionated logging library - [rubyist/circuitbreaker](https://github.com/rubyist/circuitbreaker), circuit breaker library - [sirupsen/logrus](https://github.com/sirupsen/logrus), structured, pluggable logging for Go ★ - [sourcegraph/appdash](https://github.com/sourcegraph/appdash), application tracing system based on Google's Dapper - [spacemonkeygo/monitor](https://github.com/spacemonkeygo/monitor), data collection, monitoring, instrumentation, and Zipkin client library - [streadway/handy](https://github.com/streadway/handy), net/http handler filters - [vitess/rpcplus](https://godoc.org/github.com/youtube/vitess/go/rpcplus), package rpc + context.Context - [gdamore/mangos](https://github.com/gdamore/mangos), nanomsg implementation in pure Go ### Web frameworks - [Gorilla](http://www.gorillatoolkit.org) - [Gin](https://gin-gonic.com/) - [Negroni](https://github.com/codegangsta/negroni) - [Goji](https://github.com/zenazn/goji) - [Martini](https://github.com/go-martini/martini) - [Beego](http://beego.me/) - [Revel](https://revel.github.io/) (considered [harmful](https://github.com/go-kit/kit/issues/350)) - [GoBuffalo](https://gobuffalo.io/) ## Additional reading - [Architecting for the Cloud](https://slideshare.net/stonse/architecting-for-the-cloud-using-netflixoss-codemash-workshop-29852233) — Netflix - [Dapper, a Large-Scale Distributed Systems Tracing Infrastructure](http://research.google.com/pubs/pub36356.html) — Google - [Your Server as a Function](http://monkey.org/~marius/funsrv.pdf) (PDF) — Twitter golang-github-go-kit-kit-0.10.0/auth/000077500000000000000000000000001362256312400172415ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/auth/basic/000077500000000000000000000000001362256312400203225ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/auth/basic/README.md000066400000000000000000000015621362256312400216050ustar00rootroot00000000000000This package provides a Basic Authentication middleware. It'll try to compare credentials from Authentication request header to a username/password pair in middleware constructor. More details about this type of authentication can be found in [Mozilla article](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication). ## Usage ```go import httptransport "github.com/go-kit/kit/transport/http" httptransport.NewServer( AuthMiddleware(cfg.auth.user, cfg.auth.password, "Example Realm")(makeUppercaseEndpoint()), decodeMappingsRequest, httptransport.EncodeJSONResponse, httptransport.ServerBefore(httptransport.PopulateRequestContext), ) ``` For AuthMiddleware to be able to pick up the Authentication header from an HTTP request we need to pass it through the context with something like ```httptransport.ServerBefore(httptransport.PopulateRequestContext)```.golang-github-go-kit-kit-0.10.0/auth/basic/middleware.go000066400000000000000000000047671362256312400230040ustar00rootroot00000000000000package basic import ( "bytes" "context" "crypto/sha256" "crypto/subtle" "encoding/base64" "fmt" "net/http" "strings" "github.com/go-kit/kit/endpoint" httptransport "github.com/go-kit/kit/transport/http" ) // AuthError represents an authorization error. type AuthError struct { Realm string } // StatusCode is an implementation of the StatusCoder interface in go-kit/http. func (AuthError) StatusCode() int { return http.StatusUnauthorized } // Error is an implementation of the Error interface. func (AuthError) Error() string { return http.StatusText(http.StatusUnauthorized) } // Headers is an implementation of the Headerer interface in go-kit/http. func (e AuthError) Headers() http.Header { return http.Header{ "Content-Type": []string{"text/plain; charset=utf-8"}, "X-Content-Type-Options": []string{"nosniff"}, "WWW-Authenticate": []string{fmt.Sprintf(`Basic realm=%q`, e.Realm)}, } } // parseBasicAuth parses an HTTP Basic Authentication string. // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ([]byte("Aladdin"), []byte("open sesame"), true). func parseBasicAuth(auth string) (username, password []byte, ok bool) { const prefix = "Basic " if !strings.HasPrefix(auth, prefix) { return } c, err := base64.StdEncoding.DecodeString(auth[len(prefix):]) if err != nil { return } s := bytes.IndexByte(c, ':') if s < 0 { return } return c[:s], c[s+1:], true } // Returns a hash of a given slice. func toHashSlice(s []byte) []byte { hash := sha256.Sum256(s) return hash[:] } // AuthMiddleware returns a Basic Authentication middleware for a particular user and password. func AuthMiddleware(requiredUser, requiredPassword, realm string) endpoint.Middleware { requiredUserBytes := toHashSlice([]byte(requiredUser)) requiredPasswordBytes := toHashSlice([]byte(requiredPassword)) return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { auth, ok := ctx.Value(httptransport.ContextKeyRequestAuthorization).(string) if !ok { return nil, AuthError{realm} } givenUser, givenPassword, ok := parseBasicAuth(auth) if !ok { return nil, AuthError{realm} } givenUserBytes := toHashSlice(givenUser) givenPasswordBytes := toHashSlice(givenPassword) if subtle.ConstantTimeCompare(givenUserBytes, requiredUserBytes) == 0 || subtle.ConstantTimeCompare(givenPasswordBytes, requiredPasswordBytes) == 0 { return nil, AuthError{realm} } return next(ctx, request) } } } golang-github-go-kit-kit-0.10.0/auth/basic/middleware_test.go000066400000000000000000000032761362256312400240350ustar00rootroot00000000000000package basic import ( "context" "encoding/base64" "fmt" "testing" httptransport "github.com/go-kit/kit/transport/http" ) func TestWithBasicAuth(t *testing.T) { requiredUser := "test-user" requiredPassword := "test-pass" realm := "test realm" type want struct { result interface{} err error } tests := []struct { name string authHeader interface{} want want }{ {"Isn't valid with nil header", nil, want{nil, AuthError{realm}}}, {"Isn't valid with non-string header", 42, want{nil, AuthError{realm}}}, {"Isn't valid without authHeader", "", want{nil, AuthError{realm}}}, {"Isn't valid for wrong user", makeAuthString("wrong-user", requiredPassword), want{nil, AuthError{realm}}}, {"Isn't valid for wrong password", makeAuthString(requiredUser, "wrong-password"), want{nil, AuthError{realm}}}, {"Is valid for correct creds", makeAuthString(requiredUser, requiredPassword), want{true, nil}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.WithValue(context.TODO(), httptransport.ContextKeyRequestAuthorization, tt.authHeader) result, err := AuthMiddleware(requiredUser, requiredPassword, realm)(passedValidation)(ctx, nil) if result != tt.want.result || err != tt.want.err { t.Errorf("WithBasicAuth() = result: %v, err: %v, want result: %v, want error: %v", result, err, tt.want.result, tt.want.err) } }) } } func makeAuthString(user string, password string) string { data := []byte(fmt.Sprintf("%s:%s", user, password)) return fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString(data)) } func passedValidation(ctx context.Context, request interface{}) (response interface{}, err error) { return true, nil } golang-github-go-kit-kit-0.10.0/auth/casbin/000077500000000000000000000000001362256312400205005ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/auth/casbin/middleware.go000066400000000000000000000044121362256312400231450ustar00rootroot00000000000000package casbin import ( "context" "errors" stdcasbin "github.com/casbin/casbin/v2" "github.com/go-kit/kit/endpoint" ) type contextKey string const ( // CasbinModelContextKey holds the key to store the access control model // in context, it can be a path to configuration file or a casbin/model // Model. CasbinModelContextKey contextKey = "CasbinModel" // CasbinPolicyContextKey holds the key to store the access control policy // in context, it can be a path to policy file or an implementation of // casbin/persist Adapter interface. CasbinPolicyContextKey contextKey = "CasbinPolicy" // CasbinEnforcerContextKey holds the key to retrieve the active casbin // Enforcer. CasbinEnforcerContextKey contextKey = "CasbinEnforcer" ) var ( // ErrModelContextMissing denotes a casbin model was not passed into // the parsing of middleware's context. ErrModelContextMissing = errors.New("CasbinModel is required in context") // ErrPolicyContextMissing denotes a casbin policy was not passed into // the parsing of middleware's context. ErrPolicyContextMissing = errors.New("CasbinPolicy is required in context") // ErrUnauthorized denotes the subject is not authorized to do the action // intended on the given object, based on the context model and policy. ErrUnauthorized = errors.New("Unauthorized Access") ) // NewEnforcer checks whether the subject is authorized to do the specified // action on the given object. If a valid access control model and policy // is given, then the generated casbin Enforcer is stored in the context // with CasbinEnforcer as the key. func NewEnforcer( subject string, object interface{}, action string, ) endpoint.Middleware { return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { casbinModel := ctx.Value(CasbinModelContextKey) casbinPolicy := ctx.Value(CasbinPolicyContextKey) enforcer, err := stdcasbin.NewEnforcer(casbinModel, casbinPolicy) if err != nil { return nil, err } ctx = context.WithValue(ctx, CasbinEnforcerContextKey, enforcer) ok, err := enforcer.Enforce(subject, object, action) if err != nil { return nil, err } if !ok { return nil, ErrUnauthorized } return next(ctx, request) } } } golang-github-go-kit-kit-0.10.0/auth/casbin/middleware_test.go000066400000000000000000000034161362256312400242070ustar00rootroot00000000000000package casbin import ( "context" "testing" stdcasbin "github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2/model" fileadapter "github.com/casbin/casbin/v2/persist/file-adapter" ) func TestStructBaseContext(t *testing.T) { e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil } m := model.NewModel() m.AddDef("r", "r", "sub, obj, act") m.AddDef("p", "p", "sub, obj, act") m.AddDef("e", "e", "some(where (p.eft == allow))") m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)") a := fileadapter.NewAdapter("testdata/keymatch_policy.csv") ctx := context.WithValue(context.Background(), CasbinModelContextKey, m) ctx = context.WithValue(ctx, CasbinPolicyContextKey, a) // positive case middleware := NewEnforcer("alice", "/alice_data/resource1", "GET")(e) ctx1, err := middleware(ctx, struct{}{}) if err != nil { t.Fatalf("Enforcer returned error: %s", err) } _, ok := ctx1.(context.Context).Value(CasbinEnforcerContextKey).(*stdcasbin.Enforcer) if !ok { t.Fatalf("context should contains the active enforcer") } // negative case middleware = NewEnforcer("alice", "/alice_data/resource2", "POST")(e) _, err = middleware(ctx, struct{}{}) if err == nil { t.Fatalf("Enforcer should return error") } } func TestFileBaseContext(t *testing.T) { e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil } ctx := context.WithValue(context.Background(), CasbinModelContextKey, "testdata/basic_model.conf") ctx = context.WithValue(ctx, CasbinPolicyContextKey, "testdata/basic_policy.csv") // positive case middleware := NewEnforcer("alice", "data1", "read")(e) _, err := middleware(ctx, struct{}{}) if err != nil { t.Fatalf("Enforcer returned error: %s", err) } } golang-github-go-kit-kit-0.10.0/auth/casbin/testdata/000077500000000000000000000000001362256312400223115ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/auth/casbin/testdata/basic_model.conf000066400000000000000000000003021362256312400254140ustar00rootroot00000000000000[request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act [policy_effect] e = some(where (p.eft == allow)) [matchers] m = r.sub == p.sub && r.obj == p.obj && r.act == p.actgolang-github-go-kit-kit-0.10.0/auth/casbin/testdata/basic_policy.csv000066400000000000000000000000521362256312400254630ustar00rootroot00000000000000p, alice, data1, read p, bob, data2, writegolang-github-go-kit-kit-0.10.0/auth/casbin/testdata/keymatch_policy.csv000066400000000000000000000002451362256312400262130ustar00rootroot00000000000000p, alice, /alice_data/*, GET p, alice, /alice_data/resource1, POST p, bob, /alice_data/resource2, GET p, bob, /bob_data/*, POST p, cathy, /cathy_data, (GET)|(POST)golang-github-go-kit-kit-0.10.0/auth/jwt/000077500000000000000000000000001362256312400200455ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/auth/jwt/README.md000066400000000000000000000062371362256312400213340ustar00rootroot00000000000000# package auth/jwt `package auth/jwt` provides a set of interfaces for service authorization through [JSON Web Tokens](https://jwt.io/). ## Usage NewParser takes a key function and an expected signing method and returns an `endpoint.Middleware`. The middleware will parse a token passed into the context via the `jwt.JWTTokenContextKey`. If the token is valid, any claims will be added to the context via the `jwt.JWTClaimsContextKey`. ```go import ( stdjwt "github.com/dgrijalva/jwt-go" "github.com/go-kit/kit/auth/jwt" "github.com/go-kit/kit/endpoint" ) func main() { var exampleEndpoint endpoint.Endpoint { kf := func(token *stdjwt.Token) (interface{}, error) { return []byte("SigningString"), nil } exampleEndpoint = MakeExampleEndpoint(service) exampleEndpoint = jwt.NewParser(kf, stdjwt.SigningMethodHS256, jwt.StandardClaimsFactory)(exampleEndpoint) } } ``` NewSigner takes a JWT key ID header, the signing key, signing method, and a claims object. It returns an `endpoint.Middleware`. The middleware will build the token string and add it to the context via the `jwt.JWTTokenContextKey`. ```go import ( stdjwt "github.com/dgrijalva/jwt-go" "github.com/go-kit/kit/auth/jwt" "github.com/go-kit/kit/endpoint" ) func main() { var exampleEndpoint endpoint.Endpoint { exampleEndpoint = grpctransport.NewClient(...).Endpoint() exampleEndpoint = jwt.NewSigner( "kid-header", []byte("SigningString"), stdjwt.SigningMethodHS256, jwt.Claims{}, )(exampleEndpoint) } } ``` In order for the parser and the signer to work, the authorization headers need to be passed between the request and the context. `HTTPToContext()`, `ContextToHTTP()`, `GRPCToContext()`, and `ContextToGRPC()` are given as helpers to do this. These functions implement the correlating transport's RequestFunc interface and can be passed as ClientBefore or ServerBefore options. Example of use in a client: ```go import ( stdjwt "github.com/dgrijalva/jwt-go" grpctransport "github.com/go-kit/kit/transport/grpc" "github.com/go-kit/kit/auth/jwt" "github.com/go-kit/kit/endpoint" ) func main() { options := []httptransport.ClientOption{} var exampleEndpoint endpoint.Endpoint { exampleEndpoint = grpctransport.NewClient(..., grpctransport.ClientBefore(jwt.ContextToGRPC())).Endpoint() exampleEndpoint = jwt.NewSigner( "kid-header", []byte("SigningString"), stdjwt.SigningMethodHS256, jwt.Claims{}, )(exampleEndpoint) } } ``` Example of use in a server: ```go import ( "context" "github.com/go-kit/kit/auth/jwt" "github.com/go-kit/kit/log" grpctransport "github.com/go-kit/kit/transport/grpc" ) func MakeGRPCServer(ctx context.Context, endpoints Endpoints, logger log.Logger) pb.ExampleServer { options := []grpctransport.ServerOption{grpctransport.ServerErrorLogger(logger)} return &grpcServer{ createUser: grpctransport.NewServer( ctx, endpoints.CreateUserEndpoint, DecodeGRPCCreateUserRequest, EncodeGRPCCreateUserResponse, append(options, grpctransport.ServerBefore(jwt.GRPCToContext()))..., ), getUser: grpctransport.NewServer( ctx, endpoints.GetUserEndpoint, DecodeGRPCGetUserRequest, EncodeGRPCGetUserResponse, options..., ), } } ``` golang-github-go-kit-kit-0.10.0/auth/jwt/middleware.go000066400000000000000000000113661362256312400225200ustar00rootroot00000000000000package jwt import ( "context" "errors" jwt "github.com/dgrijalva/jwt-go" "github.com/go-kit/kit/endpoint" ) type contextKey string const ( // JWTTokenContextKey holds the key used to store a JWT Token in the // context. JWTTokenContextKey contextKey = "JWTToken" // JWTClaimsContextKey holds the key used to store the JWT Claims in the // context. JWTClaimsContextKey contextKey = "JWTClaims" ) var ( // ErrTokenContextMissing denotes a token was not passed into the parsing // middleware's context. ErrTokenContextMissing = errors.New("token up for parsing was not passed through the context") // ErrTokenInvalid denotes a token was not able to be validated. ErrTokenInvalid = errors.New("JWT Token was invalid") // ErrTokenExpired denotes a token's expire header (exp) has since passed. ErrTokenExpired = errors.New("JWT Token is expired") // ErrTokenMalformed denotes a token was not formatted as a JWT token. ErrTokenMalformed = errors.New("JWT Token is malformed") // ErrTokenNotActive denotes a token's not before header (nbf) is in the // future. ErrTokenNotActive = errors.New("token is not valid yet") // ErrUnexpectedSigningMethod denotes a token was signed with an unexpected // signing method. ErrUnexpectedSigningMethod = errors.New("unexpected signing method") ) // NewSigner creates a new JWT token generating middleware, specifying key ID, // signing string, signing method and the claims you would like it to contain. // Tokens are signed with a Key ID header (kid) which is useful for determining // the key to use for parsing. Particularly useful for clients. func NewSigner(kid string, key []byte, method jwt.SigningMethod, claims jwt.Claims) endpoint.Middleware { return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { token := jwt.NewWithClaims(method, claims) token.Header["kid"] = kid // Sign and get the complete encoded token as a string using the secret tokenString, err := token.SignedString(key) if err != nil { return nil, err } ctx = context.WithValue(ctx, JWTTokenContextKey, tokenString) return next(ctx, request) } } } // ClaimsFactory is a factory for jwt.Claims. // Useful in NewParser middleware. type ClaimsFactory func() jwt.Claims // MapClaimsFactory is a ClaimsFactory that returns // an empty jwt.MapClaims. func MapClaimsFactory() jwt.Claims { return jwt.MapClaims{} } // StandardClaimsFactory is a ClaimsFactory that returns // an empty jwt.StandardClaims. func StandardClaimsFactory() jwt.Claims { return &jwt.StandardClaims{} } // NewParser creates a new JWT token parsing middleware, specifying a // jwt.Keyfunc interface, the signing method and the claims type to be used. NewParser // adds the resulting claims to endpoint context or returns error on invalid token. // Particularly useful for servers. func NewParser(keyFunc jwt.Keyfunc, method jwt.SigningMethod, newClaims ClaimsFactory) endpoint.Middleware { return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { // tokenString is stored in the context from the transport handlers. tokenString, ok := ctx.Value(JWTTokenContextKey).(string) if !ok { return nil, ErrTokenContextMissing } // Parse takes the token string and a function for looking up the // key. The latter is especially useful if you use multiple keys // for your application. The standard is to use 'kid' in the head // of the token to identify which key to use, but the parsed token // (head and claims) is provided to the callback, providing // flexibility. token, err := jwt.ParseWithClaims(tokenString, newClaims(), func(token *jwt.Token) (interface{}, error) { // Don't forget to validate the alg is what you expect: if token.Method != method { return nil, ErrUnexpectedSigningMethod } return keyFunc(token) }) if err != nil { if e, ok := err.(*jwt.ValidationError); ok { switch { case e.Errors&jwt.ValidationErrorMalformed != 0: // Token is malformed return nil, ErrTokenMalformed case e.Errors&jwt.ValidationErrorExpired != 0: // Token is expired return nil, ErrTokenExpired case e.Errors&jwt.ValidationErrorNotValidYet != 0: // Token is not active yet return nil, ErrTokenNotActive case e.Inner != nil: // report e.Inner return nil, e.Inner } // We have a ValidationError but have no specific Go kit error for it. // Fall through to return original error. } return nil, err } if !token.Valid { return nil, ErrTokenInvalid } ctx = context.WithValue(ctx, JWTClaimsContextKey, token.Claims) return next(ctx, request) } } } golang-github-go-kit-kit-0.10.0/auth/jwt/middleware_test.go000066400000000000000000000171671362256312400235640ustar00rootroot00000000000000package jwt import ( "context" "sync" "testing" "time" "crypto/subtle" jwt "github.com/dgrijalva/jwt-go" "github.com/go-kit/kit/endpoint" ) type customClaims struct { MyProperty string `json:"my_property"` jwt.StandardClaims } func (c customClaims) VerifyMyProperty(p string) bool { return subtle.ConstantTimeCompare([]byte(c.MyProperty), []byte(p)) != 0 } var ( kid = "kid" key = []byte("test_signing_key") myProperty = "some value" method = jwt.SigningMethodHS256 invalidMethod = jwt.SigningMethodRS256 mapClaims = jwt.MapClaims{"user": "go-kit"} standardClaims = jwt.StandardClaims{Audience: "go-kit"} myCustomClaims = customClaims{MyProperty: myProperty, StandardClaims: standardClaims} // Signed tokens generated at https://jwt.io/ signedKey = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ28ta2l0In0.14M2VmYyApdSlV_LZ88ajjwuaLeIFplB8JpyNy0A19E" standardSignedKey = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJnby1raXQifQ.L5ypIJjCOOv3jJ8G5SelaHvR04UJuxmcBN5QW3m_aoY" customSignedKey = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJteV9wcm9wZXJ0eSI6InNvbWUgdmFsdWUiLCJhdWQiOiJnby1raXQifQ.s8F-IDrV4WPJUsqr7qfDi-3GRlcKR0SRnkTeUT_U-i0" invalidKey = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.e30.vKVCKto-Wn6rgz3vBdaZaCBGfCBDTXOENSo_X2Gq7qA" malformedKey = "malformed.jwt.token" ) func signingValidator(t *testing.T, signer endpoint.Endpoint, expectedKey string) { ctx, err := signer(context.Background(), struct{}{}) if err != nil { t.Fatalf("Signer returned error: %s", err) } token, ok := ctx.(context.Context).Value(JWTTokenContextKey).(string) if !ok { t.Fatal("Token did not exist in context") } if token != expectedKey { t.Fatalf("JWT tokens did not match: expecting %s got %s", expectedKey, token) } } func TestNewSigner(t *testing.T) { e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil } signer := NewSigner(kid, key, method, mapClaims)(e) signingValidator(t, signer, signedKey) signer = NewSigner(kid, key, method, standardClaims)(e) signingValidator(t, signer, standardSignedKey) signer = NewSigner(kid, key, method, myCustomClaims)(e) signingValidator(t, signer, customSignedKey) } func TestJWTParser(t *testing.T) { e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil } keys := func(token *jwt.Token) (interface{}, error) { return key, nil } parser := NewParser(keys, method, MapClaimsFactory)(e) // No Token is passed into the parser _, err := parser(context.Background(), struct{}{}) if err == nil { t.Error("Parser should have returned an error") } if err != ErrTokenContextMissing { t.Errorf("unexpected error returned, expected: %s got: %s", ErrTokenContextMissing, err) } // Invalid Token is passed into the parser ctx := context.WithValue(context.Background(), JWTTokenContextKey, invalidKey) _, err = parser(ctx, struct{}{}) if err == nil { t.Error("Parser should have returned an error") } // Invalid Method is used in the parser badParser := NewParser(keys, invalidMethod, MapClaimsFactory)(e) ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey) _, err = badParser(ctx, struct{}{}) if err == nil { t.Error("Parser should have returned an error") } if err != ErrUnexpectedSigningMethod { t.Errorf("unexpected error returned, expected: %s got: %s", ErrUnexpectedSigningMethod, err) } // Invalid key is used in the parser invalidKeys := func(token *jwt.Token) (interface{}, error) { return []byte("bad"), nil } badParser = NewParser(invalidKeys, method, MapClaimsFactory)(e) ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey) _, err = badParser(ctx, struct{}{}) if err == nil { t.Error("Parser should have returned an error") } // Correct token is passed into the parser ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey) ctx1, err := parser(ctx, struct{}{}) if err != nil { t.Fatalf("Parser returned error: %s", err) } cl, ok := ctx1.(context.Context).Value(JWTClaimsContextKey).(jwt.MapClaims) if !ok { t.Fatal("Claims were not passed into context correctly") } if cl["user"] != mapClaims["user"] { t.Fatalf("JWT Claims.user did not match: expecting %s got %s", mapClaims["user"], cl["user"]) } // Test for malformed token error response parser = NewParser(keys, method, StandardClaimsFactory)(e) ctx = context.WithValue(context.Background(), JWTTokenContextKey, malformedKey) ctx1, err = parser(ctx, struct{}{}) if want, have := ErrTokenMalformed, err; want != have { t.Fatalf("Expected %+v, got %+v", want, have) } // Test for expired token error response parser = NewParser(keys, method, StandardClaimsFactory)(e) expired := jwt.NewWithClaims(method, jwt.StandardClaims{ExpiresAt: time.Now().Unix() - 100}) token, err := expired.SignedString(key) if err != nil { t.Fatalf("Unable to Sign Token: %+v", err) } ctx = context.WithValue(context.Background(), JWTTokenContextKey, token) ctx1, err = parser(ctx, struct{}{}) if want, have := ErrTokenExpired, err; want != have { t.Fatalf("Expected %+v, got %+v", want, have) } // Test for not activated token error response parser = NewParser(keys, method, StandardClaimsFactory)(e) notactive := jwt.NewWithClaims(method, jwt.StandardClaims{NotBefore: time.Now().Unix() + 100}) token, err = notactive.SignedString(key) if err != nil { t.Fatalf("Unable to Sign Token: %+v", err) } ctx = context.WithValue(context.Background(), JWTTokenContextKey, token) ctx1, err = parser(ctx, struct{}{}) if want, have := ErrTokenNotActive, err; want != have { t.Fatalf("Expected %+v, got %+v", want, have) } // test valid standard claims token parser = NewParser(keys, method, StandardClaimsFactory)(e) ctx = context.WithValue(context.Background(), JWTTokenContextKey, standardSignedKey) ctx1, err = parser(ctx, struct{}{}) if err != nil { t.Fatalf("Parser returned error: %s", err) } stdCl, ok := ctx1.(context.Context).Value(JWTClaimsContextKey).(*jwt.StandardClaims) if !ok { t.Fatal("Claims were not passed into context correctly") } if !stdCl.VerifyAudience("go-kit", true) { t.Fatalf("JWT jwt.StandardClaims.Audience did not match: expecting %s got %s", standardClaims.Audience, stdCl.Audience) } // test valid customized claims token parser = NewParser(keys, method, func() jwt.Claims { return &customClaims{} })(e) ctx = context.WithValue(context.Background(), JWTTokenContextKey, customSignedKey) ctx1, err = parser(ctx, struct{}{}) if err != nil { t.Fatalf("Parser returned error: %s", err) } custCl, ok := ctx1.(context.Context).Value(JWTClaimsContextKey).(*customClaims) if !ok { t.Fatal("Claims were not passed into context correctly") } if !custCl.VerifyAudience("go-kit", true) { t.Fatalf("JWT customClaims.Audience did not match: expecting %s got %s", standardClaims.Audience, custCl.Audience) } if !custCl.VerifyMyProperty(myProperty) { t.Fatalf("JWT customClaims.MyProperty did not match: expecting %s got %s", myProperty, custCl.MyProperty) } } func TestIssue562(t *testing.T) { var ( kf = func(token *jwt.Token) (interface{}, error) { return []byte("secret"), nil } e = NewParser(kf, jwt.SigningMethodHS256, MapClaimsFactory)(endpoint.Nop) key = JWTTokenContextKey val = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ28ta2l0In0.14M2VmYyApdSlV_LZ88ajjwuaLeIFplB8JpyNy0A19E" ctx = context.WithValue(context.Background(), key, val) ) wg := sync.WaitGroup{} for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() e(ctx, struct{}{}) // fatal error: concurrent map read and map write }() } wg.Wait() } golang-github-go-kit-kit-0.10.0/auth/jwt/transport.go000066400000000000000000000043131362256312400224310ustar00rootroot00000000000000package jwt import ( "context" "fmt" stdhttp "net/http" "strings" "google.golang.org/grpc/metadata" "github.com/go-kit/kit/transport/grpc" "github.com/go-kit/kit/transport/http" ) const ( bearer string = "bearer" bearerFormat string = "Bearer %s" ) // HTTPToContext moves a JWT from request header to context. Particularly // useful for servers. func HTTPToContext() http.RequestFunc { return func(ctx context.Context, r *stdhttp.Request) context.Context { token, ok := extractTokenFromAuthHeader(r.Header.Get("Authorization")) if !ok { return ctx } return context.WithValue(ctx, JWTTokenContextKey, token) } } // ContextToHTTP moves a JWT from context to request header. Particularly // useful for clients. func ContextToHTTP() http.RequestFunc { return func(ctx context.Context, r *stdhttp.Request) context.Context { token, ok := ctx.Value(JWTTokenContextKey).(string) if ok { r.Header.Add("Authorization", generateAuthHeaderFromToken(token)) } return ctx } } // GRPCToContext moves a JWT from grpc metadata to context. Particularly // userful for servers. func GRPCToContext() grpc.ServerRequestFunc { return func(ctx context.Context, md metadata.MD) context.Context { // capital "Key" is illegal in HTTP/2. authHeader, ok := md["authorization"] if !ok { return ctx } token, ok := extractTokenFromAuthHeader(authHeader[0]) if ok { ctx = context.WithValue(ctx, JWTTokenContextKey, token) } return ctx } } // ContextToGRPC moves a JWT from context to grpc metadata. Particularly // useful for clients. func ContextToGRPC() grpc.ClientRequestFunc { return func(ctx context.Context, md *metadata.MD) context.Context { token, ok := ctx.Value(JWTTokenContextKey).(string) if ok { // capital "Key" is illegal in HTTP/2. (*md)["authorization"] = []string{generateAuthHeaderFromToken(token)} } return ctx } } func extractTokenFromAuthHeader(val string) (token string, ok bool) { authHeaderParts := strings.Split(val, " ") if len(authHeaderParts) != 2 || !strings.EqualFold(authHeaderParts[0], bearer) { return "", false } return authHeaderParts[1], true } func generateAuthHeaderFromToken(token string) string { return fmt.Sprintf(bearerFormat, token) } golang-github-go-kit-kit-0.10.0/auth/jwt/transport_test.go000066400000000000000000000064641362256312400235010ustar00rootroot00000000000000package jwt import ( "context" "fmt" "net/http" "testing" "google.golang.org/grpc/metadata" ) func TestHTTPToContext(t *testing.T) { reqFunc := HTTPToContext() // When the header doesn't exist ctx := reqFunc(context.Background(), &http.Request{}) if ctx.Value(JWTTokenContextKey) != nil { t.Error("Context shouldn't contain the encoded JWT") } // Authorization header value has invalid format header := http.Header{} header.Set("Authorization", "no expected auth header format value") ctx = reqFunc(context.Background(), &http.Request{Header: header}) if ctx.Value(JWTTokenContextKey) != nil { t.Error("Context shouldn't contain the encoded JWT") } // Authorization header is correct header.Set("Authorization", generateAuthHeaderFromToken(signedKey)) ctx = reqFunc(context.Background(), &http.Request{Header: header}) token := ctx.Value(JWTTokenContextKey).(string) if token != signedKey { t.Errorf("Context doesn't contain the expected encoded token value; expected: %s, got: %s", signedKey, token) } } func TestContextToHTTP(t *testing.T) { reqFunc := ContextToHTTP() // No JWT Token is passed in the context ctx := context.Background() r := http.Request{} reqFunc(ctx, &r) token := r.Header.Get("Authorization") if token != "" { t.Error("authorization key should not exist in metadata") } // Correct JWT Token is passed in the context ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey) r = http.Request{Header: http.Header{}} reqFunc(ctx, &r) token = r.Header.Get("Authorization") expected := generateAuthHeaderFromToken(signedKey) if token != expected { t.Errorf("Authorization header does not contain the expected JWT token; expected %s, got %s", expected, token) } } func TestGRPCToContext(t *testing.T) { md := metadata.MD{} reqFunc := GRPCToContext() // No Authorization header is passed ctx := reqFunc(context.Background(), md) token := ctx.Value(JWTTokenContextKey) if token != nil { t.Error("Context should not contain a JWT Token") } // Invalid Authorization header is passed md["authorization"] = []string{fmt.Sprintf("%s", signedKey)} ctx = reqFunc(context.Background(), md) token = ctx.Value(JWTTokenContextKey) if token != nil { t.Error("Context should not contain a JWT Token") } // Authorization header is correct md["authorization"] = []string{fmt.Sprintf("Bearer %s", signedKey)} ctx = reqFunc(context.Background(), md) token, ok := ctx.Value(JWTTokenContextKey).(string) if !ok { t.Fatal("JWT Token not passed to context correctly") } if token != signedKey { t.Errorf("JWT tokens did not match: expecting %s got %s", signedKey, token) } } func TestContextToGRPC(t *testing.T) { reqFunc := ContextToGRPC() // No JWT Token is passed in the context ctx := context.Background() md := metadata.MD{} reqFunc(ctx, &md) _, ok := md["authorization"] if ok { t.Error("authorization key should not exist in metadata") } // Correct JWT Token is passed in the context ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey) md = metadata.MD{} reqFunc(ctx, &md) token, ok := md["authorization"] if !ok { t.Fatal("JWT Token not passed to metadata correctly") } if token[0] != generateAuthHeaderFromToken(signedKey) { t.Errorf("JWT tokens did not match: expecting %s got %s", signedKey, token[0]) } } golang-github-go-kit-kit-0.10.0/circle.yml000066400000000000000000000014751362256312400202730ustar00rootroot00000000000000version: 2 jobs: build: machine: true working_directory: /home/circleci/.go_workspace/src/github.com/go-kit/kit environment: ETCD_ADDR: http://localhost:2379 CONSUL_ADDR: localhost:8500 ZK_ADDR: localhost:2181 EUREKA_ADDR: http://localhost:8761/eureka steps: - checkout - run: wget -q -O- https://golang.org/VERSION?m=text > go_version.txt - run: wget -q https://storage.googleapis.com/golang/$(cat go_version.txt).linux-amd64.tar.gz - run: sudo rm -rf /usr/local/go - run: sudo tar -C /usr/local -xzf $(cat go_version.txt).linux-amd64.tar.gz - run: docker-compose -f docker-compose-integration.yml up -d --force-recreate - run: go get -t github.com/go-kit/kit/... - run: go test -v -race -tags integration github.com/go-kit/kit/... golang-github-go-kit-kit-0.10.0/circuitbreaker/000077500000000000000000000000001362256312400212765ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/circuitbreaker/doc.go000066400000000000000000000007221362256312400223730ustar00rootroot00000000000000// Package circuitbreaker implements the circuit breaker pattern. // // Circuit breakers prevent thundering herds, and improve resiliency against // intermittent errors. Every client-side endpoint should be wrapped in a // circuit breaker. // // We provide several implementations in this package, but if you're looking // for guidance, Gobreaker is probably the best place to start. It has a // simple and intuitive API, and is well-tested. package circuitbreaker golang-github-go-kit-kit-0.10.0/circuitbreaker/gobreaker.go000066400000000000000000000012751362256312400235730ustar00rootroot00000000000000package circuitbreaker import ( "context" "github.com/sony/gobreaker" "github.com/go-kit/kit/endpoint" ) // Gobreaker returns an endpoint.Middleware that implements the circuit // breaker pattern using the sony/gobreaker package. Only errors returned by // the wrapped endpoint count against the circuit breaker's error count. // // See http://godoc.org/github.com/sony/gobreaker for more information. func Gobreaker(cb *gobreaker.CircuitBreaker) endpoint.Middleware { return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { return cb.Execute(func() (interface{}, error) { return next(ctx, request) }) } } } golang-github-go-kit-kit-0.10.0/circuitbreaker/gobreaker_test.go000066400000000000000000000010331362256312400246220ustar00rootroot00000000000000package circuitbreaker_test import ( "testing" "github.com/sony/gobreaker" "github.com/go-kit/kit/circuitbreaker" ) func TestGobreaker(t *testing.T) { var ( breaker = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{})) primeWith = 100 shouldPass = func(n int) bool { return n <= 5 } // https://github.com/sony/gobreaker/blob/bfa846d/gobreaker.go#L76 circuitOpenError = "circuit breaker is open" ) testFailingEndpoint(t, breaker, primeWith, shouldPass, 0, circuitOpenError) } golang-github-go-kit-kit-0.10.0/circuitbreaker/handy_breaker.go000066400000000000000000000016601362256312400244260ustar00rootroot00000000000000package circuitbreaker import ( "context" "time" "github.com/streadway/handy/breaker" "github.com/go-kit/kit/endpoint" ) // HandyBreaker returns an endpoint.Middleware that implements the circuit // breaker pattern using the streadway/handy/breaker package. Only errors // returned by the wrapped endpoint count against the circuit breaker's error // count. // // See http://godoc.org/github.com/streadway/handy/breaker for more // information. func HandyBreaker(cb breaker.Breaker) endpoint.Middleware { return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { if !cb.Allow() { return nil, breaker.ErrCircuitOpen } defer func(begin time.Time) { if err == nil { cb.Success(time.Since(begin)) } else { cb.Failure(time.Since(begin)) } }(time.Now()) response, err = next(ctx, request) return } } } golang-github-go-kit-kit-0.10.0/circuitbreaker/handy_breaker_test.go000066400000000000000000000011361362256312400254630ustar00rootroot00000000000000package circuitbreaker_test import ( "testing" handybreaker "github.com/streadway/handy/breaker" "github.com/go-kit/kit/circuitbreaker" ) func TestHandyBreaker(t *testing.T) { var ( failureRatio = 0.05 breaker = circuitbreaker.HandyBreaker(handybreaker.NewBreaker(failureRatio)) primeWith = handybreaker.DefaultMinObservations * 10 shouldPass = func(n int) bool { return (float64(n) / float64(primeWith+n)) <= failureRatio } openCircuitError = handybreaker.ErrCircuitOpen.Error() ) testFailingEndpoint(t, breaker, primeWith, shouldPass, 0, openCircuitError) } golang-github-go-kit-kit-0.10.0/circuitbreaker/hystrix.go000066400000000000000000000014761362256312400233470ustar00rootroot00000000000000package circuitbreaker import ( "context" "github.com/afex/hystrix-go/hystrix" "github.com/go-kit/kit/endpoint" ) // Hystrix returns an endpoint.Middleware that implements the circuit // breaker pattern using the afex/hystrix-go package. // // When using this circuit breaker, please configure your commands separately. // // See https://godoc.org/github.com/afex/hystrix-go/hystrix for more // information. func Hystrix(commandName string) endpoint.Middleware { return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { var resp interface{} if err := hystrix.Do(commandName, func() (err error) { resp, err = next(ctx, request) return err }, nil); err != nil { return nil, err } return resp, nil } } } golang-github-go-kit-kit-0.10.0/circuitbreaker/hystrix_test.go000066400000000000000000000021671362256312400244040ustar00rootroot00000000000000package circuitbreaker_test import ( "io/ioutil" stdlog "log" "testing" "time" "github.com/afex/hystrix-go/hystrix" "github.com/go-kit/kit/circuitbreaker" ) func TestHystrix(t *testing.T) { stdlog.SetOutput(ioutil.Discard) const ( commandName = "my-endpoint" errorPercent = 5 maxConcurrent = 1000 ) hystrix.ConfigureCommand(commandName, hystrix.CommandConfig{ ErrorPercentThreshold: errorPercent, MaxConcurrentRequests: maxConcurrent, }) var ( breaker = circuitbreaker.Hystrix(commandName) primeWith = hystrix.DefaultVolumeThreshold * 2 shouldPass = func(n int) bool { return (float64(n) / float64(primeWith+n)) <= (float64(errorPercent-1) / 100.0) } openCircuitError = hystrix.ErrCircuitOpen.Error() ) // hystrix-go uses buffered channels to receive reports on request success/failure, // and so is basically impossible to test deterministically. We have to make sure // the report buffer is emptied, by injecting a sleep between each invocation. requestDelay := 5 * time.Millisecond testFailingEndpoint(t, breaker, primeWith, shouldPass, requestDelay, openCircuitError) } golang-github-go-kit-kit-0.10.0/circuitbreaker/util_test.go000066400000000000000000000033731362256312400236470ustar00rootroot00000000000000package circuitbreaker_test import ( "context" "errors" "fmt" "path/filepath" "runtime" "testing" "time" "github.com/go-kit/kit/endpoint" ) func testFailingEndpoint( t *testing.T, breaker endpoint.Middleware, primeWith int, shouldPass func(int) bool, requestDelay time.Duration, openCircuitError string, ) { _, file, line, _ := runtime.Caller(1) caller := fmt.Sprintf("%s:%d", filepath.Base(file), line) // Create a mock endpoint and wrap it with the breaker. m := mock{} var e endpoint.Endpoint e = m.endpoint e = breaker(e) // Prime the endpoint with successful requests. for i := 0; i < primeWith; i++ { if _, err := e(context.Background(), struct{}{}); err != nil { t.Fatalf("%s: during priming, got error: %v", caller, err) } time.Sleep(requestDelay) } // Switch the endpoint to start throwing errors. m.err = errors.New("tragedy+disaster") m.through = 0 // The first several should be allowed through and yield our error. for i := 0; shouldPass(i); i++ { if _, err := e(context.Background(), struct{}{}); err != m.err { t.Fatalf("%s: want %v, have %v", caller, m.err, err) } time.Sleep(requestDelay) } through := m.through // But the rest should be blocked by an open circuit. for i := 0; i < 10; i++ { if _, err := e(context.Background(), struct{}{}); err.Error() != openCircuitError { t.Fatalf("%s: want %q, have %q", caller, openCircuitError, err.Error()) } time.Sleep(requestDelay) } // Make sure none of those got through. if want, have := through, m.through; want != have { t.Errorf("%s: want %d, have %d", caller, want, have) } } type mock struct { through int err error } func (m *mock) endpoint(context.Context, interface{}) (interface{}, error) { m.through++ return struct{}{}, m.err } golang-github-go-kit-kit-0.10.0/cmd/000077500000000000000000000000001362256312400170435ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/000077500000000000000000000000001362256312400203245ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/.ignore000066400000000000000000000000161362256312400216050ustar00rootroot00000000000000testdata/*/*/ golang-github-go-kit-kit-0.10.0/cmd/kitgen/README.md000066400000000000000000000032611362256312400216050ustar00rootroot00000000000000# kitgen kitgen is an experimental code generation utility that helps with some of the boilerplate code required to implement the "onion" pattern `go-kit` utilizes. ## Usage Before using this tool please explore the [testdata]() directory for examples of the inputs it requires and the outputs that will be produced. _You may not need this tool._ If you are new to and just learning `go-kit` or if your use case involves introducing `go-kit` to an existing codebase you are better suited by slowly building out the "onion" by hand. Before starting you need to *install* `kitgen` utility — see instructions below. 1. **Define** your service. Create a `.go` file with the definition of your Service interface and any of the custom types it refers to: ```go // service.go package profilesvc // don't forget to name your package type Service interface { PostProfile(ctx context.Context, p Profile) error // ... } type Profile struct { ID string `json:"id"` Name string `json:"name,omitempty"` // ... } ``` 2. **Generate** your code. Run the following command: ```sh kitgen ./service.go # kitgen has a couple of flags that you may find useful # keep all code in the root directory kitgen -repo-layout flat ./service.go # put generated code elsewhere kitgen -target-dir ~/Projects/gohome/src/home.com/kitchenservice/brewcoffee ``` ## Installation 1. **Fetch** the `inlinefiles` utility. Go generate will use it to create your code: ``` go get github.com/nyarly/inlinefiles ``` 2. **Install** the binary for easy access to `kitgen`. Run the following commands: ```sh cd $GOPATH/src/github.com/go-kit/kit/cmd/kitgen go install # Check installation by running: kitgen -h ``` golang-github-go-kit-kit-0.10.0/cmd/kitgen/arg.go000066400000000000000000000011601362256312400214220ustar00rootroot00000000000000package main import "go/ast" type arg struct { name, asField *ast.Ident typ ast.Expr } func (a arg) chooseName(scope *ast.Scope) *ast.Ident { if a.name == nil || scope.Lookup(a.name.Name) != nil { return inventName(a.typ, scope) } return a.name } func (a arg) field(scope *ast.Scope) *ast.Field { return &ast.Field{ Names: []*ast.Ident{a.chooseName(scope)}, Type: a.typ, } } func (a arg) result() *ast.Field { return &ast.Field{ Names: nil, Type: a.typ, } } func (a arg) exported() *ast.Field { return &ast.Field{ Names: []*ast.Ident{id(export(a.asField.Name))}, Type: a.typ, } } golang-github-go-kit-kit-0.10.0/cmd/kitgen/ast_helpers.go000066400000000000000000000101501362256312400231610ustar00rootroot00000000000000package main import ( "fmt" "go/ast" "go/parser" "go/token" "path/filepath" "strings" "unicode" ) func export(s string) string { return strings.Title(s) } func unexport(s string) string { first := true return strings.Map(func(r rune) rune { if first { first = false return unicode.ToLower(r) } return r }, s) } func inventName(t ast.Expr, scope *ast.Scope) *ast.Ident { n := baseName(t) for try := 0; ; try++ { nstr := pickName(n, try) obj := ast.NewObj(ast.Var, nstr) if alt := scope.Insert(obj); alt == nil { return ast.NewIdent(nstr) } } } func baseName(t ast.Expr) string { switch tt := t.(type) { default: panic(fmt.Sprintf("don't know how to choose a base name for %T (%[1]v)", tt)) case *ast.ArrayType: return "slice" case *ast.Ident: return tt.Name case *ast.SelectorExpr: return tt.Sel.Name } } func pickName(base string, idx int) string { if idx == 0 { switch base { default: return strings.Split(base, "")[0] case "Context": return "ctx" case "error": return "err" } } return fmt.Sprintf("%s%d", base, idx) } func scopeWith(names ...string) *ast.Scope { scope := ast.NewScope(nil) for _, name := range names { scope.Insert(ast.NewObj(ast.Var, name)) } return scope } type visitFn func(ast.Node, func(ast.Node)) func (fn visitFn) Visit(node ast.Node, r func(ast.Node)) Visitor { fn(node, r) return fn } func replaceIdent(src ast.Node, named string, with ast.Node) ast.Node { r := visitFn(func(node ast.Node, replaceWith func(ast.Node)) { switch id := node.(type) { case *ast.Ident: if id.Name == named { replaceWith(with) } } }) return WalkReplace(r, src) } func replaceLit(src ast.Node, from, to string) ast.Node { r := visitFn(func(node ast.Node, replaceWith func(ast.Node)) { switch lit := node.(type) { case *ast.BasicLit: if lit.Value == from { replaceWith(&ast.BasicLit{Value: to}) } } }) return WalkReplace(r, src) } func fullAST() *ast.File { full, err := ASTTemplates.Open("full.go") if err != nil { panic(err) } f, err := parser.ParseFile(token.NewFileSet(), "templates/full.go", full, parser.DeclarationErrors) if err != nil { panic(err) } return f } func fetchImports() []*ast.ImportSpec { return fullAST().Imports } func fetchFuncDecl(name string) *ast.FuncDecl { f := fullAST() for _, decl := range f.Decls { if f, ok := decl.(*ast.FuncDecl); ok && f.Name.Name == name { return f } } panic(fmt.Errorf("no function called %q in 'templates/full.go'", name)) } func id(name string) *ast.Ident { return ast.NewIdent(name) } func sel(ids ...*ast.Ident) ast.Expr { switch len(ids) { default: return &ast.SelectorExpr{ X: sel(ids[:len(ids)-1]...), Sel: ids[len(ids)-1], } case 1: return ids[0] case 0: panic("zero ids to sel()") } } func typeField(t ast.Expr) *ast.Field { return &ast.Field{Type: t} } func field(n *ast.Ident, t ast.Expr) *ast.Field { return &ast.Field{ Names: []*ast.Ident{n}, Type: t, } } func fieldList(list ...*ast.Field) *ast.FieldList { return &ast.FieldList{List: list} } func mappedFieldList(fn func(arg) *ast.Field, args ...arg) *ast.FieldList { fl := &ast.FieldList{List: []*ast.Field{}} for _, a := range args { fl.List = append(fl.List, fn(a)) } return fl } func blockStmt(stmts ...ast.Stmt) *ast.BlockStmt { return &ast.BlockStmt{ List: stmts, } } func structDecl(name *ast.Ident, fields *ast.FieldList) ast.Decl { return typeDecl(&ast.TypeSpec{ Name: name, Type: &ast.StructType{ Fields: fields, }, }) } func typeDecl(ts *ast.TypeSpec) ast.Decl { return &ast.GenDecl{ Tok: token.TYPE, Specs: []ast.Spec{ts}, } } func pasteStmts(body *ast.BlockStmt, idx int, stmts []ast.Stmt) { list := body.List prefix := list[:idx] suffix := make([]ast.Stmt, len(list)-idx-1) copy(suffix, list[idx+1:]) body.List = append(append(prefix, stmts...), suffix...) } func importFor(is *ast.ImportSpec) *ast.GenDecl { return &ast.GenDecl{Tok: token.IMPORT, Specs: []ast.Spec{is}} } func importSpec(path string) *ast.ImportSpec { return &ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"` + filepath.ToSlash(path) + `"`}} } golang-github-go-kit-kit-0.10.0/cmd/kitgen/ast_templates.go000066400000000000000000000035161362256312400235250ustar00rootroot00000000000000// This file was automatically generated based on the contents of *.tmpl // If you need to update this file, change the contents of those files // (or add new ones) and run 'go generate' package main import "golang.org/x/tools/godoc/vfs/mapfs" var ASTTemplates = mapfs.New(map[string]string{ `full.go`: "package foo\n\nimport (\n \"context\"\n \"encoding/json\"\n \"errors\"\n \"net/http\"\n\n \"github.com/go-kit/kit/endpoint\"\n httptransport \"github.com/go-kit/kit/transport/http\"\n)\n\ntype ExampleService struct {\n}\n\ntype ExampleRequest struct {\n I int\n S string\n}\ntype ExampleResponse struct {\n S string\n Err error\n}\n\ntype Endpoints struct {\n ExampleEndpoint endpoint.Endpoint\n}\n\nfunc (f ExampleService) ExampleEndpoint(ctx context.Context, i int, s string) (string, error) {\n panic(errors.New(\"not implemented\"))\n}\n\nfunc makeExampleEndpoint(f ExampleService) endpoint.Endpoint {\n return func(ctx context.Context, request interface{}) (interface{}, error) {\n req := request.(ExampleRequest)\n s, err := f.ExampleEndpoint(ctx, req.I, req.S)\n return ExampleResponse{S: s, Err: err}, nil\n }\n}\n\nfunc inlineHandlerBuilder(m *http.ServeMux, endpoints Endpoints) {\n m.Handle(\"/bar\", httptransport.NewServer(endpoints.ExampleEndpoint, DecodeExampleRequest, EncodeExampleResponse))\n}\n\nfunc NewHTTPHandler(endpoints Endpoints) http.Handler {\n m := http.NewServeMux()\n inlineHandlerBuilder(m, endpoints)\n return m\n}\n\nfunc DecodeExampleRequest(_ context.Context, r *http.Request) (interface{}, error) {\n var req ExampleRequest\n err := json.NewDecoder(r.Body).Decode(&req)\n return req, err\n}\n\nfunc EncodeExampleResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {\n w.Header().Set(\"Content-Type\", \"application/json; charset=utf-8\")\n return json.NewEncoder(w).Encode(response)\n}\n", }) golang-github-go-kit-kit-0.10.0/cmd/kitgen/deflayout.go000066400000000000000000000030631362256312400226510ustar00rootroot00000000000000package main import "path/filepath" type deflayout struct { targetDir string } func (l deflayout) packagePath(sub string) string { return filepath.Join(l.targetDir, sub) } func (l deflayout) transformAST(ctx *sourceContext) (files, error) { out := make(outputTree) endpoints := out.addFile("endpoints/endpoints.go", "endpoints") http := out.addFile("http/http.go", "http") service := out.addFile("service/service.go", "service") addImports(endpoints, ctx) addImports(http, ctx) addImports(service, ctx) for _, typ := range ctx.types { addType(service, typ) } for _, iface := range ctx.interfaces { //only one... addStubStruct(service, iface) for _, meth := range iface.methods { addMethod(service, iface, meth) addRequestStruct(endpoints, meth) addResponseStruct(endpoints, meth) addEndpointMaker(endpoints, iface, meth) } addEndpointsStruct(endpoints, iface) addHTTPHandler(http, iface) for _, meth := range iface.methods { addDecoder(http, meth) addEncoder(http, meth) } for name := range out { out[name] = selectify(out[name], "service", iface.stubName().Name, l.packagePath("service")) for _, meth := range iface.methods { out[name] = selectify(out[name], "endpoints", meth.requestStructName().Name, l.packagePath("endpoints")) } } } for name := range out { out[name] = selectify(out[name], "endpoints", "Endpoints", l.packagePath("endpoints")) for _, typ := range ctx.types { out[name] = selectify(out[name], "service", typ.Name.Name, l.packagePath("service")) } } return formatNodes(out) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/flatlayout.go000066400000000000000000000013461362256312400230430ustar00rootroot00000000000000package main import "go/ast" type flat struct{} func (f flat) transformAST(ctx *sourceContext) (files, error) { root := &ast.File{ Name: ctx.pkg, Decls: []ast.Decl{}, } addImports(root, ctx) for _, typ := range ctx.types { addType(root, typ) } for _, iface := range ctx.interfaces { //only one... addStubStruct(root, iface) for _, meth := range iface.methods { addMethod(root, iface, meth) addRequestStruct(root, meth) addResponseStruct(root, meth) addEndpointMaker(root, iface, meth) } addEndpointsStruct(root, iface) addHTTPHandler(root, iface) for _, meth := range iface.methods { addDecoder(root, meth) addEncoder(root, meth) } } return formatNodes(outputTree{"gokit.go": root}) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/interface.go000066400000000000000000000036351362256312400226220ustar00rootroot00000000000000package main import "go/ast" // because "interface" is a keyword... type iface struct { name, stubname, rcvrName *ast.Ident methods []method } func (i iface) stubName() *ast.Ident { return i.stubname } func (i iface) stubStructDecl() ast.Decl { return structDecl(i.stubName(), &ast.FieldList{}) } func (i iface) endpointsStruct() ast.Decl { fl := &ast.FieldList{} for _, m := range i.methods { fl.List = append(fl.List, &ast.Field{Names: []*ast.Ident{m.name}, Type: sel(id("endpoint"), id("Endpoint"))}) } return structDecl(id("Endpoints"), fl) } func (i iface) httpHandler() ast.Decl { handlerFn := fetchFuncDecl("NewHTTPHandler") // does this "inlining" process merit a helper akin to replaceIdent? handleCalls := []ast.Stmt{} for _, m := range i.methods { handleCall := fetchFuncDecl("inlineHandlerBuilder").Body.List[0].(*ast.ExprStmt).X.(*ast.CallExpr) handleCall = replaceLit(handleCall, `"/bar"`, `"`+m.pathName()+`"`).(*ast.CallExpr) handleCall = replaceIdent(handleCall, "ExampleEndpoint", m.name).(*ast.CallExpr) handleCall = replaceIdent(handleCall, "DecodeExampleRequest", m.decodeFuncName()).(*ast.CallExpr) handleCall = replaceIdent(handleCall, "EncodeExampleResponse", m.encodeFuncName()).(*ast.CallExpr) handleCalls = append(handleCalls, &ast.ExprStmt{X: handleCall}) } pasteStmts(handlerFn.Body, 1, handleCalls) return handlerFn } func (i iface) receiver() *ast.Field { return field(i.receiverName(), i.stubName()) } func (i iface) receiverName() *ast.Ident { if i.rcvrName != nil { return i.rcvrName } scope := ast.NewScope(nil) for _, meth := range i.methods { for _, arg := range meth.params { if arg.name != nil { scope.Insert(ast.NewObj(ast.Var, arg.name.Name)) } } for _, arg := range meth.results { if arg.name != nil { scope.Insert(ast.NewObj(ast.Var, arg.name.Name)) } } } return id(unexport(inventName(i.name, scope).Name)) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/main.go000066400000000000000000000064311362256312400216030ustar00rootroot00000000000000package main import ( "flag" "fmt" "go/ast" "go/parser" "go/token" "io" "log" "os" "path" "github.com/pkg/errors" ) // go get github.com/nyarly/inlinefiles //go:generate inlinefiles --package=main --vfs=ASTTemplates ./templates ast_templates.go func usage() string { return fmt.Sprintf("Usage: %s (try -h)", os.Args[0]) } var ( help = flag.Bool("h", false, "print this help") layoutkind = flag.String("repo-layout", "default", "default, flat...") outdirrel = flag.String("target-dir", ".", "base directory to emit into") //contextOmittable = flag.Bool("allow-no-context", false, "allow service methods to omit context parameter") ) func helpText() { fmt.Println("USAGE") fmt.Println(" kitgen [flags] path/to/service.go") fmt.Println("") fmt.Println("FLAGS") flag.PrintDefaults() } func main() { flag.Parse() if *help { helpText() os.Exit(0) } outdir := *outdirrel if !path.IsAbs(*outdirrel) { wd, err := os.Getwd() if err != nil { log.Fatalf("error getting current working directory: %v", err) } outdir = path.Join(wd, *outdirrel) } var layout layout switch *layoutkind { default: log.Fatalf("Unrecognized layout kind: %q - try 'default' or 'flat'", *layoutkind) case "default": gopath := getGopath() importBase, err := importPath(outdir, gopath) if err != nil { log.Fatal(err) } layout = deflayout{targetDir: importBase} case "flat": layout = flat{} } if len(os.Args) < 2 { log.Fatal(usage()) } filename := flag.Arg(0) file, err := os.Open(filename) if err != nil { log.Fatalf("error while opening %q: %v", filename, err) } tree, err := process(filename, file, layout) if err != nil { log.Fatal(err) } err = splat(outdir, tree) if err != nil { log.Fatal(err) } } func process(filename string, source io.Reader, layout layout) (files, error) { f, err := parseFile(filename, source) if err != nil { return nil, errors.Wrapf(err, "parsing input %q", filename) } context, err := extractContext(f) if err != nil { return nil, errors.Wrapf(err, "examining input file %q", filename) } tree, err := layout.transformAST(context) if err != nil { return nil, errors.Wrapf(err, "generating AST") } return tree, nil } /* buf, err := formatNode(dest) if err != nil { return nil, errors.Wrapf(err, "formatting") } return buf, nil } */ func parseFile(fname string, source io.Reader) (ast.Node, error) { f, err := parser.ParseFile(token.NewFileSet(), fname, source, parser.DeclarationErrors) if err != nil { return nil, err } return f, nil } func extractContext(f ast.Node) (*sourceContext, error) { context := &sourceContext{} visitor := &parseVisitor{src: context} ast.Walk(visitor, f) return context, context.validate() } func splat(dir string, tree files) error { for fn, buf := range tree { if err := splatFile(path.Join(dir, fn), buf); err != nil { return err } } return nil } func splatFile(target string, buf io.Reader) error { err := os.MkdirAll(path.Dir(target), os.ModePerm) if err != nil { return errors.Wrapf(err, "Couldn't create directory for %q", target) } f, err := os.Create(target) if err != nil { return errors.Wrapf(err, "Couldn't create file %q", target) } defer f.Close() _, err = io.Copy(f, buf) return errors.Wrapf(err, "Error writing data to file %q", target) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/main_test.go000066400000000000000000000050771362256312400226470ustar00rootroot00000000000000package main import ( "bufio" "bytes" "flag" "fmt" "io/ioutil" "os/exec" "path/filepath" "testing" "github.com/aryann/difflib" ) var update = flag.Bool("update", false, "update golden files") func TestProcess(t *testing.T) { cases, err := filepath.Glob("testdata/*") if err != nil { t.Fatal(err) } laidout := func(t *testing.T, inpath, dir, kind string, layout layout, in []byte) { t.Run(kind, func(t *testing.T) { targetDir := filepath.Join(dir, kind) tree, err := process(inpath, bytes.NewBuffer(in), layout) if err != nil { t.Fatal(inpath, fmt.Sprintf("%+#v", err)) } if *update { err := splat(targetDir, tree) if err != nil { t.Fatal(kind, err) } // otherwise we need to do some tomfoolery with resetting buffers // I'm willing to just run the tests again - besides, we shouldn't be // regerating the golden files that often t.Error("Updated outputs - DID NOT COMPARE! (run tests again without -update)") return } for filename, buf := range tree { actual, err := ioutil.ReadAll(buf) if err != nil { t.Fatal(kind, filename, err) } outpath := filepath.Join(targetDir, filename) expected, err := ioutil.ReadFile(outpath) if err != nil { t.Fatal(outpath, err) } if !bytes.Equal(expected, actual) { results := difflib.Diff(splitLines(expected), splitLines(actual)) for _, result := range results { if result.Delta == difflib.Common { continue } t.Error(result) } } } if !t.Failed() { build := exec.Command("go", "build", "./...") build.Dir = targetDir out, err := build.CombinedOutput() if err != nil { t.Fatalf("Cannot build output: %v\n%s", err, string(out)) } } }) } testcase := func(dir string) { name := filepath.Base(dir) t.Run(name, func(t *testing.T) { inpath := filepath.Join(dir, "in.go") in, err := ioutil.ReadFile(inpath) if err != nil { t.Fatal(inpath, err) } laidout(t, inpath, dir, "flat", flat{}, in) laidout(t, inpath, dir, "default", deflayout{ targetDir: filepath.Join("github.com/go-kit/kit/cmd/kitgen", dir, "default"), }, in) }) } for _, dir := range cases { testcase(dir) } } func TestTemplatesBuild(t *testing.T) { build := exec.Command("go", "build", "./...") build.Dir = "templates" out, err := build.CombinedOutput() if err != nil { t.Fatal(err, "\n", string(out)) } } func splitLines(txt []byte) []string { s := bufio.NewScanner(bytes.NewReader(txt)) var ss []string for s.Scan() { ss = append(ss, s.Text()) } return ss } golang-github-go-kit-kit-0.10.0/cmd/kitgen/method.go000066400000000000000000000125131362256312400221350ustar00rootroot00000000000000package main import ( "go/ast" "go/token" "strings" ) type method struct { name *ast.Ident params []arg results []arg structsResolved bool } func (m method) definition(ifc iface) ast.Decl { notImpl := fetchFuncDecl("ExampleEndpoint") notImpl.Name = m.name notImpl.Recv = fieldList(ifc.receiver()) scope := scopeWith(notImpl.Recv.List[0].Names[0].Name) notImpl.Type.Params = m.funcParams(scope) notImpl.Type.Results = m.funcResults() return notImpl } func (m method) endpointMaker(ifc iface) ast.Decl { endpointFn := fetchFuncDecl("makeExampleEndpoint") scope := scopeWith("ctx", "req", ifc.receiverName().Name) anonFunc := endpointFn.Body.List[0].(*ast.ReturnStmt).Results[0].(*ast.FuncLit) if !m.hasContext() { // strip context param from endpoint function anonFunc.Type.Params.List = anonFunc.Type.Params.List[1:] } anonFunc = replaceIdent(anonFunc, "ExampleRequest", m.requestStructName()).(*ast.FuncLit) callMethod := m.called(ifc, scope, "ctx", "req") anonFunc.Body.List[1] = callMethod anonFunc.Body.List[2].(*ast.ReturnStmt).Results[0] = m.wrapResult(callMethod.Lhs) endpointFn.Body.List[0].(*ast.ReturnStmt).Results[0] = anonFunc endpointFn.Name = m.endpointMakerName() endpointFn.Type.Params = fieldList(ifc.receiver()) endpointFn.Type.Results = fieldList(typeField(sel(id("endpoint"), id("Endpoint")))) return endpointFn } func (m method) pathName() string { return "/" + strings.ToLower(m.name.Name) } func (m method) encodeFuncName() *ast.Ident { return id("Encode" + m.name.Name + "Response") } func (m method) decodeFuncName() *ast.Ident { return id("Decode" + m.name.Name + "Request") } func (m method) resultNames(scope *ast.Scope) []*ast.Ident { ids := []*ast.Ident{} for _, rz := range m.results { ids = append(ids, rz.chooseName(scope)) } return ids } func (m method) called(ifc iface, scope *ast.Scope, ctxName, spreadStruct string) *ast.AssignStmt { m.resolveStructNames() resNamesExpr := []ast.Expr{} for _, r := range m.resultNames(scope) { resNamesExpr = append(resNamesExpr, ast.Expr(r)) } arglist := []ast.Expr{} if m.hasContext() { arglist = append(arglist, id(ctxName)) } ssid := id(spreadStruct) for _, f := range m.requestStructFields().List { arglist = append(arglist, sel(ssid, f.Names[0])) } return &ast.AssignStmt{ Lhs: resNamesExpr, Tok: token.DEFINE, Rhs: []ast.Expr{ &ast.CallExpr{ Fun: sel(ifc.receiverName(), m.name), Args: arglist, }, }, } } func (m method) wrapResult(results []ast.Expr) ast.Expr { kvs := []ast.Expr{} m.resolveStructNames() for i, a := range m.results { kvs = append(kvs, &ast.KeyValueExpr{ Key: ast.NewIdent(export(a.asField.Name)), Value: results[i], }) } return &ast.CompositeLit{ Type: m.responseStructName(), Elts: kvs, } } func (m method) resolveStructNames() { if m.structsResolved { return } m.structsResolved = true scope := ast.NewScope(nil) for i, p := range m.params { p.asField = p.chooseName(scope) m.params[i] = p } scope = ast.NewScope(nil) for i, r := range m.results { r.asField = r.chooseName(scope) m.results[i] = r } } func (m method) decoderFunc() ast.Decl { fn := fetchFuncDecl("DecodeExampleRequest") fn.Name = m.decodeFuncName() fn = replaceIdent(fn, "ExampleRequest", m.requestStructName()).(*ast.FuncDecl) return fn } func (m method) encoderFunc() ast.Decl { fn := fetchFuncDecl("EncodeExampleResponse") fn.Name = m.encodeFuncName() return fn } func (m method) endpointMakerName() *ast.Ident { return id("Make" + m.name.Name + "Endpoint") } func (m method) requestStruct() ast.Decl { m.resolveStructNames() return structDecl(m.requestStructName(), m.requestStructFields()) } func (m method) responseStruct() ast.Decl { m.resolveStructNames() return structDecl(m.responseStructName(), m.responseStructFields()) } func (m method) hasContext() bool { if len(m.params) < 1 { return false } carg := m.params[0].typ // ugh. this is maybe okay for the one-off, but a general case for matching // types would be helpful if sel, is := carg.(*ast.SelectorExpr); is && sel.Sel.Name == "Context" { if id, is := sel.X.(*ast.Ident); is && id.Name == "context" { return true } } return false } func (m method) nonContextParams() []arg { if m.hasContext() { return m.params[1:] } return m.params } func (m method) funcParams(scope *ast.Scope) *ast.FieldList { parms := &ast.FieldList{} if m.hasContext() { parms.List = []*ast.Field{{ Names: []*ast.Ident{ast.NewIdent("ctx")}, Type: sel(id("context"), id("Context")), }} scope.Insert(ast.NewObj(ast.Var, "ctx")) } parms.List = append(parms.List, mappedFieldList(func(a arg) *ast.Field { return a.field(scope) }, m.nonContextParams()...).List...) return parms } func (m method) funcResults() *ast.FieldList { return mappedFieldList(func(a arg) *ast.Field { return a.result() }, m.results...) } func (m method) requestStructName() *ast.Ident { return id(export(m.name.Name) + "Request") } func (m method) requestStructFields() *ast.FieldList { return mappedFieldList(func(a arg) *ast.Field { return a.exported() }, m.nonContextParams()...) } func (m method) responseStructName() *ast.Ident { return id(export(m.name.Name) + "Response") } func (m method) responseStructFields() *ast.FieldList { return mappedFieldList(func(a arg) *ast.Field { return a.exported() }, m.results...) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/parsevisitor.go000066400000000000000000000064121362256312400234100ustar00rootroot00000000000000package main import ( "go/ast" ) type ( parseVisitor struct { src *sourceContext } typeSpecVisitor struct { src *sourceContext node *ast.TypeSpec iface *iface name *ast.Ident } interfaceTypeVisitor struct { node *ast.TypeSpec ts *typeSpecVisitor methods []method } methodVisitor struct { depth int node *ast.TypeSpec list *[]method name *ast.Ident params, results *[]arg isMethod bool } argListVisitor struct { list *[]arg } argVisitor struct { node *ast.TypeSpec parts []ast.Expr list *[]arg } ) func (v *parseVisitor) Visit(n ast.Node) ast.Visitor { switch rn := n.(type) { default: return v case *ast.File: v.src.pkg = rn.Name return v case *ast.ImportSpec: v.src.imports = append(v.src.imports, rn) return nil case *ast.TypeSpec: switch rn.Type.(type) { default: v.src.types = append(v.src.types, rn) case *ast.InterfaceType: // can't output interfaces // because they'd conflict with our implementations } return &typeSpecVisitor{src: v.src, node: rn} } } /* package foo type FooService interface { Bar(ctx context.Context, i int, s string) (string, error) } */ func (v *typeSpecVisitor) Visit(n ast.Node) ast.Visitor { switch rn := n.(type) { default: return v case *ast.Ident: if v.name == nil { v.name = rn } return v case *ast.InterfaceType: return &interfaceTypeVisitor{ts: v, methods: []method{}} case nil: if v.iface != nil { v.iface.name = v.name sn := *v.name v.iface.stubname = &sn v.iface.stubname.Name = v.name.String() v.src.interfaces = append(v.src.interfaces, *v.iface) } return nil } } func (v *interfaceTypeVisitor) Visit(n ast.Node) ast.Visitor { switch n.(type) { default: return v case *ast.Field: return &methodVisitor{list: &v.methods} case nil: v.ts.iface = &iface{methods: v.methods} return nil } } func (v *methodVisitor) Visit(n ast.Node) ast.Visitor { switch rn := n.(type) { default: v.depth++ return v case *ast.Ident: if rn.IsExported() { v.name = rn } v.depth++ return v case *ast.FuncType: v.depth++ v.isMethod = true return v case *ast.FieldList: if v.params == nil { v.params = &[]arg{} return &argListVisitor{list: v.params} } if v.results == nil { v.results = &[]arg{} } return &argListVisitor{list: v.results} case nil: v.depth-- if v.depth == 0 && v.isMethod && v.name != nil { *v.list = append(*v.list, method{name: v.name, params: *v.params, results: *v.results}) } return nil } } func (v *argListVisitor) Visit(n ast.Node) ast.Visitor { switch n.(type) { default: return nil case *ast.Field: return &argVisitor{list: v.list} } } func (v *argVisitor) Visit(n ast.Node) ast.Visitor { switch t := n.(type) { case *ast.CommentGroup, *ast.BasicLit: return nil case *ast.Ident: //Expr -> everything, but clarity if t.Name != "_" { v.parts = append(v.parts, t) } case ast.Expr: v.parts = append(v.parts, t) case nil: names := v.parts[:len(v.parts)-1] tp := v.parts[len(v.parts)-1] if len(names) == 0 { *v.list = append(*v.list, arg{typ: tp}) return nil } for _, n := range names { *v.list = append(*v.list, arg{ name: n.(*ast.Ident), typ: tp, }) } } return nil } golang-github-go-kit-kit-0.10.0/cmd/kitgen/path_test.go000066400000000000000000000032101362256312400226420ustar00rootroot00000000000000package main import ( "fmt" "runtime" "strings" "testing" ) func TestImportPath(t *testing.T) { testcase := func(gopath, targetpath, expected string) { t.Run(fmt.Sprintf("%q + %q", gopath, targetpath), func(t *testing.T) { actual, err := importPath(targetpath, gopath) if err != nil { t.Fatalf("Expected no error, got %q", err) } if actual != expected { t.Errorf("Expected %q, got %q", expected, actual) } }) } if runtime.GOOS == "windows" { testcase("c:\\gopath\\", "c:\\gopath\\src\\somewhere", "somewhere") testcase("c:\\gopath", "c:\\gopath\\src\\somewhere", "somewhere") testcase("c:\\gopath;\\other", "c:\\gopath\\src\\somewhere", "somewhere") testcase("c:\\other;c:\\gopath\\", "c:\\gopath\\src\\somewhere", "somewhere") } else { testcase("/gopath/", "/gopath/src/somewhere", "somewhere") testcase("/gopath", "/gopath/src/somewhere", "somewhere") testcase("/gopath:/other", "/gopath/src/somewhere", "somewhere") testcase("/other:/gopath/", "/gopath/src/somewhere", "somewhere") } } func TestImportPathSadpath(t *testing.T) { testcase := func(gopath, targetpath, expected string) { t.Run(fmt.Sprintf("%q + %q", gopath, targetpath), func(t *testing.T) { actual, err := importPath(targetpath, gopath) if actual != "" { t.Errorf("Expected empty path, got %q", actual) } if strings.Index(err.Error(), expected) == -1 { t.Errorf("Expected %q to include %q", err, expected) } }) } if runtime.GOOS == "windows" { testcase("", "c:\\gopath\\src\\somewhere", "is not in") } else { testcase("", "/gopath/src/somewhere", "is not in") } testcase("", "./somewhere", "not an absolute") } golang-github-go-kit-kit-0.10.0/cmd/kitgen/replacewalk.go000066400000000000000000000362271362256312400231570ustar00rootroot00000000000000package main import ( "fmt" "go/ast" ) // A Visitor's Visit method is invoked for each node encountered by walkToReplace. // If the result visitor w is not nil, walkToReplace visits each of the children // of node with the visitor w, followed by a call of w.Visit(nil). type Visitor interface { Visit(node ast.Node, replace func(ast.Node)) (w Visitor) } // Helper functions for common node lists. They may be empty. func walkIdentList(v Visitor, list []*ast.Ident) { for i, x := range list { walkToReplace(v, x, func(r ast.Node) { list[i] = r.(*ast.Ident) }) } } func walkExprList(v Visitor, list []ast.Expr) { for i, x := range list { walkToReplace(v, x, func(r ast.Node) { list[i] = r.(ast.Expr) }) } } func walkStmtList(v Visitor, list []ast.Stmt) { for i, x := range list { walkToReplace(v, x, func(r ast.Node) { list[i] = r.(ast.Stmt) }) } } func walkDeclList(v Visitor, list []ast.Decl) { for i, x := range list { walkToReplace(v, x, func(r ast.Node) { list[i] = r.(ast.Decl) }) } } // WalkToReplace traverses an AST in depth-first order: It starts by calling // v.Visit(node); node must not be nil. If the visitor w returned by // v.Visit(node) is not nil, walkToReplace is invoked recursively with visitor // w for each of the non-nil children of node, followed by a call of // w.Visit(nil). func WalkReplace(v Visitor, node ast.Node) (replacement ast.Node) { walkToReplace(v, node, func(r ast.Node) { replacement = r }) return } func walkToReplace(v Visitor, node ast.Node, replace func(ast.Node)) { if v == nil { return } var replacement ast.Node repl := func(r ast.Node) { replacement = r replace(r) } v = v.Visit(node, repl) if replacement != nil { return } // walk children // (the order of the cases matches the order // of the corresponding node types in ast.go) switch n := node.(type) { // These are all leaves, so there's no sub-walk to do. // We just need to replace them on their parent with a copy. case *ast.Comment: cpy := *n replace(&cpy) case *ast.BadExpr: cpy := *n replace(&cpy) case *ast.Ident: cpy := *n replace(&cpy) case *ast.BasicLit: cpy := *n replace(&cpy) case *ast.BadDecl: cpy := *n replace(&cpy) case *ast.EmptyStmt: cpy := *n replace(&cpy) case *ast.BadStmt: cpy := *n replace(&cpy) case *ast.CommentGroup: cpy := *n if n.List != nil { cpy.List = make([]*ast.Comment, len(n.List)) copy(cpy.List, n.List) } for i, c := range cpy.List { walkToReplace(v, c, func(r ast.Node) { cpy.List[i] = r.(*ast.Comment) }) } replace(&cpy) case *ast.Field: cpy := *n if n.Names != nil { cpy.Names = make([]*ast.Ident, len(n.Names)) copy(cpy.Names, n.Names) } if cpy.Doc != nil { walkToReplace(v, cpy.Doc, func(r ast.Node) { cpy.Doc = r.(*ast.CommentGroup) }) } walkIdentList(v, cpy.Names) walkToReplace(v, cpy.Type, func(r ast.Node) { cpy.Type = r.(ast.Expr) }) if cpy.Tag != nil { walkToReplace(v, cpy.Tag, func(r ast.Node) { cpy.Tag = r.(*ast.BasicLit) }) } if cpy.Comment != nil { walkToReplace(v, cpy.Comment, func(r ast.Node) { cpy.Comment = r.(*ast.CommentGroup) }) } replace(&cpy) case *ast.FieldList: cpy := *n if n.List != nil { cpy.List = make([]*ast.Field, len(n.List)) copy(cpy.List, n.List) } for i, f := range cpy.List { walkToReplace(v, f, func(r ast.Node) { cpy.List[i] = r.(*ast.Field) }) } replace(&cpy) case *ast.Ellipsis: cpy := *n if cpy.Elt != nil { walkToReplace(v, cpy.Elt, func(r ast.Node) { cpy.Elt = r.(ast.Expr) }) } replace(&cpy) case *ast.FuncLit: cpy := *n walkToReplace(v, cpy.Type, func(r ast.Node) { cpy.Type = r.(*ast.FuncType) }) walkToReplace(v, cpy.Body, func(r ast.Node) { cpy.Body = r.(*ast.BlockStmt) }) replace(&cpy) case *ast.CompositeLit: cpy := *n if n.Elts != nil { cpy.Elts = make([]ast.Expr, len(n.Elts)) copy(cpy.Elts, n.Elts) } if cpy.Type != nil { walkToReplace(v, cpy.Type, func(r ast.Node) { cpy.Type = r.(ast.Expr) }) } walkExprList(v, cpy.Elts) replace(&cpy) case *ast.ParenExpr: cpy := *n walkToReplace(v, cpy.X, func(r ast.Node) { cpy.X = r.(ast.Expr) }) replace(&cpy) case *ast.SelectorExpr: cpy := *n walkToReplace(v, cpy.X, func(r ast.Node) { cpy.X = r.(ast.Expr) }) walkToReplace(v, cpy.Sel, func(r ast.Node) { cpy.Sel = r.(*ast.Ident) }) replace(&cpy) case *ast.IndexExpr: cpy := *n walkToReplace(v, cpy.X, func(r ast.Node) { cpy.X = r.(ast.Expr) }) walkToReplace(v, cpy.Index, func(r ast.Node) { cpy.Index = r.(ast.Expr) }) replace(&cpy) case *ast.SliceExpr: cpy := *n walkToReplace(v, cpy.X, func(r ast.Node) { cpy.X = r.(ast.Expr) }) if cpy.Low != nil { walkToReplace(v, cpy.Low, func(r ast.Node) { cpy.Low = r.(ast.Expr) }) } if cpy.High != nil { walkToReplace(v, cpy.High, func(r ast.Node) { cpy.High = r.(ast.Expr) }) } if cpy.Max != nil { walkToReplace(v, cpy.Max, func(r ast.Node) { cpy.Max = r.(ast.Expr) }) } replace(&cpy) case *ast.TypeAssertExpr: cpy := *n walkToReplace(v, cpy.X, func(r ast.Node) { cpy.X = r.(ast.Expr) }) if cpy.Type != nil { walkToReplace(v, cpy.Type, func(r ast.Node) { cpy.Type = r.(ast.Expr) }) } replace(&cpy) case *ast.CallExpr: cpy := *n if n.Args != nil { cpy.Args = make([]ast.Expr, len(n.Args)) copy(cpy.Args, n.Args) } walkToReplace(v, cpy.Fun, func(r ast.Node) { cpy.Fun = r.(ast.Expr) }) walkExprList(v, cpy.Args) replace(&cpy) case *ast.StarExpr: cpy := *n walkToReplace(v, cpy.X, func(r ast.Node) { cpy.X = r.(ast.Expr) }) replace(&cpy) case *ast.UnaryExpr: cpy := *n walkToReplace(v, cpy.X, func(r ast.Node) { cpy.X = r.(ast.Expr) }) replace(&cpy) case *ast.BinaryExpr: cpy := *n walkToReplace(v, cpy.X, func(r ast.Node) { cpy.X = r.(ast.Expr) }) walkToReplace(v, cpy.Y, func(r ast.Node) { cpy.Y = r.(ast.Expr) }) replace(&cpy) case *ast.KeyValueExpr: cpy := *n walkToReplace(v, cpy.Key, func(r ast.Node) { cpy.Key = r.(ast.Expr) }) walkToReplace(v, cpy.Value, func(r ast.Node) { cpy.Value = r.(ast.Expr) }) replace(&cpy) // Types case *ast.ArrayType: cpy := *n if cpy.Len != nil { walkToReplace(v, cpy.Len, func(r ast.Node) { cpy.Len = r.(ast.Expr) }) } walkToReplace(v, cpy.Elt, func(r ast.Node) { cpy.Elt = r.(ast.Expr) }) replace(&cpy) case *ast.StructType: cpy := *n walkToReplace(v, cpy.Fields, func(r ast.Node) { cpy.Fields = r.(*ast.FieldList) }) replace(&cpy) case *ast.FuncType: cpy := *n if cpy.Params != nil { walkToReplace(v, cpy.Params, func(r ast.Node) { cpy.Params = r.(*ast.FieldList) }) } if cpy.Results != nil { walkToReplace(v, cpy.Results, func(r ast.Node) { cpy.Results = r.(*ast.FieldList) }) } replace(&cpy) case *ast.InterfaceType: cpy := *n walkToReplace(v, cpy.Methods, func(r ast.Node) { cpy.Methods = r.(*ast.FieldList) }) replace(&cpy) case *ast.MapType: cpy := *n walkToReplace(v, cpy.Key, func(r ast.Node) { cpy.Key = r.(ast.Expr) }) walkToReplace(v, cpy.Value, func(r ast.Node) { cpy.Value = r.(ast.Expr) }) replace(&cpy) case *ast.ChanType: cpy := *n walkToReplace(v, cpy.Value, func(r ast.Node) { cpy.Value = r.(ast.Expr) }) replace(&cpy) case *ast.DeclStmt: cpy := *n walkToReplace(v, cpy.Decl, func(r ast.Node) { cpy.Decl = r.(ast.Decl) }) replace(&cpy) case *ast.LabeledStmt: cpy := *n walkToReplace(v, cpy.Label, func(r ast.Node) { cpy.Label = r.(*ast.Ident) }) walkToReplace(v, cpy.Stmt, func(r ast.Node) { cpy.Stmt = r.(ast.Stmt) }) replace(&cpy) case *ast.ExprStmt: cpy := *n walkToReplace(v, cpy.X, func(r ast.Node) { cpy.X = r.(ast.Expr) }) replace(&cpy) case *ast.SendStmt: cpy := *n walkToReplace(v, cpy.Chan, func(r ast.Node) { cpy.Chan = r.(ast.Expr) }) walkToReplace(v, cpy.Value, func(r ast.Node) { cpy.Value = r.(ast.Expr) }) replace(&cpy) case *ast.IncDecStmt: cpy := *n walkToReplace(v, cpy.X, func(r ast.Node) { cpy.X = r.(ast.Expr) }) replace(&cpy) case *ast.AssignStmt: cpy := *n if n.Lhs != nil { cpy.Lhs = make([]ast.Expr, len(n.Lhs)) copy(cpy.Lhs, n.Lhs) } if n.Rhs != nil { cpy.Rhs = make([]ast.Expr, len(n.Rhs)) copy(cpy.Rhs, n.Rhs) } walkExprList(v, cpy.Lhs) walkExprList(v, cpy.Rhs) replace(&cpy) case *ast.GoStmt: cpy := *n walkToReplace(v, cpy.Call, func(r ast.Node) { cpy.Call = r.(*ast.CallExpr) }) replace(&cpy) case *ast.DeferStmt: cpy := *n walkToReplace(v, cpy.Call, func(r ast.Node) { cpy.Call = r.(*ast.CallExpr) }) replace(&cpy) case *ast.ReturnStmt: cpy := *n if n.Results != nil { cpy.Results = make([]ast.Expr, len(n.Results)) copy(cpy.Results, n.Results) } walkExprList(v, cpy.Results) replace(&cpy) case *ast.BranchStmt: cpy := *n if cpy.Label != nil { walkToReplace(v, cpy.Label, func(r ast.Node) { cpy.Label = r.(*ast.Ident) }) } replace(&cpy) case *ast.BlockStmt: cpy := *n if n.List != nil { cpy.List = make([]ast.Stmt, len(n.List)) copy(cpy.List, n.List) } walkStmtList(v, cpy.List) replace(&cpy) case *ast.IfStmt: cpy := *n if cpy.Init != nil { walkToReplace(v, cpy.Init, func(r ast.Node) { cpy.Init = r.(ast.Stmt) }) } walkToReplace(v, cpy.Cond, func(r ast.Node) { cpy.Cond = r.(ast.Expr) }) walkToReplace(v, cpy.Body, func(r ast.Node) { cpy.Body = r.(*ast.BlockStmt) }) if cpy.Else != nil { walkToReplace(v, cpy.Else, func(r ast.Node) { cpy.Else = r.(ast.Stmt) }) } replace(&cpy) case *ast.CaseClause: cpy := *n if n.List != nil { cpy.List = make([]ast.Expr, len(n.List)) copy(cpy.List, n.List) } if n.Body != nil { cpy.Body = make([]ast.Stmt, len(n.Body)) copy(cpy.Body, n.Body) } walkExprList(v, cpy.List) walkStmtList(v, cpy.Body) replace(&cpy) case *ast.SwitchStmt: cpy := *n if cpy.Init != nil { walkToReplace(v, cpy.Init, func(r ast.Node) { cpy.Init = r.(ast.Stmt) }) } if cpy.Tag != nil { walkToReplace(v, cpy.Tag, func(r ast.Node) { cpy.Tag = r.(ast.Expr) }) } walkToReplace(v, cpy.Body, func(r ast.Node) { cpy.Body = r.(*ast.BlockStmt) }) replace(&cpy) case *ast.TypeSwitchStmt: cpy := *n if cpy.Init != nil { walkToReplace(v, cpy.Init, func(r ast.Node) { cpy.Init = r.(ast.Stmt) }) } walkToReplace(v, cpy.Assign, func(r ast.Node) { cpy.Assign = r.(ast.Stmt) }) walkToReplace(v, cpy.Body, func(r ast.Node) { cpy.Body = r.(*ast.BlockStmt) }) replace(&cpy) case *ast.CommClause: cpy := *n if n.Body != nil { cpy.Body = make([]ast.Stmt, len(n.Body)) copy(cpy.Body, n.Body) } if cpy.Comm != nil { walkToReplace(v, cpy.Comm, func(r ast.Node) { cpy.Comm = r.(ast.Stmt) }) } walkStmtList(v, cpy.Body) replace(&cpy) case *ast.SelectStmt: cpy := *n walkToReplace(v, cpy.Body, func(r ast.Node) { cpy.Body = r.(*ast.BlockStmt) }) replace(&cpy) case *ast.ForStmt: cpy := *n if cpy.Init != nil { walkToReplace(v, cpy.Init, func(r ast.Node) { cpy.Init = r.(ast.Stmt) }) } if cpy.Cond != nil { walkToReplace(v, cpy.Cond, func(r ast.Node) { cpy.Cond = r.(ast.Expr) }) } if cpy.Post != nil { walkToReplace(v, cpy.Post, func(r ast.Node) { cpy.Post = r.(ast.Stmt) }) } walkToReplace(v, cpy.Body, func(r ast.Node) { cpy.Body = r.(*ast.BlockStmt) }) replace(&cpy) case *ast.RangeStmt: cpy := *n if cpy.Key != nil { walkToReplace(v, cpy.Key, func(r ast.Node) { cpy.Key = r.(ast.Expr) }) } if cpy.Value != nil { walkToReplace(v, cpy.Value, func(r ast.Node) { cpy.Value = r.(ast.Expr) }) } walkToReplace(v, cpy.X, func(r ast.Node) { cpy.X = r.(ast.Expr) }) walkToReplace(v, cpy.Body, func(r ast.Node) { cpy.Body = r.(*ast.BlockStmt) }) // Declarations replace(&cpy) case *ast.ImportSpec: cpy := *n if cpy.Doc != nil { walkToReplace(v, cpy.Doc, func(r ast.Node) { cpy.Doc = r.(*ast.CommentGroup) }) } if cpy.Name != nil { walkToReplace(v, cpy.Name, func(r ast.Node) { cpy.Name = r.(*ast.Ident) }) } walkToReplace(v, cpy.Path, func(r ast.Node) { cpy.Path = r.(*ast.BasicLit) }) if cpy.Comment != nil { walkToReplace(v, cpy.Comment, func(r ast.Node) { cpy.Comment = r.(*ast.CommentGroup) }) } replace(&cpy) case *ast.ValueSpec: cpy := *n if n.Names != nil { cpy.Names = make([]*ast.Ident, len(n.Names)) copy(cpy.Names, n.Names) } if n.Values != nil { cpy.Values = make([]ast.Expr, len(n.Values)) copy(cpy.Values, n.Values) } if cpy.Doc != nil { walkToReplace(v, cpy.Doc, func(r ast.Node) { cpy.Doc = r.(*ast.CommentGroup) }) } walkIdentList(v, cpy.Names) if cpy.Type != nil { walkToReplace(v, cpy.Type, func(r ast.Node) { cpy.Type = r.(ast.Expr) }) } walkExprList(v, cpy.Values) if cpy.Comment != nil { walkToReplace(v, cpy.Comment, func(r ast.Node) { cpy.Comment = r.(*ast.CommentGroup) }) } replace(&cpy) case *ast.TypeSpec: cpy := *n if cpy.Doc != nil { walkToReplace(v, cpy.Doc, func(r ast.Node) { cpy.Doc = r.(*ast.CommentGroup) }) } walkToReplace(v, cpy.Name, func(r ast.Node) { cpy.Name = r.(*ast.Ident) }) walkToReplace(v, cpy.Type, func(r ast.Node) { cpy.Type = r.(ast.Expr) }) if cpy.Comment != nil { walkToReplace(v, cpy.Comment, func(r ast.Node) { cpy.Comment = r.(*ast.CommentGroup) }) } replace(&cpy) case *ast.GenDecl: cpy := *n if n.Specs != nil { cpy.Specs = make([]ast.Spec, len(n.Specs)) copy(cpy.Specs, n.Specs) } if cpy.Doc != nil { walkToReplace(v, cpy.Doc, func(r ast.Node) { cpy.Doc = r.(*ast.CommentGroup) }) } for i, s := range cpy.Specs { walkToReplace(v, s, func(r ast.Node) { cpy.Specs[i] = r.(ast.Spec) }) } replace(&cpy) case *ast.FuncDecl: cpy := *n if cpy.Doc != nil { walkToReplace(v, cpy.Doc, func(r ast.Node) { cpy.Doc = r.(*ast.CommentGroup) }) } if cpy.Recv != nil { walkToReplace(v, cpy.Recv, func(r ast.Node) { cpy.Recv = r.(*ast.FieldList) }) } walkToReplace(v, cpy.Name, func(r ast.Node) { cpy.Name = r.(*ast.Ident) }) walkToReplace(v, cpy.Type, func(r ast.Node) { cpy.Type = r.(*ast.FuncType) }) if cpy.Body != nil { walkToReplace(v, cpy.Body, func(r ast.Node) { cpy.Body = r.(*ast.BlockStmt) }) } // Files and packages replace(&cpy) case *ast.File: cpy := *n if cpy.Doc != nil { walkToReplace(v, cpy.Doc, func(r ast.Node) { cpy.Doc = r.(*ast.CommentGroup) }) } walkToReplace(v, cpy.Name, func(r ast.Node) { cpy.Name = r.(*ast.Ident) }) walkDeclList(v, cpy.Decls) // don't walk cpy.Comments - they have been // visited already through the individual // nodes replace(&cpy) case *ast.Package: cpy := *n cpy.Files = map[string]*ast.File{} for i, f := range n.Files { cpy.Files[i] = f walkToReplace(v, f, func(r ast.Node) { cpy.Files[i] = r.(*ast.File) }) } replace(&cpy) default: panic(fmt.Sprintf("walkToReplace: unexpected node type %T", n)) } if v != nil { v.Visit(nil, func(ast.Node) { panic("can't replace the go-up nil") }) } } golang-github-go-kit-kit-0.10.0/cmd/kitgen/sourcecontext.go000066400000000000000000000020451362256312400235610ustar00rootroot00000000000000package main import ( "fmt" "go/ast" "go/token" ) type sourceContext struct { pkg *ast.Ident imports []*ast.ImportSpec interfaces []iface types []*ast.TypeSpec } func (sc *sourceContext) validate() error { if len(sc.interfaces) != 1 { return fmt.Errorf("found %d interfaces, expecting exactly 1", len(sc.interfaces)) } for _, i := range sc.interfaces { for _, m := range i.methods { if len(m.results) < 1 { return fmt.Errorf("method %q of interface %q has no result types", m.name, i.name) } } } return nil } func (sc *sourceContext) importDecls() (decls []ast.Decl) { have := map[string]struct{}{} notHave := func(is *ast.ImportSpec) bool { if _, has := have[is.Path.Value]; has { return false } have[is.Path.Value] = struct{}{} return true } for _, is := range sc.imports { if notHave(is) { decls = append(decls, importFor(is)) } } for _, is := range fetchImports() { if notHave(is) { decls = append(decls, &ast.GenDecl{Tok: token.IMPORT, Specs: []ast.Spec{is}}) } } return } golang-github-go-kit-kit-0.10.0/cmd/kitgen/templates/000077500000000000000000000000001362256312400223225ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/templates/full.go000066400000000000000000000027041362256312400236160ustar00rootroot00000000000000package foo import ( "context" "encoding/json" "errors" "net/http" "github.com/go-kit/kit/endpoint" httptransport "github.com/go-kit/kit/transport/http" ) type ExampleService struct { } type ExampleRequest struct { I int S string } type ExampleResponse struct { S string Err error } type Endpoints struct { ExampleEndpoint endpoint.Endpoint } func (f ExampleService) ExampleEndpoint(ctx context.Context, i int, s string) (string, error) { panic(errors.New("not implemented")) } func makeExampleEndpoint(f ExampleService) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(ExampleRequest) s, err := f.ExampleEndpoint(ctx, req.I, req.S) return ExampleResponse{S: s, Err: err}, nil } } func inlineHandlerBuilder(m *http.ServeMux, endpoints Endpoints) { m.Handle("/bar", httptransport.NewServer(endpoints.ExampleEndpoint, DecodeExampleRequest, EncodeExampleResponse)) } func NewHTTPHandler(endpoints Endpoints) http.Handler { m := http.NewServeMux() inlineHandlerBuilder(m, endpoints) return m } func DecodeExampleRequest(_ context.Context, r *http.Request) (interface{}, error) { var req ExampleRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeExampleResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/000077500000000000000000000000001362256312400221355ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/anonfields/000077500000000000000000000000001362256312400242575ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/anonfields/default/000077500000000000000000000000001362256312400257035ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/anonfields/default/endpoints/000077500000000000000000000000001362256312400277065ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/anonfields/default/endpoints/endpoints.go000066400000000000000000000010401362256312400322330ustar00rootroot00000000000000package endpoints import ( "context" "github.com/go-kit/kit/cmd/kitgen/testdata/anonfields/default/service" "github.com/go-kit/kit/endpoint" ) type FooRequest struct { I int S string } type FooResponse struct { I int Err error } func MakeFooEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(FooRequest) i, err := s.Foo(ctx, req.I, req.S) return FooResponse{I: i, Err: err}, nil } } type Endpoints struct { Foo endpoint.Endpoint } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/anonfields/default/http/000077500000000000000000000000001362256312400266625ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/anonfields/default/http/http.go000066400000000000000000000014101362256312400301640ustar00rootroot00000000000000package http import ( "context" "encoding/json" "net/http" "github.com/go-kit/kit/cmd/kitgen/testdata/anonfields/default/endpoints" httptransport "github.com/go-kit/kit/transport/http" ) func NewHTTPHandler(endpoints endpoints.Endpoints) http.Handler { m := http.NewServeMux() m.Handle("/foo", httptransport.NewServer(endpoints.Foo, DecodeFooRequest, EncodeFooResponse)) return m } func DecodeFooRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.FooRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeFooResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/anonfields/default/service/000077500000000000000000000000001362256312400273435ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/anonfields/default/service/service.go000066400000000000000000000003031362256312400313260ustar00rootroot00000000000000package service import ( "context" "errors" ) type Service struct { } func (s Service) Foo(ctx context.Context, i int, string1 string) (int, error) { panic(errors.New("not implemented")) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/anonfields/flat/000077500000000000000000000000001362256312400252055ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/anonfields/flat/gokit.go000066400000000000000000000023541362256312400266550ustar00rootroot00000000000000package foo import ( "context" "encoding/json" "errors" "net/http" "github.com/go-kit/kit/endpoint" httptransport "github.com/go-kit/kit/transport/http" ) type Service struct { } func (s Service) Foo(ctx context.Context, i int, string1 string) (int, error) { panic(errors.New("not implemented")) } type FooRequest struct { I int S string } type FooResponse struct { I int Err error } func MakeFooEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(FooRequest) i, err := s.Foo(ctx, req.I, req.S) return FooResponse{I: i, Err: err}, nil } } type Endpoints struct { Foo endpoint.Endpoint } func NewHTTPHandler(endpoints Endpoints) http.Handler { m := http.NewServeMux() m.Handle("/foo", httptransport.NewServer(endpoints.Foo, DecodeFooRequest, EncodeFooResponse)) return m } func DecodeFooRequest(_ context.Context, r *http.Request) (interface{}, error) { var req FooRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeFooResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/anonfields/in.go000066400000000000000000000002361362256312400252150ustar00rootroot00000000000000package foo // from https://github.com/go-kit/kit/pull/589#issuecomment-319937530 type Service interface { Foo(context.Context, int, string) (int, error) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/foo/000077500000000000000000000000001362256312400227205ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/foo/default/000077500000000000000000000000001362256312400243445ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/foo/default/endpoints/000077500000000000000000000000001362256312400263475ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/foo/default/endpoints/endpoints.go000066400000000000000000000010371362256312400307020ustar00rootroot00000000000000package endpoints import ( "context" "github.com/go-kit/kit/cmd/kitgen/testdata/foo/default/service" "github.com/go-kit/kit/endpoint" ) type BarRequest struct { I int S string } type BarResponse struct { S string Err error } func MakeBarEndpoint(f service.FooService) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(BarRequest) s, err := f.Bar(ctx, req.I, req.S) return BarResponse{S: s, Err: err}, nil } } type Endpoints struct { Bar endpoint.Endpoint } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/foo/default/http/000077500000000000000000000000001362256312400253235ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/foo/default/http/http.go000066400000000000000000000014011362256312400266250ustar00rootroot00000000000000package http import ( "context" "encoding/json" "net/http" "github.com/go-kit/kit/cmd/kitgen/testdata/foo/default/endpoints" httptransport "github.com/go-kit/kit/transport/http" ) func NewHTTPHandler(endpoints endpoints.Endpoints) http.Handler { m := http.NewServeMux() m.Handle("/bar", httptransport.NewServer(endpoints.Bar, DecodeBarRequest, EncodeBarResponse)) return m } func DecodeBarRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.BarRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeBarResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/foo/default/service/000077500000000000000000000000001362256312400260045ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/foo/default/service/service.go000066400000000000000000000003061362256312400277720ustar00rootroot00000000000000package service import ( "context" "errors" ) type FooService struct { } func (f FooService) Bar(ctx context.Context, i int, s string) (string, error) { panic(errors.New("not implemented")) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/foo/flat/000077500000000000000000000000001362256312400236465ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/foo/flat/gokit.go000066400000000000000000000023651362256312400253200ustar00rootroot00000000000000package foo import ( "context" "encoding/json" "errors" "net/http" "github.com/go-kit/kit/endpoint" httptransport "github.com/go-kit/kit/transport/http" ) type FooService struct { } func (f FooService) Bar(ctx context.Context, i int, s string) (string, error) { panic(errors.New("not implemented")) } type BarRequest struct { I int S string } type BarResponse struct { S string Err error } func MakeBarEndpoint(f FooService) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(BarRequest) s, err := f.Bar(ctx, req.I, req.S) return BarResponse{S: s, Err: err}, nil } } type Endpoints struct { Bar endpoint.Endpoint } func NewHTTPHandler(endpoints Endpoints) http.Handler { m := http.NewServeMux() m.Handle("/bar", httptransport.NewServer(endpoints.Bar, DecodeBarRequest, EncodeBarResponse)) return m } func DecodeBarRequest(_ context.Context, r *http.Request) (interface{}, error) { var req BarRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeBarResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/foo/in.go000066400000000000000000000001461362256312400236560ustar00rootroot00000000000000package foo type FooService interface { Bar(ctx context.Context, i int, s string) (string, error) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/profilesvc/000077500000000000000000000000001362256312400243115ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/profilesvc/default/000077500000000000000000000000001362256312400257355ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/profilesvc/default/endpoints/000077500000000000000000000000001362256312400277405ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/profilesvc/default/endpoints/endpoints.go000066400000000000000000000077651362256312400323110ustar00rootroot00000000000000package endpoints import ( "context" "github.com/go-kit/kit/cmd/kitgen/testdata/profilesvc/default/service" "github.com/go-kit/kit/endpoint" ) type PostProfileRequest struct { P service.Profile } type PostProfileResponse struct { Err error } func MakePostProfileEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(PostProfileRequest) err := s.PostProfile(ctx, req.P) return PostProfileResponse{Err: err}, nil } } type GetProfileRequest struct { Id string } type GetProfileResponse struct { P service.Profile Err error } func MakeGetProfileEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(GetProfileRequest) P, err := s.GetProfile(ctx, req.Id) return GetProfileResponse{P: P, Err: err}, nil } } type PutProfileRequest struct { Id string P service.Profile } type PutProfileResponse struct { Err error } func MakePutProfileEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(PutProfileRequest) err := s.PutProfile(ctx, req.Id, req.P) return PutProfileResponse{Err: err}, nil } } type PatchProfileRequest struct { Id string P service.Profile } type PatchProfileResponse struct { Err error } func MakePatchProfileEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(PatchProfileRequest) err := s.PatchProfile(ctx, req.Id, req.P) return PatchProfileResponse{Err: err}, nil } } type DeleteProfileRequest struct { Id string } type DeleteProfileResponse struct { Err error } func MakeDeleteProfileEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(DeleteProfileRequest) err := s.DeleteProfile(ctx, req.Id) return DeleteProfileResponse{Err: err}, nil } } type GetAddressesRequest struct { ProfileID string } type GetAddressesResponse struct { S []service.Address Err error } func MakeGetAddressesEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(GetAddressesRequest) slice1, err := s.GetAddresses(ctx, req.ProfileID) return GetAddressesResponse{S: slice1, Err: err}, nil } } type GetAddressRequest struct { ProfileID string AddressID string } type GetAddressResponse struct { A service.Address Err error } func MakeGetAddressEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(GetAddressRequest) A, err := s.GetAddress(ctx, req.ProfileID, req.AddressID) return GetAddressResponse{A: A, Err: err}, nil } } type PostAddressRequest struct { ProfileID string A service.Address } type PostAddressResponse struct { Err error } func MakePostAddressEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(PostAddressRequest) err := s.PostAddress(ctx, req.ProfileID, req.A) return PostAddressResponse{Err: err}, nil } } type DeleteAddressRequest struct { ProfileID string AddressID string } type DeleteAddressResponse struct { Err error } func MakeDeleteAddressEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(DeleteAddressRequest) err := s.DeleteAddress(ctx, req.ProfileID, req.AddressID) return DeleteAddressResponse{Err: err}, nil } } type Endpoints struct { PostProfile endpoint.Endpoint GetProfile endpoint.Endpoint PutProfile endpoint.Endpoint PatchProfile endpoint.Endpoint DeleteProfile endpoint.Endpoint GetAddresses endpoint.Endpoint GetAddress endpoint.Endpoint PostAddress endpoint.Endpoint DeleteAddress endpoint.Endpoint } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/profilesvc/default/http/000077500000000000000000000000001362256312400267145ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/profilesvc/default/http/http.go000066400000000000000000000120051362256312400302200ustar00rootroot00000000000000package http import ( "context" "encoding/json" "net/http" "github.com/go-kit/kit/cmd/kitgen/testdata/profilesvc/default/endpoints" httptransport "github.com/go-kit/kit/transport/http" ) func NewHTTPHandler(endpoints endpoints.Endpoints) http.Handler { m := http.NewServeMux() m.Handle("/postprofile", httptransport.NewServer(endpoints.PostProfile, DecodePostProfileRequest, EncodePostProfileResponse)) m.Handle("/getprofile", httptransport.NewServer(endpoints.GetProfile, DecodeGetProfileRequest, EncodeGetProfileResponse)) m.Handle("/putprofile", httptransport.NewServer(endpoints.PutProfile, DecodePutProfileRequest, EncodePutProfileResponse)) m.Handle("/patchprofile", httptransport.NewServer(endpoints.PatchProfile, DecodePatchProfileRequest, EncodePatchProfileResponse)) m.Handle("/deleteprofile", httptransport.NewServer(endpoints.DeleteProfile, DecodeDeleteProfileRequest, EncodeDeleteProfileResponse)) m.Handle("/getaddresses", httptransport.NewServer(endpoints.GetAddresses, DecodeGetAddressesRequest, EncodeGetAddressesResponse)) m.Handle("/getaddress", httptransport.NewServer(endpoints.GetAddress, DecodeGetAddressRequest, EncodeGetAddressResponse)) m.Handle("/postaddress", httptransport.NewServer(endpoints.PostAddress, DecodePostAddressRequest, EncodePostAddressResponse)) m.Handle("/deleteaddress", httptransport.NewServer(endpoints.DeleteAddress, DecodeDeleteAddressRequest, EncodeDeleteAddressResponse)) return m } func DecodePostProfileRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.PostProfileRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodePostProfileResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodeGetProfileRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.GetProfileRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeGetProfileResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodePutProfileRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.PutProfileRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodePutProfileResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodePatchProfileRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.PatchProfileRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodePatchProfileResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodeDeleteProfileRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.DeleteProfileRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeDeleteProfileResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodeGetAddressesRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.GetAddressesRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeGetAddressesResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodeGetAddressRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.GetAddressRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeGetAddressResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodePostAddressRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.PostAddressRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodePostAddressResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodeDeleteAddressRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.DeleteAddressRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeDeleteAddressResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/profilesvc/default/service/000077500000000000000000000000001362256312400273755ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/profilesvc/default/service/service.go000066400000000000000000000026411362256312400313670ustar00rootroot00000000000000package service import ( "context" "errors" ) type Profile struct { ID string `json:"id"` Name string `json:"name,omitempty"` Addresses []Address `json:"addresses,omitempty"` } type Address struct { ID string `json:"id"` Location string `json:"location,omitempty"` } type Service struct { } func (s Service) PostProfile(ctx context.Context, p Profile) error { panic(errors.New("not implemented")) } func (s Service) GetProfile(ctx context.Context, id string) (Profile, error) { panic(errors.New("not implemented")) } func (s Service) PutProfile(ctx context.Context, id string, p Profile) error { panic(errors.New("not implemented")) } func (s Service) PatchProfile(ctx context.Context, id string, p Profile) error { panic(errors.New("not implemented")) } func (s Service) DeleteProfile(ctx context.Context, id string) error { panic(errors.New("not implemented")) } func (s Service) GetAddresses(ctx context.Context, profileID string) ([]Address, error) { panic(errors.New("not implemented")) } func (s Service) GetAddress(ctx context.Context, profileID string, addressID string) (Address, error) { panic(errors.New("not implemented")) } func (s Service) PostAddress(ctx context.Context, profileID string, a Address) error { panic(errors.New("not implemented")) } func (s Service) DeleteAddress(ctx context.Context, profileID string, addressID string) error { panic(errors.New("not implemented")) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/profilesvc/flat/000077500000000000000000000000001362256312400252375ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/profilesvc/flat/gokit.go000066400000000000000000000237331362256312400267130ustar00rootroot00000000000000package profilesvc import ( "context" "encoding/json" "errors" "net/http" "github.com/go-kit/kit/endpoint" httptransport "github.com/go-kit/kit/transport/http" ) type Profile struct { ID string `json:"id"` Name string `json:"name,omitempty"` Addresses []Address `json:"addresses,omitempty"` } type Address struct { ID string `json:"id"` Location string `json:"location,omitempty"` } type Service struct { } func (s Service) PostProfile(ctx context.Context, p Profile) error { panic(errors.New("not implemented")) } type PostProfileRequest struct { P Profile } type PostProfileResponse struct { Err error } func MakePostProfileEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(PostProfileRequest) err := s.PostProfile(ctx, req.P) return PostProfileResponse{Err: err}, nil } } func (s Service) GetProfile(ctx context.Context, id string) (Profile, error) { panic(errors.New("not implemented")) } type GetProfileRequest struct { Id string } type GetProfileResponse struct { P Profile Err error } func MakeGetProfileEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(GetProfileRequest) P, err := s.GetProfile(ctx, req.Id) return GetProfileResponse{P: P, Err: err}, nil } } func (s Service) PutProfile(ctx context.Context, id string, p Profile) error { panic(errors.New("not implemented")) } type PutProfileRequest struct { Id string P Profile } type PutProfileResponse struct { Err error } func MakePutProfileEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(PutProfileRequest) err := s.PutProfile(ctx, req.Id, req.P) return PutProfileResponse{Err: err}, nil } } func (s Service) PatchProfile(ctx context.Context, id string, p Profile) error { panic(errors.New("not implemented")) } type PatchProfileRequest struct { Id string P Profile } type PatchProfileResponse struct { Err error } func MakePatchProfileEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(PatchProfileRequest) err := s.PatchProfile(ctx, req.Id, req.P) return PatchProfileResponse{Err: err}, nil } } func (s Service) DeleteProfile(ctx context.Context, id string) error { panic(errors.New("not implemented")) } type DeleteProfileRequest struct { Id string } type DeleteProfileResponse struct { Err error } func MakeDeleteProfileEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(DeleteProfileRequest) err := s.DeleteProfile(ctx, req.Id) return DeleteProfileResponse{Err: err}, nil } } func (s Service) GetAddresses(ctx context.Context, profileID string) ([]Address, error) { panic(errors.New("not implemented")) } type GetAddressesRequest struct { ProfileID string } type GetAddressesResponse struct { S []Address Err error } func MakeGetAddressesEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(GetAddressesRequest) slice1, err := s.GetAddresses(ctx, req.ProfileID) return GetAddressesResponse{S: slice1, Err: err}, nil } } func (s Service) GetAddress(ctx context.Context, profileID string, addressID string) (Address, error) { panic(errors.New("not implemented")) } type GetAddressRequest struct { ProfileID string AddressID string } type GetAddressResponse struct { A Address Err error } func MakeGetAddressEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(GetAddressRequest) A, err := s.GetAddress(ctx, req.ProfileID, req.AddressID) return GetAddressResponse{A: A, Err: err}, nil } } func (s Service) PostAddress(ctx context.Context, profileID string, a Address) error { panic(errors.New("not implemented")) } type PostAddressRequest struct { ProfileID string A Address } type PostAddressResponse struct { Err error } func MakePostAddressEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(PostAddressRequest) err := s.PostAddress(ctx, req.ProfileID, req.A) return PostAddressResponse{Err: err}, nil } } func (s Service) DeleteAddress(ctx context.Context, profileID string, addressID string) error { panic(errors.New("not implemented")) } type DeleteAddressRequest struct { ProfileID string AddressID string } type DeleteAddressResponse struct { Err error } func MakeDeleteAddressEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(DeleteAddressRequest) err := s.DeleteAddress(ctx, req.ProfileID, req.AddressID) return DeleteAddressResponse{Err: err}, nil } } type Endpoints struct { PostProfile endpoint.Endpoint GetProfile endpoint.Endpoint PutProfile endpoint.Endpoint PatchProfile endpoint.Endpoint DeleteProfile endpoint.Endpoint GetAddresses endpoint.Endpoint GetAddress endpoint.Endpoint PostAddress endpoint.Endpoint DeleteAddress endpoint.Endpoint } func NewHTTPHandler(endpoints Endpoints) http.Handler { m := http.NewServeMux() m.Handle("/postprofile", httptransport.NewServer(endpoints.PostProfile, DecodePostProfileRequest, EncodePostProfileResponse)) m.Handle("/getprofile", httptransport.NewServer(endpoints.GetProfile, DecodeGetProfileRequest, EncodeGetProfileResponse)) m.Handle("/putprofile", httptransport.NewServer(endpoints.PutProfile, DecodePutProfileRequest, EncodePutProfileResponse)) m.Handle("/patchprofile", httptransport.NewServer(endpoints.PatchProfile, DecodePatchProfileRequest, EncodePatchProfileResponse)) m.Handle("/deleteprofile", httptransport.NewServer(endpoints.DeleteProfile, DecodeDeleteProfileRequest, EncodeDeleteProfileResponse)) m.Handle("/getaddresses", httptransport.NewServer(endpoints.GetAddresses, DecodeGetAddressesRequest, EncodeGetAddressesResponse)) m.Handle("/getaddress", httptransport.NewServer(endpoints.GetAddress, DecodeGetAddressRequest, EncodeGetAddressResponse)) m.Handle("/postaddress", httptransport.NewServer(endpoints.PostAddress, DecodePostAddressRequest, EncodePostAddressResponse)) m.Handle("/deleteaddress", httptransport.NewServer(endpoints.DeleteAddress, DecodeDeleteAddressRequest, EncodeDeleteAddressResponse)) return m } func DecodePostProfileRequest(_ context.Context, r *http.Request) (interface{}, error) { var req PostProfileRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodePostProfileResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodeGetProfileRequest(_ context.Context, r *http.Request) (interface{}, error) { var req GetProfileRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeGetProfileResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodePutProfileRequest(_ context.Context, r *http.Request) (interface{}, error) { var req PutProfileRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodePutProfileResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodePatchProfileRequest(_ context.Context, r *http.Request) (interface{}, error) { var req PatchProfileRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodePatchProfileResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodeDeleteProfileRequest(_ context.Context, r *http.Request) (interface{}, error) { var req DeleteProfileRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeDeleteProfileResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodeGetAddressesRequest(_ context.Context, r *http.Request) (interface{}, error) { var req GetAddressesRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeGetAddressesResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodeGetAddressRequest(_ context.Context, r *http.Request) (interface{}, error) { var req GetAddressRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeGetAddressResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodePostAddressRequest(_ context.Context, r *http.Request) (interface{}, error) { var req PostAddressRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodePostAddressResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodeDeleteAddressRequest(_ context.Context, r *http.Request) (interface{}, error) { var req DeleteAddressRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeDeleteAddressResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/profilesvc/in.go000066400000000000000000000015751362256312400252560ustar00rootroot00000000000000package profilesvc type Service interface { PostProfile(ctx context.Context, p Profile) error GetProfile(ctx context.Context, id string) (Profile, error) PutProfile(ctx context.Context, id string, p Profile) error PatchProfile(ctx context.Context, id string, p Profile) error DeleteProfile(ctx context.Context, id string) error GetAddresses(ctx context.Context, profileID string) ([]Address, error) GetAddress(ctx context.Context, profileID string, addressID string) (Address, error) PostAddress(ctx context.Context, profileID string, a Address) error DeleteAddress(ctx context.Context, profileID string, addressID string) error } type Profile struct { ID string `json:"id"` Name string `json:"name,omitempty"` Addresses []Address `json:"addresses,omitempty"` } type Address struct { ID string `json:"id"` Location string `json:"location,omitempty"` } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/stringservice/000077500000000000000000000000001362256312400250245ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/stringservice/default/000077500000000000000000000000001362256312400264505ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/stringservice/default/endpoints/000077500000000000000000000000001362256312400304535ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/stringservice/default/endpoints/endpoints.go000066400000000000000000000016601362256312400330100ustar00rootroot00000000000000package endpoints import ( "context" "github.com/go-kit/kit/cmd/kitgen/testdata/stringservice/default/service" "github.com/go-kit/kit/endpoint" ) type ConcatRequest struct { A string B string } type ConcatResponse struct { S string Err error } func MakeConcatEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(ConcatRequest) string1, err := s.Concat(ctx, req.A, req.B) return ConcatResponse{S: string1, Err: err}, nil } } type CountRequest struct { S string } type CountResponse struct { Count int } func MakeCountEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(CountRequest) count := s.Count(ctx, req.S) return CountResponse{Count: count}, nil } } type Endpoints struct { Concat endpoint.Endpoint Count endpoint.Endpoint } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/stringservice/default/http/000077500000000000000000000000001362256312400274275ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/stringservice/default/http/http.go000066400000000000000000000024141362256312400307360ustar00rootroot00000000000000package http import ( "context" "encoding/json" "net/http" "github.com/go-kit/kit/cmd/kitgen/testdata/stringservice/default/endpoints" httptransport "github.com/go-kit/kit/transport/http" ) func NewHTTPHandler(endpoints endpoints.Endpoints) http.Handler { m := http.NewServeMux() m.Handle("/concat", httptransport.NewServer(endpoints.Concat, DecodeConcatRequest, EncodeConcatResponse)) m.Handle("/count", httptransport.NewServer(endpoints.Count, DecodeCountRequest, EncodeCountResponse)) return m } func DecodeConcatRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.ConcatRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeConcatResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodeCountRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.CountRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeCountResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/stringservice/default/service/000077500000000000000000000000001362256312400301105ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/stringservice/default/service/service.go000066400000000000000000000004601362256312400320770ustar00rootroot00000000000000package service import ( "context" "errors" ) type Service struct { } func (s Service) Concat(ctx context.Context, a string, b string) (string, error) { panic(errors.New("not implemented")) } func (s Service) Count(ctx context.Context, string1 string) int { panic(errors.New("not implemented")) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/stringservice/flat/000077500000000000000000000000001362256312400257525ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/stringservice/flat/gokit.go000066400000000000000000000043251362256312400274220ustar00rootroot00000000000000package foo import ( "context" "encoding/json" "errors" "net/http" "github.com/go-kit/kit/endpoint" httptransport "github.com/go-kit/kit/transport/http" ) type Service struct { } func (s Service) Concat(ctx context.Context, a string, b string) (string, error) { panic(errors.New("not implemented")) } type ConcatRequest struct { A string B string } type ConcatResponse struct { S string Err error } func MakeConcatEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(ConcatRequest) string1, err := s.Concat(ctx, req.A, req.B) return ConcatResponse{S: string1, Err: err}, nil } } func (s Service) Count(ctx context.Context, string1 string) int { panic(errors.New("not implemented")) } type CountRequest struct { S string } type CountResponse struct { Count int } func MakeCountEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(CountRequest) count := s.Count(ctx, req.S) return CountResponse{Count: count}, nil } } type Endpoints struct { Concat endpoint.Endpoint Count endpoint.Endpoint } func NewHTTPHandler(endpoints Endpoints) http.Handler { m := http.NewServeMux() m.Handle("/concat", httptransport.NewServer(endpoints.Concat, DecodeConcatRequest, EncodeConcatResponse)) m.Handle("/count", httptransport.NewServer(endpoints.Count, DecodeCountRequest, EncodeCountResponse)) return m } func DecodeConcatRequest(_ context.Context, r *http.Request) (interface{}, error) { var req ConcatRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeConcatResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } func DecodeCountRequest(_ context.Context, r *http.Request) (interface{}, error) { var req CountRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeCountResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/stringservice/in.go000066400000000000000000000002241362256312400257570ustar00rootroot00000000000000package foo type Service interface { Concat(ctx context.Context, a, b string) (string, error) Count(ctx context.Context, s string) (count int) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/underscores/000077500000000000000000000000001362256312400244715ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/underscores/default/000077500000000000000000000000001362256312400261155ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/underscores/default/endpoints/000077500000000000000000000000001362256312400301205ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/underscores/default/endpoints/endpoints.go000066400000000000000000000010201362256312400324430ustar00rootroot00000000000000package endpoints import ( "context" "github.com/go-kit/kit/cmd/kitgen/testdata/underscores/default/service" "github.com/go-kit/kit/endpoint" ) type FooRequest struct { I int } type FooResponse struct { I int Err error } func MakeFooEndpoint(s service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(FooRequest) i, err := s.Foo(ctx, req.I) return FooResponse{I: i, Err: err}, nil } } type Endpoints struct { Foo endpoint.Endpoint } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/underscores/default/http/000077500000000000000000000000001362256312400270745ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/underscores/default/http/http.go000066400000000000000000000014111362256312400303770ustar00rootroot00000000000000package http import ( "context" "encoding/json" "net/http" "github.com/go-kit/kit/cmd/kitgen/testdata/underscores/default/endpoints" httptransport "github.com/go-kit/kit/transport/http" ) func NewHTTPHandler(endpoints endpoints.Endpoints) http.Handler { m := http.NewServeMux() m.Handle("/foo", httptransport.NewServer(endpoints.Foo, DecodeFooRequest, EncodeFooResponse)) return m } func DecodeFooRequest(_ context.Context, r *http.Request) (interface{}, error) { var req endpoints.FooRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeFooResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/underscores/default/service/000077500000000000000000000000001362256312400275555ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/underscores/default/service/service.go000066400000000000000000000002631362256312400315450ustar00rootroot00000000000000package service import ( "context" "errors" ) type Service struct { } func (s Service) Foo(ctx context.Context, i int) (int, error) { panic(errors.New("not implemented")) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/underscores/flat/000077500000000000000000000000001362256312400254175ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/underscores/flat/gokit.go000066400000000000000000000023231362256312400270630ustar00rootroot00000000000000package underscores import ( "context" "encoding/json" "errors" "net/http" "github.com/go-kit/kit/endpoint" httptransport "github.com/go-kit/kit/transport/http" ) type Service struct { } func (s Service) Foo(ctx context.Context, i int) (int, error) { panic(errors.New("not implemented")) } type FooRequest struct { I int } type FooResponse struct { I int Err error } func MakeFooEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(FooRequest) i, err := s.Foo(ctx, req.I) return FooResponse{I: i, Err: err}, nil } } type Endpoints struct { Foo endpoint.Endpoint } func NewHTTPHandler(endpoints Endpoints) http.Handler { m := http.NewServeMux() m.Handle("/foo", httptransport.NewServer(endpoints.Foo, DecodeFooRequest, EncodeFooResponse)) return m } func DecodeFooRequest(_ context.Context, r *http.Request) (interface{}, error) { var req FooRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } func EncodeFooResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/testdata/underscores/in.go000066400000000000000000000001561362256312400254300ustar00rootroot00000000000000package underscores import "context" type Service interface { Foo(_ context.Context, _ int) (int, error) } golang-github-go-kit-kit-0.10.0/cmd/kitgen/transform.go000066400000000000000000000117251362256312400226740ustar00rootroot00000000000000package main import ( "bytes" "fmt" "go/ast" "go/format" "go/token" "io" "os" "path/filepath" "sort" "strings" "github.com/davecgh/go-spew/spew" "github.com/pkg/errors" "golang.org/x/tools/imports" ) type ( files map[string]io.Reader layout interface { transformAST(ctx *sourceContext) (files, error) } outputTree map[string]*ast.File ) func (ot outputTree) addFile(path, pkgname string) *ast.File { file := &ast.File{ Name: id(pkgname), Decls: []ast.Decl{}, } ot[path] = file return file } func getGopath() string { gopath, set := os.LookupEnv("GOPATH") if !set { return filepath.Join(os.Getenv("HOME"), "go") } return gopath } func importPath(targetDir, gopath string) (string, error) { if !filepath.IsAbs(targetDir) { return "", fmt.Errorf("%q is not an absolute path", targetDir) } for _, dir := range filepath.SplitList(gopath) { abspath, err := filepath.Abs(dir) if err != nil { continue } srcPath := filepath.Join(abspath, "src") res, err := filepath.Rel(srcPath, targetDir) if err != nil { continue } if strings.Index(res, "..") == -1 { return res, nil } } return "", fmt.Errorf("%q is not in GOPATH (%s)", targetDir, gopath) } func selectify(file *ast.File, pkgName, identName, importPath string) *ast.File { if file.Name.Name == pkgName { return file } selector := sel(id(pkgName), id(identName)) var did bool if file, did = selectifyIdent(identName, file, selector); did { addImport(file, importPath) } return file } type selIdentFn func(ast.Node, func(ast.Node)) Visitor func (f selIdentFn) Visit(node ast.Node, r func(ast.Node)) Visitor { return f(node, r) } func selectifyIdent(identName string, file *ast.File, selector ast.Expr) (*ast.File, bool) { var replaced bool var r selIdentFn r = selIdentFn(func(node ast.Node, replaceWith func(ast.Node)) Visitor { switch id := node.(type) { case *ast.SelectorExpr: return nil case *ast.Ident: if id.Name == identName { replaced = true replaceWith(selector) } } return r }) return WalkReplace(r, file).(*ast.File), replaced } func formatNode(fname string, node ast.Node) (*bytes.Buffer, error) { if file, is := node.(*ast.File); is { sort.Stable(sortableDecls(file.Decls)) } outfset := token.NewFileSet() buf := &bytes.Buffer{} err := format.Node(buf, outfset, node) if err != nil { return nil, err } imps, err := imports.Process(fname, buf.Bytes(), nil) if err != nil { return nil, err } return bytes.NewBuffer(imps), nil } type sortableDecls []ast.Decl func (sd sortableDecls) Len() int { return len(sd) } func (sd sortableDecls) Less(i int, j int) bool { switch left := sd[i].(type) { case *ast.GenDecl: switch right := sd[j].(type) { default: return left.Tok == token.IMPORT case *ast.GenDecl: return left.Tok == token.IMPORT && right.Tok != token.IMPORT } } return false } func (sd sortableDecls) Swap(i int, j int) { sd[i], sd[j] = sd[j], sd[i] } func formatNodes(nodes outputTree) (files, error) { res := files{} var err error for fn, node := range nodes { res[fn], err = formatNode(fn, node) if err != nil { return nil, errors.Wrapf(err, "formatNodes") } } return res, nil } // XXX debug func spewDecls(f *ast.File) { for _, d := range f.Decls { switch dcl := d.(type) { default: spew.Dump(dcl) case *ast.GenDecl: spew.Dump(dcl.Tok) case *ast.FuncDecl: spew.Dump(dcl.Name.Name) } } } func addImports(root *ast.File, ctx *sourceContext) { root.Decls = append(root.Decls, ctx.importDecls()...) } func addImport(root *ast.File, path string) { for _, d := range root.Decls { if imp, is := d.(*ast.GenDecl); is && imp.Tok == token.IMPORT { for _, s := range imp.Specs { if s.(*ast.ImportSpec).Path.Value == `"`+filepath.ToSlash(path)+`"` { return // already have one // xxx aliased imports? } } } } root.Decls = append(root.Decls, importFor(importSpec(path))) } func addStubStruct(root *ast.File, iface iface) { root.Decls = append(root.Decls, iface.stubStructDecl()) } func addType(root *ast.File, typ *ast.TypeSpec) { root.Decls = append(root.Decls, typeDecl(typ)) } func addMethod(root *ast.File, iface iface, meth method) { def := meth.definition(iface) root.Decls = append(root.Decls, def) } func addRequestStruct(root *ast.File, meth method) { root.Decls = append(root.Decls, meth.requestStruct()) } func addResponseStruct(root *ast.File, meth method) { root.Decls = append(root.Decls, meth.responseStruct()) } func addEndpointMaker(root *ast.File, ifc iface, meth method) { root.Decls = append(root.Decls, meth.endpointMaker(ifc)) } func addEndpointsStruct(root *ast.File, ifc iface) { root.Decls = append(root.Decls, ifc.endpointsStruct()) } func addHTTPHandler(root *ast.File, ifc iface) { root.Decls = append(root.Decls, ifc.httpHandler()) } func addDecoder(root *ast.File, meth method) { root.Decls = append(root.Decls, meth.decoderFunc()) } func addEncoder(root *ast.File, meth method) { root.Decls = append(root.Decls, meth.encoderFunc()) } golang-github-go-kit-kit-0.10.0/coveralls.bash000077500000000000000000000011051362256312400211310ustar00rootroot00000000000000#!/usr/bin/env bash if ! type -P gover then echo gover missing: go get github.com/modocache/gover exit 1 fi if ! type -P goveralls then echo goveralls missing: go get github.com/mattn/goveralls exit 1 fi if [[ "$COVERALLS_TOKEN" == "" ]] then echo COVERALLS_TOKEN not set exit 1 fi go list ./... | grep -v '/examples/' | cut -d'/' -f 4- | while read d do cd $d go test -covermode count -coverprofile coverage.coverprofile cd - done gover goveralls -coverprofile gover.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN find . -name '*.coverprofile' -delete golang-github-go-kit-kit-0.10.0/docker-compose-integration.yml000066400000000000000000000010511362256312400242530ustar00rootroot00000000000000version: '2' services: etcd: image: quay.io/coreos/etcd ports: - "2379:2379" command: /usr/local/bin/etcd -advertise-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 -listen-client-urls "http://0.0.0.0:2379,http://0.0.0.0:4001" consul: image: progrium/consul ports: - "8500:8500" command: -server -bootstrap zk: image: zookeeper ports: - "2181:2181" eureka: image: springcloud/eureka environment: eureka.server.responseCacheUpdateIntervalMs: 1000 ports: - "8761:8761" golang-github-go-kit-kit-0.10.0/endpoint/000077500000000000000000000000001362256312400201205ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/endpoint/doc.go000066400000000000000000000003231362256312400212120ustar00rootroot00000000000000// Package endpoint defines an abstraction for RPCs. // // Endpoints are a fundamental building block for many Go kit components. // Endpoints are implemented by servers, and called by clients. package endpoint golang-github-go-kit-kit-0.10.0/endpoint/endpoint.go000066400000000000000000000026561362256312400223000ustar00rootroot00000000000000package endpoint import ( "context" ) // Endpoint is the fundamental building block of servers and clients. // It represents a single RPC method. type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error) // Nop is an endpoint that does nothing and returns a nil error. // Useful for tests. func Nop(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil } // Middleware is a chainable behavior modifier for endpoints. type Middleware func(Endpoint) Endpoint // Chain is a helper function for composing middlewares. Requests will // traverse them in the order they're declared. That is, the first middleware // is treated as the outermost middleware. func Chain(outer Middleware, others ...Middleware) Middleware { return func(next Endpoint) Endpoint { for i := len(others) - 1; i >= 0; i-- { // reverse next = others[i](next) } return outer(next) } } // Failer may be implemented by Go kit response types that contain business // logic error details. If Failed returns a non-nil error, the Go kit transport // layer may interpret this as a business logic error, and may encode it // differently than a regular, successful response. // // It's not necessary for your response types to implement Failer, but it may // help for more sophisticated use cases. The addsvc example shows how Failer // should be used by a complete application. type Failer interface { Failed() error } golang-github-go-kit-kit-0.10.0/endpoint/endpoint_example_test.go000066400000000000000000000015171362256312400250450ustar00rootroot00000000000000package endpoint_test import ( "context" "fmt" "github.com/go-kit/kit/endpoint" ) func ExampleChain() { e := endpoint.Chain( annotate("first"), annotate("second"), annotate("third"), )(myEndpoint) if _, err := e(ctx, req); err != nil { panic(err) } // Output: // first pre // second pre // third pre // my endpoint! // third post // second post // first post } var ( ctx = context.Background() req = struct{}{} ) func annotate(s string) endpoint.Middleware { return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { fmt.Println(s, "pre") defer fmt.Println(s, "post") return next(ctx, request) } } } func myEndpoint(context.Context, interface{}) (interface{}, error) { fmt.Println("my endpoint!") return struct{}{}, nil } golang-github-go-kit-kit-0.10.0/examples/000077500000000000000000000000001362256312400201165ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/README.md000066400000000000000000000002371362256312400213770ustar00rootroot00000000000000# Examples For more information about these examples, including a walkthrough of the stringsvc example, see [gokit.io/examples](https://gokit.io/examples). golang-github-go-kit-kit-0.10.0/examples/addsvc/000077500000000000000000000000001362256312400213625ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/README.md000066400000000000000000000017641362256312400226510ustar00rootroot00000000000000# addsvc addsvc is an example microservice which takes full advantage of most of Go kit's features, including both service- and transport-level middlewares, speaking multiple transports simultaneously, distributed tracing, and rich error definitions. The server binary is available in cmd/addsvc. The client binary is available in cmd/addcli. Finally, the addtransport package provides both server and clients for each supported transport. The client structs bake-in certain middlewares, in order to demonstrate the _client library pattern_. But beware: client libraries are generally a bad idea, because they easily lead to the [distributed monolith antipattern](https://www.microservices.com/talks/dont-build-a-distributed-monolith/). If you don't _know_ you need to use one in your organization, it's probably best avoided: prefer moving that logic to consumers, and relying on [contract testing](https://docs.pact.io/best_practices/contract_tests_not_functional_tests.html) to detect incompatibilities. golang-github-go-kit-kit-0.10.0/examples/addsvc/cmd/000077500000000000000000000000001362256312400221255ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/cmd/addcli/000077500000000000000000000000001362256312400233455ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/cmd/addcli/addcli.go000066400000000000000000000162501362256312400251200ustar00rootroot00000000000000package main import ( "context" "flag" "fmt" "os" "strconv" "text/tabwriter" "time" "google.golang.org/grpc" "github.com/apache/thrift/lib/go/thrift" lightstep "github.com/lightstep/lightstep-tracer-go" stdopentracing "github.com/opentracing/opentracing-go" zipkinot "github.com/openzipkin-contrib/zipkin-go-opentracing" zipkin "github.com/openzipkin/zipkin-go" zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http" "sourcegraph.com/sourcegraph/appdash" appdashot "sourcegraph.com/sourcegraph/appdash/opentracing" "github.com/go-kit/kit/log" "github.com/go-kit/kit/examples/addsvc/pkg/addservice" "github.com/go-kit/kit/examples/addsvc/pkg/addtransport" addthrift "github.com/go-kit/kit/examples/addsvc/thrift/gen-go/addsvc" ) func main() { // The addcli presumes no service discovery system, and expects users to // provide the direct address of an addsvc. This presumption is reflected in // the addcli binary and the client packages: the -transport.addr flags // and various client constructors both expect host:port strings. For an // example service with a client built on top of a service discovery system, // see profilesvc. fs := flag.NewFlagSet("addcli", flag.ExitOnError) var ( httpAddr = fs.String("http-addr", "", "HTTP address of addsvc") grpcAddr = fs.String("grpc-addr", "", "gRPC address of addsvc") thriftAddr = fs.String("thrift-addr", "", "Thrift address of addsvc") jsonRPCAddr = fs.String("jsonrpc-addr", "", "JSON RPC address of addsvc") thriftProtocol = fs.String("thrift-protocol", "binary", "binary, compact, json, simplejson") thriftBuffer = fs.Int("thrift-buffer", 0, "0 for unbuffered") thriftFramed = fs.Bool("thrift-framed", false, "true to enable framing") zipkinURL = fs.String("zipkin-url", "", "Enable Zipkin tracing via HTTP reporter URL e.g. http://localhost:9411/api/v2/spans") zipkinBridge = fs.Bool("zipkin-ot-bridge", false, "Use Zipkin OpenTracing bridge instead of native implementation") lightstepToken = fs.String("lightstep-token", "", "Enable LightStep tracing via a LightStep access token") appdashAddr = fs.String("appdash-addr", "", "Enable Appdash tracing via an Appdash server host:port") method = fs.String("method", "sum", "sum, concat") ) fs.Usage = usageFor(fs, os.Args[0]+" [flags] ") fs.Parse(os.Args[1:]) if len(fs.Args()) != 2 { fs.Usage() os.Exit(1) } // This is a demonstration of the native Zipkin tracing client. If using // Zipkin this is the more idiomatic client over OpenTracing. var zipkinTracer *zipkin.Tracer { if *zipkinURL != "" { var ( err error hostPort = "" // if host:port is unknown we can keep this empty serviceName = "addsvc-cli" reporter = zipkinhttp.NewReporter(*zipkinURL) ) defer reporter.Close() zEP, _ := zipkin.NewEndpoint(serviceName, hostPort) zipkinTracer, err = zipkin.NewTracer(reporter, zipkin.WithLocalEndpoint(zEP)) if err != nil { fmt.Fprintf(os.Stderr, "unable to create zipkin tracer: %s\n", err.Error()) os.Exit(1) } } } // This is a demonstration client, which supports multiple tracers. // Your clients will probably just use one tracer. var otTracer stdopentracing.Tracer { if *zipkinBridge && zipkinTracer != nil { otTracer = zipkinot.Wrap(zipkinTracer) zipkinTracer = nil // do not instrument with both native and ot bridge } else if *lightstepToken != "" { otTracer = lightstep.NewTracer(lightstep.Options{ AccessToken: *lightstepToken, }) defer lightstep.FlushLightStepTracer(otTracer) } else if *appdashAddr != "" { otTracer = appdashot.NewTracer(appdash.NewRemoteCollector(*appdashAddr)) } else { otTracer = stdopentracing.GlobalTracer() // no-op } } // This is a demonstration client, which supports multiple transports. // Your clients will probably just define and stick with 1 transport. var ( svc addservice.Service err error ) if *httpAddr != "" { svc, err = addtransport.NewHTTPClient(*httpAddr, otTracer, zipkinTracer, log.NewNopLogger()) } else if *grpcAddr != "" { conn, err := grpc.Dial(*grpcAddr, grpc.WithInsecure(), grpc.WithTimeout(time.Second)) if err != nil { fmt.Fprintf(os.Stderr, "error: %v", err) os.Exit(1) } defer conn.Close() svc = addtransport.NewGRPCClient(conn, otTracer, zipkinTracer, log.NewNopLogger()) } else if *jsonRPCAddr != "" { svc, err = addtransport.NewJSONRPCClient(*jsonRPCAddr, otTracer, log.NewNopLogger()) } else if *thriftAddr != "" { // It's necessary to do all of this construction in the func main, // because (among other reasons) we need to control the lifecycle of the // Thrift transport, i.e. close it eventually. var protocolFactory thrift.TProtocolFactory switch *thriftProtocol { case "compact": protocolFactory = thrift.NewTCompactProtocolFactory() case "simplejson": protocolFactory = thrift.NewTSimpleJSONProtocolFactory() case "json": protocolFactory = thrift.NewTJSONProtocolFactory() case "binary", "": protocolFactory = thrift.NewTBinaryProtocolFactoryDefault() default: fmt.Fprintf(os.Stderr, "error: invalid protocol %q\n", *thriftProtocol) os.Exit(1) } var transportFactory thrift.TTransportFactory if *thriftBuffer > 0 { transportFactory = thrift.NewTBufferedTransportFactory(*thriftBuffer) } else { transportFactory = thrift.NewTTransportFactory() } if *thriftFramed { transportFactory = thrift.NewTFramedTransportFactory(transportFactory) } transportSocket, err := thrift.NewTSocket(*thriftAddr) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } transport, err := transportFactory.GetTransport(transportSocket) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } if err := transport.Open(); err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } defer transport.Close() client := addthrift.NewAddServiceClientFactory(transport, protocolFactory) svc = addtransport.NewThriftClient(client) } else { fmt.Fprintf(os.Stderr, "error: no remote address specified\n") os.Exit(1) } if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } switch *method { case "sum": a, _ := strconv.ParseInt(fs.Args()[0], 10, 64) b, _ := strconv.ParseInt(fs.Args()[1], 10, 64) v, err := svc.Sum(context.Background(), int(a), int(b)) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Fprintf(os.Stdout, "%d + %d = %d\n", a, b, v) case "concat": a := fs.Args()[0] b := fs.Args()[1] v, err := svc.Concat(context.Background(), a, b) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Fprintf(os.Stdout, "%q + %q = %q\n", a, b, v) default: fmt.Fprintf(os.Stderr, "error: invalid method %q\n", *method) os.Exit(1) } } func usageFor(fs *flag.FlagSet, short string) func() { return func() { fmt.Fprintf(os.Stderr, "USAGE\n") fmt.Fprintf(os.Stderr, " %s\n", short) fmt.Fprintf(os.Stderr, "\n") fmt.Fprintf(os.Stderr, "FLAGS\n") w := tabwriter.NewWriter(os.Stderr, 0, 2, 2, ' ', 0) fs.VisitAll(func(f *flag.Flag) { fmt.Fprintf(w, "\t-%s %s\t%s\n", f.Name, f.DefValue, f.Usage) }) w.Flush() fmt.Fprintf(os.Stderr, "\n") } } golang-github-go-kit-kit-0.10.0/examples/addsvc/cmd/addsvc/000077500000000000000000000000001362256312400233715ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/cmd/addsvc/addsvc.go000066400000000000000000000257561362256312400252030ustar00rootroot00000000000000package main import ( "flag" "fmt" "net" "net/http" "os" "os/signal" "syscall" "text/tabwriter" "github.com/apache/thrift/lib/go/thrift" lightstep "github.com/lightstep/lightstep-tracer-go" "github.com/oklog/oklog/pkg/group" stdopentracing "github.com/opentracing/opentracing-go" zipkinot "github.com/openzipkin-contrib/zipkin-go-opentracing" zipkin "github.com/openzipkin/zipkin-go" zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http" stdprometheus "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "google.golang.org/grpc" "sourcegraph.com/sourcegraph/appdash" appdashot "sourcegraph.com/sourcegraph/appdash/opentracing" "github.com/go-kit/kit/log" "github.com/go-kit/kit/metrics" "github.com/go-kit/kit/metrics/prometheus" kitgrpc "github.com/go-kit/kit/transport/grpc" addpb "github.com/go-kit/kit/examples/addsvc/pb" "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint" "github.com/go-kit/kit/examples/addsvc/pkg/addservice" "github.com/go-kit/kit/examples/addsvc/pkg/addtransport" addthrift "github.com/go-kit/kit/examples/addsvc/thrift/gen-go/addsvc" ) func main() { // Define our flags. Your service probably won't need to bind listeners for // *all* supported transports, or support both Zipkin and LightStep, and so // on, but we do it here for demonstration purposes. fs := flag.NewFlagSet("addsvc", flag.ExitOnError) var ( debugAddr = fs.String("debug.addr", ":8080", "Debug and metrics listen address") httpAddr = fs.String("http-addr", ":8081", "HTTP listen address") grpcAddr = fs.String("grpc-addr", ":8082", "gRPC listen address") thriftAddr = fs.String("thrift-addr", ":8083", "Thrift listen address") jsonRPCAddr = fs.String("jsonrpc-addr", ":8084", "JSON RPC listen address") thriftProtocol = fs.String("thrift-protocol", "binary", "binary, compact, json, simplejson") thriftBuffer = fs.Int("thrift-buffer", 0, "0 for unbuffered") thriftFramed = fs.Bool("thrift-framed", false, "true to enable framing") zipkinURL = fs.String("zipkin-url", "", "Enable Zipkin tracing via HTTP reporter URL e.g. http://localhost:9411/api/v2/spans") zipkinBridge = fs.Bool("zipkin-ot-bridge", false, "Use Zipkin OpenTracing bridge instead of native implementation") lightstepToken = fs.String("lightstep-token", "", "Enable LightStep tracing via a LightStep access token") appdashAddr = fs.String("appdash-addr", "", "Enable Appdash tracing via an Appdash server host:port") ) fs.Usage = usageFor(fs, os.Args[0]+" [flags]") fs.Parse(os.Args[1:]) // Create a single logger, which we'll use and give to other components. var logger log.Logger { logger = log.NewLogfmtLogger(os.Stderr) logger = log.With(logger, "ts", log.DefaultTimestampUTC) logger = log.With(logger, "caller", log.DefaultCaller) } var zipkinTracer *zipkin.Tracer { if *zipkinURL != "" { var ( err error hostPort = "localhost:80" serviceName = "addsvc" reporter = zipkinhttp.NewReporter(*zipkinURL) ) defer reporter.Close() zEP, _ := zipkin.NewEndpoint(serviceName, hostPort) zipkinTracer, err = zipkin.NewTracer(reporter, zipkin.WithLocalEndpoint(zEP)) if err != nil { logger.Log("err", err) os.Exit(1) } if !(*zipkinBridge) { logger.Log("tracer", "Zipkin", "type", "Native", "URL", *zipkinURL) } } } // Determine which OpenTracing tracer to use. We'll pass the tracer to all the // components that use it, as a dependency. var tracer stdopentracing.Tracer { if *zipkinBridge && zipkinTracer != nil { logger.Log("tracer", "Zipkin", "type", "OpenTracing", "URL", *zipkinURL) tracer = zipkinot.Wrap(zipkinTracer) zipkinTracer = nil // do not instrument with both native tracer and opentracing bridge } else if *lightstepToken != "" { logger.Log("tracer", "LightStep") // probably don't want to print out the token :) tracer = lightstep.NewTracer(lightstep.Options{ AccessToken: *lightstepToken, }) defer lightstep.FlushLightStepTracer(tracer) } else if *appdashAddr != "" { logger.Log("tracer", "Appdash", "addr", *appdashAddr) tracer = appdashot.NewTracer(appdash.NewRemoteCollector(*appdashAddr)) } else { tracer = stdopentracing.GlobalTracer() // no-op } } // Create the (sparse) metrics we'll use in the service. They, too, are // dependencies that we pass to components that use them. var ints, chars metrics.Counter { // Business-level metrics. ints = prometheus.NewCounterFrom(stdprometheus.CounterOpts{ Namespace: "example", Subsystem: "addsvc", Name: "integers_summed", Help: "Total count of integers summed via the Sum method.", }, []string{}) chars = prometheus.NewCounterFrom(stdprometheus.CounterOpts{ Namespace: "example", Subsystem: "addsvc", Name: "characters_concatenated", Help: "Total count of characters concatenated via the Concat method.", }, []string{}) } var duration metrics.Histogram { // Endpoint-level metrics. duration = prometheus.NewSummaryFrom(stdprometheus.SummaryOpts{ Namespace: "example", Subsystem: "addsvc", Name: "request_duration_seconds", Help: "Request duration in seconds.", }, []string{"method", "success"}) } http.DefaultServeMux.Handle("/metrics", promhttp.Handler()) // Build the layers of the service "onion" from the inside out. First, the // business logic service; then, the set of endpoints that wrap the service; // and finally, a series of concrete transport adapters. The adapters, like // the HTTP handler or the gRPC server, are the bridge between Go kit and // the interfaces that the transports expect. Note that we're not binding // them to ports or anything yet; we'll do that next. var ( service = addservice.New(logger, ints, chars) endpoints = addendpoint.New(service, logger, duration, tracer, zipkinTracer) httpHandler = addtransport.NewHTTPHandler(endpoints, tracer, zipkinTracer, logger) grpcServer = addtransport.NewGRPCServer(endpoints, tracer, zipkinTracer, logger) thriftServer = addtransport.NewThriftServer(endpoints) jsonrpcHandler = addtransport.NewJSONRPCHandler(endpoints, logger) ) // Now we're to the part of the func main where we want to start actually // running things, like servers bound to listeners to receive connections. // // The method is the same for each component: add a new actor to the group // struct, which is a combination of 2 anonymous functions: the first // function actually runs the component, and the second function should // interrupt the first function and cause it to return. It's in these // functions that we actually bind the Go kit server/handler structs to the // concrete transports and run them. // // Putting each component into its own block is mostly for aesthetics: it // clearly demarcates the scope in which each listener/socket may be used. var g group.Group { // The debug listener mounts the http.DefaultServeMux, and serves up // stuff like the Prometheus metrics route, the Go debug and profiling // routes, and so on. debugListener, err := net.Listen("tcp", *debugAddr) if err != nil { logger.Log("transport", "debug/HTTP", "during", "Listen", "err", err) os.Exit(1) } g.Add(func() error { logger.Log("transport", "debug/HTTP", "addr", *debugAddr) return http.Serve(debugListener, http.DefaultServeMux) }, func(error) { debugListener.Close() }) } { // The HTTP listener mounts the Go kit HTTP handler we created. httpListener, err := net.Listen("tcp", *httpAddr) if err != nil { logger.Log("transport", "HTTP", "during", "Listen", "err", err) os.Exit(1) } g.Add(func() error { logger.Log("transport", "HTTP", "addr", *httpAddr) return http.Serve(httpListener, httpHandler) }, func(error) { httpListener.Close() }) } { // The gRPC listener mounts the Go kit gRPC server we created. grpcListener, err := net.Listen("tcp", *grpcAddr) if err != nil { logger.Log("transport", "gRPC", "during", "Listen", "err", err) os.Exit(1) } g.Add(func() error { logger.Log("transport", "gRPC", "addr", *grpcAddr) // we add the Go Kit gRPC Interceptor to our gRPC service as it is used by // the here demonstrated zipkin tracing middleware. baseServer := grpc.NewServer(grpc.UnaryInterceptor(kitgrpc.Interceptor)) addpb.RegisterAddServer(baseServer, grpcServer) return baseServer.Serve(grpcListener) }, func(error) { grpcListener.Close() }) } { // The Thrift socket mounts the Go kit Thrift server we created earlier. // There's a lot of boilerplate involved here, related to configuring // the protocol and transport; blame Thrift. thriftSocket, err := thrift.NewTServerSocket(*thriftAddr) if err != nil { logger.Log("transport", "Thrift", "during", "Listen", "err", err) os.Exit(1) } g.Add(func() error { logger.Log("transport", "Thrift", "addr", *thriftAddr) var protocolFactory thrift.TProtocolFactory switch *thriftProtocol { case "binary": protocolFactory = thrift.NewTBinaryProtocolFactoryDefault() case "compact": protocolFactory = thrift.NewTCompactProtocolFactory() case "json": protocolFactory = thrift.NewTJSONProtocolFactory() case "simplejson": protocolFactory = thrift.NewTSimpleJSONProtocolFactory() default: return fmt.Errorf("invalid Thrift protocol %q", *thriftProtocol) } var transportFactory thrift.TTransportFactory if *thriftBuffer > 0 { transportFactory = thrift.NewTBufferedTransportFactory(*thriftBuffer) } else { transportFactory = thrift.NewTTransportFactory() } if *thriftFramed { transportFactory = thrift.NewTFramedTransportFactory(transportFactory) } return thrift.NewTSimpleServer4( addthrift.NewAddServiceProcessor(thriftServer), thriftSocket, transportFactory, protocolFactory, ).Serve() }, func(error) { thriftSocket.Close() }) } { httpListener, err := net.Listen("tcp", *jsonRPCAddr) if err != nil { logger.Log("transport", "JSONRPC over HTTP", "during", "Listen", "err", err) os.Exit(1) } g.Add(func() error { logger.Log("transport", "JSONRPC over HTTP", "addr", *jsonRPCAddr) return http.Serve(httpListener, jsonrpcHandler) }, func(error) { httpListener.Close() }) } { // This function just sits and waits for ctrl-C. cancelInterrupt := make(chan struct{}) g.Add(func() error { c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) select { case sig := <-c: return fmt.Errorf("received signal %s", sig) case <-cancelInterrupt: return nil } }, func(error) { close(cancelInterrupt) }) } logger.Log("exit", g.Run()) } func usageFor(fs *flag.FlagSet, short string) func() { return func() { fmt.Fprintf(os.Stderr, "USAGE\n") fmt.Fprintf(os.Stderr, " %s\n", short) fmt.Fprintf(os.Stderr, "\n") fmt.Fprintf(os.Stderr, "FLAGS\n") w := tabwriter.NewWriter(os.Stderr, 0, 2, 2, ' ', 0) fs.VisitAll(func(f *flag.Flag) { fmt.Fprintf(w, "\t-%s %s\t%s\n", f.Name, f.DefValue, f.Usage) }) w.Flush() fmt.Fprintf(os.Stderr, "\n") } } golang-github-go-kit-kit-0.10.0/examples/addsvc/cmd/addsvc/pact_test.go000066400000000000000000000023521362256312400257100ustar00rootroot00000000000000package main import ( "fmt" "net/http" "os" "strings" "testing" "github.com/pact-foundation/pact-go/dsl" ) func TestPactStringsvcUppercase(t *testing.T) { if os.Getenv("WRITE_PACTS") == "" { t.Skip("skipping Pact contracts; set WRITE_PACTS environment variable to enable") } pact := dsl.Pact{ Consumer: "addsvc", Provider: "stringsvc", } defer pact.Teardown() pact.AddInteraction(). UponReceiving("stringsvc uppercase"). WithRequest(dsl.Request{ Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/json; charset=utf-8")}, Method: "POST", Path: dsl.String("/uppercase"), Body: `{"s":"foo"}`, }). WillRespondWith(dsl.Response{ Status: 200, Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/json; charset=utf-8")}, Body: `{"v":"FOO"}`, }) if err := pact.Verify(func() error { u := fmt.Sprintf("http://localhost:%d/uppercase", pact.Server.Port) req, err := http.NewRequest("POST", u, strings.NewReader(`{"s":"foo"}`)) if err != nil { return err } req.Header.Set("Content-Type", "application/json; charset=utf-8") if _, err = http.DefaultClient.Do(req); err != nil { return err } return nil }); err != nil { t.Fatal(err) } pact.WritePact() } golang-github-go-kit-kit-0.10.0/examples/addsvc/cmd/addsvc/wiring_test.go000066400000000000000000000026121362256312400262570ustar00rootroot00000000000000package main import ( "io/ioutil" "net/http" "net/http/httptest" "strings" "testing" "github.com/opentracing/opentracing-go" zipkin "github.com/openzipkin/zipkin-go" "github.com/go-kit/kit/log" "github.com/go-kit/kit/metrics/discard" "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint" "github.com/go-kit/kit/examples/addsvc/pkg/addservice" "github.com/go-kit/kit/examples/addsvc/pkg/addtransport" ) func TestHTTP(t *testing.T) { zkt, _ := zipkin.NewTracer(nil, zipkin.WithNoopTracer(true)) svc := addservice.New(log.NewNopLogger(), discard.NewCounter(), discard.NewCounter()) eps := addendpoint.New(svc, log.NewNopLogger(), discard.NewHistogram(), opentracing.GlobalTracer(), zkt) mux := addtransport.NewHTTPHandler(eps, opentracing.GlobalTracer(), zkt, log.NewNopLogger()) srv := httptest.NewServer(mux) defer srv.Close() for _, testcase := range []struct { method, url, body, want string }{ {"GET", srv.URL + "/concat", `{"a":"1","b":"2"}`, `{"v":"12"}`}, {"GET", srv.URL + "/sum", `{"a":1,"b":2}`, `{"v":3}`}, } { req, _ := http.NewRequest(testcase.method, testcase.url, strings.NewReader(testcase.body)) resp, _ := http.DefaultClient.Do(req) body, _ := ioutil.ReadAll(resp.Body) if want, have := testcase.want, strings.TrimSpace(string(body)); want != have { t.Errorf("%s %s %s: want %q, have %q", testcase.method, testcase.url, testcase.body, want, have) } } } golang-github-go-kit-kit-0.10.0/examples/addsvc/pb/000077500000000000000000000000001362256312400217635ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/pb/addsvc.pb.go000066400000000000000000000255761362256312400241750ustar00rootroot00000000000000// Code generated by protoc-gen-go. DO NOT EDIT. // source: addsvc.proto package pb import ( context "context" fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" math "math" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package // The sum request contains two parameters. type SumRequest struct { A int64 `protobuf:"varint,1,opt,name=a,proto3" json:"a,omitempty"` B int64 `protobuf:"varint,2,opt,name=b,proto3" json:"b,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *SumRequest) Reset() { *m = SumRequest{} } func (m *SumRequest) String() string { return proto.CompactTextString(m) } func (*SumRequest) ProtoMessage() {} func (*SumRequest) Descriptor() ([]byte, []int) { return fileDescriptor_174367f558d60c26, []int{0} } func (m *SumRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SumRequest.Unmarshal(m, b) } func (m *SumRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SumRequest.Marshal(b, m, deterministic) } func (m *SumRequest) XXX_Merge(src proto.Message) { xxx_messageInfo_SumRequest.Merge(m, src) } func (m *SumRequest) XXX_Size() int { return xxx_messageInfo_SumRequest.Size(m) } func (m *SumRequest) XXX_DiscardUnknown() { xxx_messageInfo_SumRequest.DiscardUnknown(m) } var xxx_messageInfo_SumRequest proto.InternalMessageInfo func (m *SumRequest) GetA() int64 { if m != nil { return m.A } return 0 } func (m *SumRequest) GetB() int64 { if m != nil { return m.B } return 0 } // The sum response contains the result of the calculation. type SumReply struct { V int64 `protobuf:"varint,1,opt,name=v,proto3" json:"v,omitempty"` Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *SumReply) Reset() { *m = SumReply{} } func (m *SumReply) String() string { return proto.CompactTextString(m) } func (*SumReply) ProtoMessage() {} func (*SumReply) Descriptor() ([]byte, []int) { return fileDescriptor_174367f558d60c26, []int{1} } func (m *SumReply) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SumReply.Unmarshal(m, b) } func (m *SumReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SumReply.Marshal(b, m, deterministic) } func (m *SumReply) XXX_Merge(src proto.Message) { xxx_messageInfo_SumReply.Merge(m, src) } func (m *SumReply) XXX_Size() int { return xxx_messageInfo_SumReply.Size(m) } func (m *SumReply) XXX_DiscardUnknown() { xxx_messageInfo_SumReply.DiscardUnknown(m) } var xxx_messageInfo_SumReply proto.InternalMessageInfo func (m *SumReply) GetV() int64 { if m != nil { return m.V } return 0 } func (m *SumReply) GetErr() string { if m != nil { return m.Err } return "" } // The Concat request contains two parameters. type ConcatRequest struct { A string `protobuf:"bytes,1,opt,name=a,proto3" json:"a,omitempty"` B string `protobuf:"bytes,2,opt,name=b,proto3" json:"b,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *ConcatRequest) Reset() { *m = ConcatRequest{} } func (m *ConcatRequest) String() string { return proto.CompactTextString(m) } func (*ConcatRequest) ProtoMessage() {} func (*ConcatRequest) Descriptor() ([]byte, []int) { return fileDescriptor_174367f558d60c26, []int{2} } func (m *ConcatRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConcatRequest.Unmarshal(m, b) } func (m *ConcatRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ConcatRequest.Marshal(b, m, deterministic) } func (m *ConcatRequest) XXX_Merge(src proto.Message) { xxx_messageInfo_ConcatRequest.Merge(m, src) } func (m *ConcatRequest) XXX_Size() int { return xxx_messageInfo_ConcatRequest.Size(m) } func (m *ConcatRequest) XXX_DiscardUnknown() { xxx_messageInfo_ConcatRequest.DiscardUnknown(m) } var xxx_messageInfo_ConcatRequest proto.InternalMessageInfo func (m *ConcatRequest) GetA() string { if m != nil { return m.A } return "" } func (m *ConcatRequest) GetB() string { if m != nil { return m.B } return "" } // The Concat response contains the result of the concatenation. type ConcatReply struct { V string `protobuf:"bytes,1,opt,name=v,proto3" json:"v,omitempty"` Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *ConcatReply) Reset() { *m = ConcatReply{} } func (m *ConcatReply) String() string { return proto.CompactTextString(m) } func (*ConcatReply) ProtoMessage() {} func (*ConcatReply) Descriptor() ([]byte, []int) { return fileDescriptor_174367f558d60c26, []int{3} } func (m *ConcatReply) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConcatReply.Unmarshal(m, b) } func (m *ConcatReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ConcatReply.Marshal(b, m, deterministic) } func (m *ConcatReply) XXX_Merge(src proto.Message) { xxx_messageInfo_ConcatReply.Merge(m, src) } func (m *ConcatReply) XXX_Size() int { return xxx_messageInfo_ConcatReply.Size(m) } func (m *ConcatReply) XXX_DiscardUnknown() { xxx_messageInfo_ConcatReply.DiscardUnknown(m) } var xxx_messageInfo_ConcatReply proto.InternalMessageInfo func (m *ConcatReply) GetV() string { if m != nil { return m.V } return "" } func (m *ConcatReply) GetErr() string { if m != nil { return m.Err } return "" } func init() { proto.RegisterType((*SumRequest)(nil), "pb.SumRequest") proto.RegisterType((*SumReply)(nil), "pb.SumReply") proto.RegisterType((*ConcatRequest)(nil), "pb.ConcatRequest") proto.RegisterType((*ConcatReply)(nil), "pb.ConcatReply") } func init() { proto.RegisterFile("addsvc.proto", fileDescriptor_174367f558d60c26) } var fileDescriptor_174367f558d60c26 = []byte{ // 189 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x49, 0x4c, 0x49, 0x29, 0x2e, 0x4b, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2a, 0x48, 0x52, 0xd2, 0xe0, 0xe2, 0x0a, 0x2e, 0xcd, 0x0d, 0x4a, 0x2d, 0x2c, 0x4d, 0x2d, 0x2e, 0x11, 0xe2, 0xe1, 0x62, 0x4c, 0x94, 0x60, 0x54, 0x60, 0xd4, 0x60, 0x0e, 0x62, 0x4c, 0x04, 0xf1, 0x92, 0x24, 0x98, 0x20, 0xbc, 0x24, 0x25, 0x2d, 0x2e, 0x0e, 0xb0, 0xca, 0x82, 0x9c, 0x4a, 0x90, 0x4c, 0x19, 0x4c, 0x5d, 0x99, 0x90, 0x00, 0x17, 0x73, 0x6a, 0x51, 0x11, 0x58, 0x25, 0x67, 0x10, 0x88, 0xa9, 0xa4, 0xcd, 0xc5, 0xeb, 0x9c, 0x9f, 0x97, 0x9c, 0x58, 0x82, 0x61, 0x30, 0x27, 0x8a, 0xc1, 0x9c, 0x20, 0x83, 0x75, 0xb9, 0xb8, 0x61, 0x8a, 0x51, 0xcc, 0xe6, 0xc4, 0x6a, 0xb6, 0x51, 0x0c, 0x17, 0xb3, 0x63, 0x4a, 0x8a, 0x90, 0x2a, 0x17, 0x73, 0x70, 0x69, 0xae, 0x10, 0x9f, 0x5e, 0x41, 0x92, 0x1e, 0xc2, 0x07, 0x52, 0x3c, 0x70, 0x7e, 0x41, 0x4e, 0xa5, 0x12, 0x83, 0x90, 0x1e, 0x17, 0x1b, 0xc4, 0x70, 0x21, 0x41, 0x90, 0x0c, 0x8a, 0xab, 0xa4, 0xf8, 0x91, 0x85, 0xc0, 0xea, 0x93, 0xd8, 0xc0, 0x41, 0x63, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xdc, 0x37, 0x81, 0x99, 0x2a, 0x01, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. var _ context.Context var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 // AddClient is the client API for Add service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type AddClient interface { // Sums two integers. Sum(ctx context.Context, in *SumRequest, opts ...grpc.CallOption) (*SumReply, error) // Concatenates two strings Concat(ctx context.Context, in *ConcatRequest, opts ...grpc.CallOption) (*ConcatReply, error) } type addClient struct { cc *grpc.ClientConn } func NewAddClient(cc *grpc.ClientConn) AddClient { return &addClient{cc} } func (c *addClient) Sum(ctx context.Context, in *SumRequest, opts ...grpc.CallOption) (*SumReply, error) { out := new(SumReply) err := c.cc.Invoke(ctx, "/pb.Add/Sum", in, out, opts...) if err != nil { return nil, err } return out, nil } func (c *addClient) Concat(ctx context.Context, in *ConcatRequest, opts ...grpc.CallOption) (*ConcatReply, error) { out := new(ConcatReply) err := c.cc.Invoke(ctx, "/pb.Add/Concat", in, out, opts...) if err != nil { return nil, err } return out, nil } // AddServer is the server API for Add service. type AddServer interface { // Sums two integers. Sum(context.Context, *SumRequest) (*SumReply, error) // Concatenates two strings Concat(context.Context, *ConcatRequest) (*ConcatReply, error) } func RegisterAddServer(s *grpc.Server, srv AddServer) { s.RegisterService(&_Add_serviceDesc, srv) } func _Add_Sum_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(SumRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(AddServer).Sum(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: "/pb.Add/Sum", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(AddServer).Sum(ctx, req.(*SumRequest)) } return interceptor(ctx, in, info, handler) } func _Add_Concat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ConcatRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(AddServer).Concat(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: "/pb.Add/Concat", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(AddServer).Concat(ctx, req.(*ConcatRequest)) } return interceptor(ctx, in, info, handler) } var _Add_serviceDesc = grpc.ServiceDesc{ ServiceName: "pb.Add", HandlerType: (*AddServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "Sum", Handler: _Add_Sum_Handler, }, { MethodName: "Concat", Handler: _Add_Concat_Handler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "addsvc.proto", } golang-github-go-kit-kit-0.10.0/examples/addsvc/pb/addsvc.proto000066400000000000000000000012451362256312400243160ustar00rootroot00000000000000syntax = "proto3"; package pb; // The Add service definition. service Add { // Sums two integers. rpc Sum (SumRequest) returns (SumReply) {} // Concatenates two strings rpc Concat (ConcatRequest) returns (ConcatReply) {} } // The sum request contains two parameters. message SumRequest { int64 a = 1; int64 b = 2; } // The sum response contains the result of the calculation. message SumReply { int64 v = 1; string err = 2; } // The Concat request contains two parameters. message ConcatRequest { string a = 1; string b = 2; } // The Concat response contains the result of the concatenation. message ConcatReply { string v = 1; string err = 2; } golang-github-go-kit-kit-0.10.0/examples/addsvc/pb/compile.sh000077500000000000000000000006201362256312400237500ustar00rootroot00000000000000#!/usr/bin/env sh # Install proto3 from source # brew install autoconf automake libtool # git clone https://github.com/google/protobuf # ./autogen.sh ; ./configure ; make ; make install # # Update protoc Go bindings via # go get -u github.com/golang/protobuf/{proto,protoc-gen-go} # # See also # https://github.com/grpc/grpc-go/tree/master/examples protoc addsvc.proto --go_out=plugins=grpc:. golang-github-go-kit-kit-0.10.0/examples/addsvc/pkg/000077500000000000000000000000001362256312400221435ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/pkg/addendpoint/000077500000000000000000000000001362256312400244345ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/pkg/addendpoint/middleware.go000066400000000000000000000024411362256312400271010ustar00rootroot00000000000000package addendpoint import ( "context" "fmt" "time" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/log" "github.com/go-kit/kit/metrics" ) // InstrumentingMiddleware returns an endpoint middleware that records // the duration of each invocation to the passed histogram. The middleware adds // a single field: "success", which is "true" if no error is returned, and // "false" otherwise. func InstrumentingMiddleware(duration metrics.Histogram) endpoint.Middleware { return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { defer func(begin time.Time) { duration.With("success", fmt.Sprint(err == nil)).Observe(time.Since(begin).Seconds()) }(time.Now()) return next(ctx, request) } } } // LoggingMiddleware returns an endpoint middleware that logs the // duration of each invocation, and the resulting error, if any. func LoggingMiddleware(logger log.Logger) endpoint.Middleware { return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { defer func(begin time.Time) { logger.Log("transport_error", err, "took", time.Since(begin)) }(time.Now()) return next(ctx, request) } } } golang-github-go-kit-kit-0.10.0/examples/addsvc/pkg/addendpoint/set.go000066400000000000000000000117111362256312400255570ustar00rootroot00000000000000package addendpoint import ( "context" "time" "golang.org/x/time/rate" stdopentracing "github.com/opentracing/opentracing-go" stdzipkin "github.com/openzipkin/zipkin-go" "github.com/sony/gobreaker" "github.com/go-kit/kit/circuitbreaker" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/log" "github.com/go-kit/kit/metrics" "github.com/go-kit/kit/ratelimit" "github.com/go-kit/kit/tracing/opentracing" "github.com/go-kit/kit/tracing/zipkin" "github.com/go-kit/kit/examples/addsvc/pkg/addservice" ) // Set collects all of the endpoints that compose an add service. It's meant to // be used as a helper struct, to collect all of the endpoints into a single // parameter. type Set struct { SumEndpoint endpoint.Endpoint ConcatEndpoint endpoint.Endpoint } // New returns a Set that wraps the provided server, and wires in all of the // expected endpoint middlewares via the various parameters. func New(svc addservice.Service, logger log.Logger, duration metrics.Histogram, otTracer stdopentracing.Tracer, zipkinTracer *stdzipkin.Tracer) Set { var sumEndpoint endpoint.Endpoint { sumEndpoint = MakeSumEndpoint(svc) // Sum is limited to 1 request per second with burst of 1 request. // Note, rate is defined as a time interval between requests. sumEndpoint = ratelimit.NewErroringLimiter(rate.NewLimiter(rate.Every(time.Second), 1))(sumEndpoint) sumEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{}))(sumEndpoint) sumEndpoint = opentracing.TraceServer(otTracer, "Sum")(sumEndpoint) if zipkinTracer != nil { sumEndpoint = zipkin.TraceEndpoint(zipkinTracer, "Sum")(sumEndpoint) } sumEndpoint = LoggingMiddleware(log.With(logger, "method", "Sum"))(sumEndpoint) sumEndpoint = InstrumentingMiddleware(duration.With("method", "Sum"))(sumEndpoint) } var concatEndpoint endpoint.Endpoint { concatEndpoint = MakeConcatEndpoint(svc) // Concat is limited to 1 request per second with burst of 100 requests. // Note, rate is defined as a number of requests per second. concatEndpoint = ratelimit.NewErroringLimiter(rate.NewLimiter(rate.Limit(1), 100))(concatEndpoint) concatEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{}))(concatEndpoint) concatEndpoint = opentracing.TraceServer(otTracer, "Concat")(concatEndpoint) if zipkinTracer != nil { concatEndpoint = zipkin.TraceEndpoint(zipkinTracer, "Concat")(concatEndpoint) } concatEndpoint = LoggingMiddleware(log.With(logger, "method", "Concat"))(concatEndpoint) concatEndpoint = InstrumentingMiddleware(duration.With("method", "Concat"))(concatEndpoint) } return Set{ SumEndpoint: sumEndpoint, ConcatEndpoint: concatEndpoint, } } // Sum implements the service interface, so Set may be used as a service. // This is primarily useful in the context of a client library. func (s Set) Sum(ctx context.Context, a, b int) (int, error) { resp, err := s.SumEndpoint(ctx, SumRequest{A: a, B: b}) if err != nil { return 0, err } response := resp.(SumResponse) return response.V, response.Err } // Concat implements the service interface, so Set may be used as a // service. This is primarily useful in the context of a client library. func (s Set) Concat(ctx context.Context, a, b string) (string, error) { resp, err := s.ConcatEndpoint(ctx, ConcatRequest{A: a, B: b}) if err != nil { return "", err } response := resp.(ConcatResponse) return response.V, response.Err } // MakeSumEndpoint constructs a Sum endpoint wrapping the service. func MakeSumEndpoint(s addservice.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { req := request.(SumRequest) v, err := s.Sum(ctx, req.A, req.B) return SumResponse{V: v, Err: err}, nil } } // MakeConcatEndpoint constructs a Concat endpoint wrapping the service. func MakeConcatEndpoint(s addservice.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { req := request.(ConcatRequest) v, err := s.Concat(ctx, req.A, req.B) return ConcatResponse{V: v, Err: err}, nil } } // compile time assertions for our response types implementing endpoint.Failer. var ( _ endpoint.Failer = SumResponse{} _ endpoint.Failer = ConcatResponse{} ) // SumRequest collects the request parameters for the Sum method. type SumRequest struct { A, B int } // SumResponse collects the response values for the Sum method. type SumResponse struct { V int `json:"v"` Err error `json:"-"` // should be intercepted by Failed/errorEncoder } // Failed implements endpoint.Failer. func (r SumResponse) Failed() error { return r.Err } // ConcatRequest collects the request parameters for the Concat method. type ConcatRequest struct { A, B string } // ConcatResponse collects the response values for the Concat method. type ConcatResponse struct { V string `json:"v"` Err error `json:"-"` } // Failed implements endpoint.Failer. func (r ConcatResponse) Failed() error { return r.Err } golang-github-go-kit-kit-0.10.0/examples/addsvc/pkg/addservice/000077500000000000000000000000001362256312400242545ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/pkg/addservice/middleware.go000066400000000000000000000033361362256312400267250ustar00rootroot00000000000000package addservice import ( "context" "github.com/go-kit/kit/log" "github.com/go-kit/kit/metrics" ) // Middleware describes a service (as opposed to endpoint) middleware. type Middleware func(Service) Service // LoggingMiddleware takes a logger as a dependency // and returns a service Middleware. func LoggingMiddleware(logger log.Logger) Middleware { return func(next Service) Service { return loggingMiddleware{logger, next} } } type loggingMiddleware struct { logger log.Logger next Service } func (mw loggingMiddleware) Sum(ctx context.Context, a, b int) (v int, err error) { defer func() { mw.logger.Log("method", "Sum", "a", a, "b", b, "v", v, "err", err) }() return mw.next.Sum(ctx, a, b) } func (mw loggingMiddleware) Concat(ctx context.Context, a, b string) (v string, err error) { defer func() { mw.logger.Log("method", "Concat", "a", a, "b", b, "v", v, "err", err) }() return mw.next.Concat(ctx, a, b) } // InstrumentingMiddleware returns a service middleware that instruments // the number of integers summed and characters concatenated over the lifetime of // the service. func InstrumentingMiddleware(ints, chars metrics.Counter) Middleware { return func(next Service) Service { return instrumentingMiddleware{ ints: ints, chars: chars, next: next, } } } type instrumentingMiddleware struct { ints metrics.Counter chars metrics.Counter next Service } func (mw instrumentingMiddleware) Sum(ctx context.Context, a, b int) (int, error) { v, err := mw.next.Sum(ctx, a, b) mw.ints.Add(float64(v)) return v, err } func (mw instrumentingMiddleware) Concat(ctx context.Context, a, b string) (string, error) { v, err := mw.next.Concat(ctx, a, b) mw.chars.Add(float64(len(v))) return v, err } golang-github-go-kit-kit-0.10.0/examples/addsvc/pkg/addservice/service.go000066400000000000000000000034701362256312400262470ustar00rootroot00000000000000package addservice import ( "context" "errors" "github.com/go-kit/kit/log" "github.com/go-kit/kit/metrics" ) // Service describes a service that adds things together. type Service interface { Sum(ctx context.Context, a, b int) (int, error) Concat(ctx context.Context, a, b string) (string, error) } // New returns a basic Service with all of the expected middlewares wired in. func New(logger log.Logger, ints, chars metrics.Counter) Service { var svc Service { svc = NewBasicService() svc = LoggingMiddleware(logger)(svc) svc = InstrumentingMiddleware(ints, chars)(svc) } return svc } var ( // ErrTwoZeroes is an arbitrary business rule for the Add method. ErrTwoZeroes = errors.New("can't sum two zeroes") // ErrIntOverflow protects the Add method. We've decided that this error // indicates a misbehaving service and should count against e.g. circuit // breakers. So, we return it directly in endpoints, to illustrate the // difference. In a real service, this probably wouldn't be the case. ErrIntOverflow = errors.New("integer overflow") // ErrMaxSizeExceeded protects the Concat method. ErrMaxSizeExceeded = errors.New("result exceeds maximum size") ) // NewBasicService returns a naïve, stateless implementation of Service. func NewBasicService() Service { return basicService{} } type basicService struct{} const ( intMax = 1<<31 - 1 intMin = -(intMax + 1) maxLen = 10 ) func (s basicService) Sum(_ context.Context, a, b int) (int, error) { if a == 0 && b == 0 { return 0, ErrTwoZeroes } if (b > 0 && a > (intMax-b)) || (b < 0 && a < (intMin-b)) { return 0, ErrIntOverflow } return a + b, nil } // Concat implements Service. func (s basicService) Concat(_ context.Context, a, b string) (string, error) { if len(a)+len(b) > maxLen { return "", ErrMaxSizeExceeded } return a + b, nil } golang-github-go-kit-kit-0.10.0/examples/addsvc/pkg/addtransport/000077500000000000000000000000001362256312400246505ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/pkg/addtransport/grpc.go000066400000000000000000000217541362256312400261430ustar00rootroot00000000000000package addtransport import ( "context" "errors" "time" "google.golang.org/grpc" stdopentracing "github.com/opentracing/opentracing-go" stdzipkin "github.com/openzipkin/zipkin-go" "github.com/sony/gobreaker" "golang.org/x/time/rate" "github.com/go-kit/kit/circuitbreaker" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/log" "github.com/go-kit/kit/ratelimit" "github.com/go-kit/kit/tracing/opentracing" "github.com/go-kit/kit/tracing/zipkin" "github.com/go-kit/kit/transport" grpctransport "github.com/go-kit/kit/transport/grpc" "github.com/go-kit/kit/examples/addsvc/pb" "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint" "github.com/go-kit/kit/examples/addsvc/pkg/addservice" ) type grpcServer struct { sum grpctransport.Handler concat grpctransport.Handler } // NewGRPCServer makes a set of endpoints available as a gRPC AddServer. func NewGRPCServer(endpoints addendpoint.Set, otTracer stdopentracing.Tracer, zipkinTracer *stdzipkin.Tracer, logger log.Logger) pb.AddServer { options := []grpctransport.ServerOption{ grpctransport.ServerErrorHandler(transport.NewLogErrorHandler(logger)), } if zipkinTracer != nil { // Zipkin GRPC Server Trace can either be instantiated per gRPC method with a // provided operation name or a global tracing service can be instantiated // without an operation name and fed to each Go kit gRPC server as a // ServerOption. // In the latter case, the operation name will be the endpoint's grpc method // path if used in combination with the Go kit gRPC Interceptor. // // In this example, we demonstrate a global Zipkin tracing service with // Go kit gRPC Interceptor. options = append(options, zipkin.GRPCServerTrace(zipkinTracer)) } return &grpcServer{ sum: grpctransport.NewServer( endpoints.SumEndpoint, decodeGRPCSumRequest, encodeGRPCSumResponse, append(options, grpctransport.ServerBefore(opentracing.GRPCToContext(otTracer, "Sum", logger)))..., ), concat: grpctransport.NewServer( endpoints.ConcatEndpoint, decodeGRPCConcatRequest, encodeGRPCConcatResponse, append(options, grpctransport.ServerBefore(opentracing.GRPCToContext(otTracer, "Concat", logger)))..., ), } } func (s *grpcServer) Sum(ctx context.Context, req *pb.SumRequest) (*pb.SumReply, error) { _, rep, err := s.sum.ServeGRPC(ctx, req) if err != nil { return nil, err } return rep.(*pb.SumReply), nil } func (s *grpcServer) Concat(ctx context.Context, req *pb.ConcatRequest) (*pb.ConcatReply, error) { _, rep, err := s.concat.ServeGRPC(ctx, req) if err != nil { return nil, err } return rep.(*pb.ConcatReply), nil } // NewGRPCClient returns an AddService backed by a gRPC server at the other end // of the conn. The caller is responsible for constructing the conn, and // eventually closing the underlying transport. We bake-in certain middlewares, // implementing the client library pattern. func NewGRPCClient(conn *grpc.ClientConn, otTracer stdopentracing.Tracer, zipkinTracer *stdzipkin.Tracer, logger log.Logger) addservice.Service { // We construct a single ratelimiter middleware, to limit the total outgoing // QPS from this client to all methods on the remote instance. We also // construct per-endpoint circuitbreaker middlewares to demonstrate how // that's done, although they could easily be combined into a single breaker // for the entire remote instance, too. limiter := ratelimit.NewErroringLimiter(rate.NewLimiter(rate.Every(time.Second), 100)) // global client middlewares var options []grpctransport.ClientOption if zipkinTracer != nil { // Zipkin GRPC Client Trace can either be instantiated per gRPC method with a // provided operation name or a global tracing client can be instantiated // without an operation name and fed to each Go kit client as ClientOption. // In the latter case, the operation name will be the endpoint's grpc method // path. // // In this example, we demonstrace a global tracing client. options = append(options, zipkin.GRPCClientTrace(zipkinTracer)) } // Each individual endpoint is an grpc/transport.Client (which implements // endpoint.Endpoint) that gets wrapped with various middlewares. If you // made your own client library, you'd do this work there, so your server // could rely on a consistent set of client behavior. var sumEndpoint endpoint.Endpoint { sumEndpoint = grpctransport.NewClient( conn, "pb.Add", "Sum", encodeGRPCSumRequest, decodeGRPCSumResponse, pb.SumReply{}, append(options, grpctransport.ClientBefore(opentracing.ContextToGRPC(otTracer, logger)))..., ).Endpoint() sumEndpoint = opentracing.TraceClient(otTracer, "Sum")(sumEndpoint) sumEndpoint = limiter(sumEndpoint) sumEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{ Name: "Sum", Timeout: 30 * time.Second, }))(sumEndpoint) } // The Concat endpoint is the same thing, with slightly different // middlewares to demonstrate how to specialize per-endpoint. var concatEndpoint endpoint.Endpoint { concatEndpoint = grpctransport.NewClient( conn, "pb.Add", "Concat", encodeGRPCConcatRequest, decodeGRPCConcatResponse, pb.ConcatReply{}, append(options, grpctransport.ClientBefore(opentracing.ContextToGRPC(otTracer, logger)))..., ).Endpoint() concatEndpoint = opentracing.TraceClient(otTracer, "Concat")(concatEndpoint) concatEndpoint = limiter(concatEndpoint) concatEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{ Name: "Concat", Timeout: 10 * time.Second, }))(concatEndpoint) } // Returning the endpoint.Set as a service.Service relies on the // endpoint.Set implementing the Service methods. That's just a simple bit // of glue code. return addendpoint.Set{ SumEndpoint: sumEndpoint, ConcatEndpoint: concatEndpoint, } } // decodeGRPCSumRequest is a transport/grpc.DecodeRequestFunc that converts a // gRPC sum request to a user-domain sum request. Primarily useful in a server. func decodeGRPCSumRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { req := grpcReq.(*pb.SumRequest) return addendpoint.SumRequest{A: int(req.A), B: int(req.B)}, nil } // decodeGRPCConcatRequest is a transport/grpc.DecodeRequestFunc that converts a // gRPC concat request to a user-domain concat request. Primarily useful in a // server. func decodeGRPCConcatRequest(_ context.Context, grpcReq interface{}) (interface{}, error) { req := grpcReq.(*pb.ConcatRequest) return addendpoint.ConcatRequest{A: req.A, B: req.B}, nil } // decodeGRPCSumResponse is a transport/grpc.DecodeResponseFunc that converts a // gRPC sum reply to a user-domain sum response. Primarily useful in a client. func decodeGRPCSumResponse(_ context.Context, grpcReply interface{}) (interface{}, error) { reply := grpcReply.(*pb.SumReply) return addendpoint.SumResponse{V: int(reply.V), Err: str2err(reply.Err)}, nil } // decodeGRPCConcatResponse is a transport/grpc.DecodeResponseFunc that converts // a gRPC concat reply to a user-domain concat response. Primarily useful in a // client. func decodeGRPCConcatResponse(_ context.Context, grpcReply interface{}) (interface{}, error) { reply := grpcReply.(*pb.ConcatReply) return addendpoint.ConcatResponse{V: reply.V, Err: str2err(reply.Err)}, nil } // encodeGRPCSumResponse is a transport/grpc.EncodeResponseFunc that converts a // user-domain sum response to a gRPC sum reply. Primarily useful in a server. func encodeGRPCSumResponse(_ context.Context, response interface{}) (interface{}, error) { resp := response.(addendpoint.SumResponse) return &pb.SumReply{V: int64(resp.V), Err: err2str(resp.Err)}, nil } // encodeGRPCConcatResponse is a transport/grpc.EncodeResponseFunc that converts // a user-domain concat response to a gRPC concat reply. Primarily useful in a // server. func encodeGRPCConcatResponse(_ context.Context, response interface{}) (interface{}, error) { resp := response.(addendpoint.ConcatResponse) return &pb.ConcatReply{V: resp.V, Err: err2str(resp.Err)}, nil } // encodeGRPCSumRequest is a transport/grpc.EncodeRequestFunc that converts a // user-domain sum request to a gRPC sum request. Primarily useful in a client. func encodeGRPCSumRequest(_ context.Context, request interface{}) (interface{}, error) { req := request.(addendpoint.SumRequest) return &pb.SumRequest{A: int64(req.A), B: int64(req.B)}, nil } // encodeGRPCConcatRequest is a transport/grpc.EncodeRequestFunc that converts a // user-domain concat request to a gRPC concat request. Primarily useful in a // client. func encodeGRPCConcatRequest(_ context.Context, request interface{}) (interface{}, error) { req := request.(addendpoint.ConcatRequest) return &pb.ConcatRequest{A: req.A, B: req.B}, nil } // These annoying helper functions are required to translate Go error types to // and from strings, which is the type we use in our IDLs to represent errors. // There is special casing to treat empty strings as nil errors. func str2err(s string) error { if s == "" { return nil } return errors.New(s) } func err2str(err error) string { if err == nil { return "" } return err.Error() } golang-github-go-kit-kit-0.10.0/examples/addsvc/pkg/addtransport/http.go000066400000000000000000000216701362256312400261640ustar00rootroot00000000000000package addtransport import ( "bytes" "context" "encoding/json" "errors" "io/ioutil" "net/http" "net/url" "strings" "time" "golang.org/x/time/rate" stdopentracing "github.com/opentracing/opentracing-go" stdzipkin "github.com/openzipkin/zipkin-go" "github.com/sony/gobreaker" "github.com/go-kit/kit/circuitbreaker" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/log" "github.com/go-kit/kit/ratelimit" "github.com/go-kit/kit/tracing/opentracing" "github.com/go-kit/kit/tracing/zipkin" "github.com/go-kit/kit/transport" httptransport "github.com/go-kit/kit/transport/http" "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint" "github.com/go-kit/kit/examples/addsvc/pkg/addservice" ) // NewHTTPHandler returns an HTTP handler that makes a set of endpoints // available on predefined paths. func NewHTTPHandler(endpoints addendpoint.Set, otTracer stdopentracing.Tracer, zipkinTracer *stdzipkin.Tracer, logger log.Logger) http.Handler { options := []httptransport.ServerOption{ httptransport.ServerErrorEncoder(errorEncoder), httptransport.ServerErrorHandler(transport.NewLogErrorHandler(logger)), } if zipkinTracer != nil { // Zipkin HTTP Server Trace can either be instantiated per endpoint with a // provided operation name or a global tracing service can be instantiated // without an operation name and fed to each Go kit endpoint as ServerOption. // In the latter case, the operation name will be the endpoint's http method. // We demonstrate a global tracing service here. options = append(options, zipkin.HTTPServerTrace(zipkinTracer)) } m := http.NewServeMux() m.Handle("/sum", httptransport.NewServer( endpoints.SumEndpoint, decodeHTTPSumRequest, encodeHTTPGenericResponse, append(options, httptransport.ServerBefore(opentracing.HTTPToContext(otTracer, "Sum", logger)))..., )) m.Handle("/concat", httptransport.NewServer( endpoints.ConcatEndpoint, decodeHTTPConcatRequest, encodeHTTPGenericResponse, append(options, httptransport.ServerBefore(opentracing.HTTPToContext(otTracer, "Concat", logger)))..., )) return m } // NewHTTPClient returns an AddService backed by an HTTP server living at the // remote instance. We expect instance to come from a service discovery system, // so likely of the form "host:port". We bake-in certain middlewares, // implementing the client library pattern. func NewHTTPClient(instance string, otTracer stdopentracing.Tracer, zipkinTracer *stdzipkin.Tracer, logger log.Logger) (addservice.Service, error) { // Quickly sanitize the instance string. if !strings.HasPrefix(instance, "http") { instance = "http://" + instance } u, err := url.Parse(instance) if err != nil { return nil, err } // We construct a single ratelimiter middleware, to limit the total outgoing // QPS from this client to all methods on the remote instance. We also // construct per-endpoint circuitbreaker middlewares to demonstrate how // that's done, although they could easily be combined into a single breaker // for the entire remote instance, too. limiter := ratelimit.NewErroringLimiter(rate.NewLimiter(rate.Every(time.Second), 100)) // global client middlewares var options []httptransport.ClientOption if zipkinTracer != nil { // Zipkin HTTP Client Trace can either be instantiated per endpoint with a // provided operation name or a global tracing client can be instantiated // without an operation name and fed to each Go kit endpoint as ClientOption. // In the latter case, the operation name will be the endpoint's http method. options = append(options, zipkin.HTTPClientTrace(zipkinTracer)) } // Each individual endpoint is an http/transport.Client (which implements // endpoint.Endpoint) that gets wrapped with various middlewares. If you // made your own client library, you'd do this work there, so your server // could rely on a consistent set of client behavior. var sumEndpoint endpoint.Endpoint { sumEndpoint = httptransport.NewClient( "POST", copyURL(u, "/sum"), encodeHTTPGenericRequest, decodeHTTPSumResponse, append(options, httptransport.ClientBefore(opentracing.ContextToHTTP(otTracer, logger)))..., ).Endpoint() sumEndpoint = opentracing.TraceClient(otTracer, "Sum")(sumEndpoint) if zipkinTracer != nil { sumEndpoint = zipkin.TraceEndpoint(zipkinTracer, "Sum")(sumEndpoint) } sumEndpoint = limiter(sumEndpoint) sumEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{ Name: "Sum", Timeout: 30 * time.Second, }))(sumEndpoint) } // The Concat endpoint is the same thing, with slightly different // middlewares to demonstrate how to specialize per-endpoint. var concatEndpoint endpoint.Endpoint { concatEndpoint = httptransport.NewClient( "POST", copyURL(u, "/concat"), encodeHTTPGenericRequest, decodeHTTPConcatResponse, append(options, httptransport.ClientBefore(opentracing.ContextToHTTP(otTracer, logger)))..., ).Endpoint() concatEndpoint = opentracing.TraceClient(otTracer, "Concat")(concatEndpoint) if zipkinTracer != nil { concatEndpoint = zipkin.TraceEndpoint(zipkinTracer, "Concat")(concatEndpoint) } concatEndpoint = limiter(concatEndpoint) concatEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{ Name: "Concat", Timeout: 10 * time.Second, }))(concatEndpoint) } // Returning the endpoint.Set as a service.Service relies on the // endpoint.Set implementing the Service methods. That's just a simple bit // of glue code. return addendpoint.Set{ SumEndpoint: sumEndpoint, ConcatEndpoint: concatEndpoint, }, nil } func copyURL(base *url.URL, path string) *url.URL { next := *base next.Path = path return &next } func errorEncoder(_ context.Context, err error, w http.ResponseWriter) { w.WriteHeader(err2code(err)) json.NewEncoder(w).Encode(errorWrapper{Error: err.Error()}) } func err2code(err error) int { switch err { case addservice.ErrTwoZeroes, addservice.ErrMaxSizeExceeded, addservice.ErrIntOverflow: return http.StatusBadRequest } return http.StatusInternalServerError } func errorDecoder(r *http.Response) error { var w errorWrapper if err := json.NewDecoder(r.Body).Decode(&w); err != nil { return err } return errors.New(w.Error) } type errorWrapper struct { Error string `json:"error"` } // decodeHTTPSumRequest is a transport/http.DecodeRequestFunc that decodes a // JSON-encoded sum request from the HTTP request body. Primarily useful in a // server. func decodeHTTPSumRequest(_ context.Context, r *http.Request) (interface{}, error) { var req addendpoint.SumRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } // decodeHTTPConcatRequest is a transport/http.DecodeRequestFunc that decodes a // JSON-encoded concat request from the HTTP request body. Primarily useful in a // server. func decodeHTTPConcatRequest(_ context.Context, r *http.Request) (interface{}, error) { var req addendpoint.ConcatRequest err := json.NewDecoder(r.Body).Decode(&req) return req, err } // decodeHTTPSumResponse is a transport/http.DecodeResponseFunc that decodes a // JSON-encoded sum response from the HTTP response body. If the response has a // non-200 status code, we will interpret that as an error and attempt to decode // the specific error message from the response body. Primarily useful in a // client. func decodeHTTPSumResponse(_ context.Context, r *http.Response) (interface{}, error) { if r.StatusCode != http.StatusOK { return nil, errors.New(r.Status) } var resp addendpoint.SumResponse err := json.NewDecoder(r.Body).Decode(&resp) return resp, err } // decodeHTTPConcatResponse is a transport/http.DecodeResponseFunc that decodes // a JSON-encoded concat response from the HTTP response body. If the response // has a non-200 status code, we will interpret that as an error and attempt to // decode the specific error message from the response body. Primarily useful in // a client. func decodeHTTPConcatResponse(_ context.Context, r *http.Response) (interface{}, error) { if r.StatusCode != http.StatusOK { return nil, errors.New(r.Status) } var resp addendpoint.ConcatResponse err := json.NewDecoder(r.Body).Decode(&resp) return resp, err } // encodeHTTPGenericRequest is a transport/http.EncodeRequestFunc that // JSON-encodes any request to the request body. Primarily useful in a client. func encodeHTTPGenericRequest(_ context.Context, r *http.Request, request interface{}) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(request); err != nil { return err } r.Body = ioutil.NopCloser(&buf) return nil } // encodeHTTPGenericResponse is a transport/http.EncodeResponseFunc that encodes // the response as JSON to the response writer. Primarily useful in a server. func encodeHTTPGenericResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error { if f, ok := response.(endpoint.Failer); ok && f.Failed() != nil { errorEncoder(ctx, f.Failed(), w) return nil } w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/examples/addsvc/pkg/addtransport/jsonrpc.go000066400000000000000000000145421362256312400266630ustar00rootroot00000000000000package addtransport import ( "context" "encoding/json" "fmt" "net/url" "strings" "time" "golang.org/x/time/rate" "github.com/go-kit/kit/circuitbreaker" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint" "github.com/go-kit/kit/examples/addsvc/pkg/addservice" "github.com/go-kit/kit/log" "github.com/go-kit/kit/ratelimit" "github.com/go-kit/kit/tracing/opentracing" "github.com/go-kit/kit/transport/http/jsonrpc" stdopentracing "github.com/opentracing/opentracing-go" "github.com/sony/gobreaker" ) // NewJSONRPCHandler returns a JSON RPC Server/Handler that can be passed to http.Handle() func NewJSONRPCHandler(endpoints addendpoint.Set, logger log.Logger) *jsonrpc.Server { handler := jsonrpc.NewServer( makeEndpointCodecMap(endpoints), jsonrpc.ServerErrorLogger(logger), ) return handler } // NewJSONRPCClient returns an addservice backed by a JSON RPC over HTTP server // living at the remote instance. We expect instance to come from a service // discovery system, so likely of the form "host:port". We bake-in certain // middlewares, implementing the client library pattern. func NewJSONRPCClient(instance string, tracer stdopentracing.Tracer, logger log.Logger) (addservice.Service, error) { // Quickly sanitize the instance string. if !strings.HasPrefix(instance, "http") { instance = "http://" + instance } u, err := url.Parse(instance) if err != nil { return nil, err } // We construct a single ratelimiter middleware, to limit the total outgoing // QPS from this client to all methods on the remote instance. We also // construct per-endpoint circuitbreaker middlewares to demonstrate how // that's done, although they could easily be combined into a single breaker // for the entire remote instance, too. limiter := ratelimit.NewErroringLimiter(rate.NewLimiter(rate.Every(time.Second), 100)) var sumEndpoint endpoint.Endpoint { sumEndpoint = jsonrpc.NewClient( u, "sum", jsonrpc.ClientRequestEncoder(encodeSumRequest), jsonrpc.ClientResponseDecoder(decodeSumResponse), ).Endpoint() sumEndpoint = opentracing.TraceClient(tracer, "Sum")(sumEndpoint) sumEndpoint = limiter(sumEndpoint) sumEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{ Name: "Sum", Timeout: 30 * time.Second, }))(sumEndpoint) } var concatEndpoint endpoint.Endpoint { concatEndpoint = jsonrpc.NewClient( u, "concat", jsonrpc.ClientRequestEncoder(encodeConcatRequest), jsonrpc.ClientResponseDecoder(decodeConcatResponse), ).Endpoint() concatEndpoint = opentracing.TraceClient(tracer, "Concat")(concatEndpoint) concatEndpoint = limiter(concatEndpoint) concatEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{ Name: "Concat", Timeout: 30 * time.Second, }))(concatEndpoint) } // Returning the endpoint.Set as a service.Service relies on the // endpoint.Set implementing the Service methods. That's just a simple bit // of glue code. return addendpoint.Set{ SumEndpoint: sumEndpoint, ConcatEndpoint: concatEndpoint, }, nil } // makeEndpointCodecMap returns a codec map configured for the addsvc. func makeEndpointCodecMap(endpoints addendpoint.Set) jsonrpc.EndpointCodecMap { return jsonrpc.EndpointCodecMap{ "sum": jsonrpc.EndpointCodec{ Endpoint: endpoints.SumEndpoint, Decode: decodeSumRequest, Encode: encodeSumResponse, }, "concat": jsonrpc.EndpointCodec{ Endpoint: endpoints.ConcatEndpoint, Decode: decodeConcatRequest, Encode: encodeConcatResponse, }, } } func decodeSumRequest(_ context.Context, msg json.RawMessage) (interface{}, error) { var req addendpoint.SumRequest err := json.Unmarshal(msg, &req) if err != nil { return nil, &jsonrpc.Error{ Code: -32000, Message: fmt.Sprintf("couldn't unmarshal body to sum request: %s", err), } } return req, nil } func encodeSumResponse(_ context.Context, obj interface{}) (json.RawMessage, error) { res, ok := obj.(addendpoint.SumResponse) if !ok { return nil, &jsonrpc.Error{ Code: -32000, Message: fmt.Sprintf("Asserting result to *SumResponse failed. Got %T, %+v", obj, obj), } } b, err := json.Marshal(res) if err != nil { return nil, fmt.Errorf("couldn't marshal response: %s", err) } return b, nil } func decodeSumResponse(_ context.Context, res jsonrpc.Response) (interface{}, error) { if res.Error != nil { return nil, *res.Error } var sumres addendpoint.SumResponse err := json.Unmarshal(res.Result, &sumres) if err != nil { return nil, fmt.Errorf("couldn't unmarshal body to SumResponse: %s", err) } return sumres, nil } func encodeSumRequest(_ context.Context, obj interface{}) (json.RawMessage, error) { req, ok := obj.(addendpoint.SumRequest) if !ok { return nil, fmt.Errorf("couldn't assert request as SumRequest, got %T", obj) } b, err := json.Marshal(req) if err != nil { return nil, fmt.Errorf("couldn't marshal request: %s", err) } return b, nil } func decodeConcatRequest(_ context.Context, msg json.RawMessage) (interface{}, error) { var req addendpoint.ConcatRequest err := json.Unmarshal(msg, &req) if err != nil { return nil, &jsonrpc.Error{ Code: -32000, Message: fmt.Sprintf("couldn't unmarshal body to concat request: %s", err), } } return req, nil } func encodeConcatResponse(_ context.Context, obj interface{}) (json.RawMessage, error) { res, ok := obj.(addendpoint.ConcatResponse) if !ok { return nil, &jsonrpc.Error{ Code: -32000, Message: fmt.Sprintf("Asserting result to *ConcatResponse failed. Got %T, %+v", obj, obj), } } b, err := json.Marshal(res) if err != nil { return nil, fmt.Errorf("couldn't marshal response: %s", err) } return b, nil } func decodeConcatResponse(_ context.Context, res jsonrpc.Response) (interface{}, error) { if res.Error != nil { return nil, *res.Error } var concatres addendpoint.ConcatResponse err := json.Unmarshal(res.Result, &concatres) if err != nil { return nil, fmt.Errorf("couldn't unmarshal body to ConcatResponse: %s", err) } return concatres, nil } func encodeConcatRequest(_ context.Context, obj interface{}) (json.RawMessage, error) { req, ok := obj.(addendpoint.ConcatRequest) if !ok { return nil, fmt.Errorf("couldn't assert request as ConcatRequest, got %T", obj) } b, err := json.Marshal(req) if err != nil { return nil, fmt.Errorf("couldn't marshal request: %s", err) } return b, nil } golang-github-go-kit-kit-0.10.0/examples/addsvc/pkg/addtransport/thrift.go000066400000000000000000000106641362256312400265060ustar00rootroot00000000000000package addtransport import ( "context" "time" "golang.org/x/time/rate" "github.com/sony/gobreaker" "github.com/go-kit/kit/circuitbreaker" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/ratelimit" "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint" "github.com/go-kit/kit/examples/addsvc/pkg/addservice" addthrift "github.com/go-kit/kit/examples/addsvc/thrift/gen-go/addsvc" ) type thriftServer struct { ctx context.Context endpoints addendpoint.Set } // NewThriftServer makes a set of endpoints available as a Thrift service. func NewThriftServer(endpoints addendpoint.Set) addthrift.AddService { return &thriftServer{ endpoints: endpoints, } } func (s *thriftServer) Sum(ctx context.Context, a int64, b int64) (*addthrift.SumReply, error) { request := addendpoint.SumRequest{A: int(a), B: int(b)} response, err := s.endpoints.SumEndpoint(ctx, request) if err != nil { return nil, err } resp := response.(addendpoint.SumResponse) return &addthrift.SumReply{Value: int64(resp.V), Err: err2str(resp.Err)}, nil } func (s *thriftServer) Concat(ctx context.Context, a string, b string) (*addthrift.ConcatReply, error) { request := addendpoint.ConcatRequest{A: a, B: b} response, err := s.endpoints.ConcatEndpoint(ctx, request) if err != nil { return nil, err } resp := response.(addendpoint.ConcatResponse) return &addthrift.ConcatReply{Value: resp.V, Err: err2str(resp.Err)}, nil } // NewThriftClient returns an AddService backed by a Thrift server described by // the provided client. The caller is responsible for constructing the client, // and eventually closing the underlying transport. We bake-in certain middlewares, // implementing the client library pattern. func NewThriftClient(client *addthrift.AddServiceClient) addservice.Service { // We construct a single ratelimiter middleware, to limit the total outgoing // QPS from this client to all methods on the remote instance. We also // construct per-endpoint circuitbreaker middlewares to demonstrate how // that's done, although they could easily be combined into a single breaker // for the entire remote instance, too. limiter := ratelimit.NewErroringLimiter(rate.NewLimiter(rate.Every(time.Second), 100)) // Each individual endpoint is an http/transport.Client (which implements // endpoint.Endpoint) that gets wrapped with various middlewares. If you // could rely on a consistent set of client behavior. var sumEndpoint endpoint.Endpoint { sumEndpoint = MakeThriftSumEndpoint(client) sumEndpoint = limiter(sumEndpoint) sumEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{ Name: "Sum", Timeout: 30 * time.Second, }))(sumEndpoint) } // The Concat endpoint is the same thing, with slightly different // middlewares to demonstrate how to specialize per-endpoint. var concatEndpoint endpoint.Endpoint { concatEndpoint = MakeThriftConcatEndpoint(client) concatEndpoint = limiter(concatEndpoint) concatEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{ Name: "Concat", Timeout: 10 * time.Second, }))(concatEndpoint) } // Returning the endpoint.Set as a service.Service relies on the // endpoint.Set implementing the Service methods. That's just a simple bit // of glue code. return addendpoint.Set{ SumEndpoint: sumEndpoint, ConcatEndpoint: concatEndpoint, } } // MakeThriftSumEndpoint returns an endpoint that invokes the passed Thrift client. // Useful only in clients, and only until a proper transport/thrift.Client exists. func MakeThriftSumEndpoint(client *addthrift.AddServiceClient) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(addendpoint.SumRequest) reply, err := client.Sum(ctx, int64(req.A), int64(req.B)) if err == addservice.ErrIntOverflow { return nil, err // special case; see comment on ErrIntOverflow } return addendpoint.SumResponse{V: int(reply.Value), Err: err}, nil } } // MakeThriftConcatEndpoint returns an endpoint that invokes the passed Thrift // client. Useful only in clients, and only until a proper // transport/thrift.Client exists. func MakeThriftConcatEndpoint(client *addthrift.AddServiceClient) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(addendpoint.ConcatRequest) reply, err := client.Concat(ctx, req.A, req.B) return addendpoint.ConcatResponse{V: reply.Value, Err: err}, nil } } golang-github-go-kit-kit-0.10.0/examples/addsvc/thrift/000077500000000000000000000000001362256312400226625ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/thrift/addsvc.thrift000066400000000000000000000003211362256312400253440ustar00rootroot00000000000000struct SumReply { 1: i64 value 2: string err } struct ConcatReply { 1: string value 2: string err } service AddService { SumReply Sum(1: i64 a, 2: i64 b) ConcatReply Concat(1: string a, 2: string b) } golang-github-go-kit-kit-0.10.0/examples/addsvc/thrift/compile.sh000077500000000000000000000017201362256312400246510ustar00rootroot00000000000000#!/usr/bin/env sh # See also https://thrift.apache.org/tutorial/go. # # An old version can be obtained via `brew install thrift`. # For the latest, here's the annoying dance: # # brew install automake bison pkg-config openssl # ln -s /usr/local/opt/openssl/include/openssl /usr/local/include # if it isn't already # git clone git@github.com:apache/thrift # ./bootstrap.sh # bash # export PATH=/usr/local/Cellar/bison/*/bin:$PATH # ./configure ./configure --without-qt4 --without-qt5 --without-c_glib --without-csharp --without-java --without-erlang --without-nodejs --without-lua --without-python --without-perl --without-php --without-php_extension --without-dart --without-ruby --without-haskell --without-rs --without-cl --without-haxe --without-dotnetcore --without-d # make # sudo make install thrift -r --gen "go:package_prefix=github.com/go-kit/kit/examples/addsvc/thrift/gen-go/,thrift_import=github.com/apache/thrift/lib/go/thrift" addsvc.thrift golang-github-go-kit-kit-0.10.0/examples/addsvc/thrift/gen-go/000077500000000000000000000000001362256312400240365ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/thrift/gen-go/addsvc/000077500000000000000000000000001362256312400253025ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/thrift/gen-go/addsvc/GoUnusedProtection__.go000066400000000000000000000002441362256312400317270ustar00rootroot00000000000000// Autogenerated by Thrift Compiler (1.0.0-dev) // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING package addsvc var GoUnusedProtection__ int; golang-github-go-kit-kit-0.10.0/examples/addsvc/thrift/gen-go/addsvc/add_service-remote/000077500000000000000000000000001362256312400310435ustar00rootroot00000000000000add_service-remote.go000077500000000000000000000112341362256312400350600ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/addsvc/thrift/gen-go/addsvc/add_service-remote// Autogenerated by Thrift Compiler (1.0.0-dev) // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING package main import ( "context" "flag" "fmt" "github.com/apache/thrift/lib/go/thrift" "github.com/go-kit/kit/examples/addsvc/thrift/gen-go/addsvc" "math" "net" "net/url" "os" "strconv" "strings" ) func Usage() { fmt.Fprintln(os.Stderr, "Usage of ", os.Args[0], " [-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:") flag.PrintDefaults() fmt.Fprintln(os.Stderr, "\nFunctions:") fmt.Fprintln(os.Stderr, " SumReply Sum(i64 a, i64 b)") fmt.Fprintln(os.Stderr, " ConcatReply Concat(string a, string b)") fmt.Fprintln(os.Stderr) os.Exit(0) } type httpHeaders map[string]string func (h httpHeaders) String() string { var m map[string]string = h return fmt.Sprintf("%s", m) } func (h httpHeaders) Set(value string) error { parts := strings.Split(value, ": ") if len(parts) != 2 { return fmt.Errorf("header should be of format 'Key: Value'") } h[parts[0]] = parts[1] return nil } func main() { flag.Usage = Usage var host string var port int var protocol string var urlString string var framed bool var useHttp bool headers := make(httpHeaders) var parsedUrl *url.URL var trans thrift.TTransport _ = strconv.Atoi _ = math.Abs flag.Usage = Usage flag.StringVar(&host, "h", "localhost", "Specify host and port") flag.IntVar(&port, "p", 9090, "Specify port") flag.StringVar(&protocol, "P", "binary", "Specify the protocol (binary, compact, simplejson, json)") flag.StringVar(&urlString, "u", "", "Specify the url") flag.BoolVar(&framed, "framed", false, "Use framed transport") flag.BoolVar(&useHttp, "http", false, "Use http") flag.Var(headers, "H", "Headers to set on the http(s) request (e.g. -H \"Key: Value\")") flag.Parse() if len(urlString) > 0 { var err error parsedUrl, err = url.Parse(urlString) if err != nil { fmt.Fprintln(os.Stderr, "Error parsing URL: ", err) flag.Usage() } host = parsedUrl.Host useHttp = parsedUrl.Scheme == "" || parsedUrl.Scheme == "http" || parsedUrl.Scheme == "https" } else if useHttp { _, err := url.Parse(fmt.Sprint("http://", host, ":", port)) if err != nil { fmt.Fprintln(os.Stderr, "Error parsing URL: ", err) flag.Usage() } } cmd := flag.Arg(0) var err error if useHttp { trans, err = thrift.NewTHttpClient(parsedUrl.String()) if len(headers) > 0 { httptrans := trans.(*thrift.THttpClient) for key, value := range headers { httptrans.SetHeader(key, value) } } } else { portStr := fmt.Sprint(port) if strings.Contains(host, ":") { host, portStr, err = net.SplitHostPort(host) if err != nil { fmt.Fprintln(os.Stderr, "error with host:", err) os.Exit(1) } } trans, err = thrift.NewTSocket(net.JoinHostPort(host, portStr)) if err != nil { fmt.Fprintln(os.Stderr, "error resolving address:", err) os.Exit(1) } if framed { trans = thrift.NewTFramedTransport(trans) } } if err != nil { fmt.Fprintln(os.Stderr, "Error creating transport", err) os.Exit(1) } defer trans.Close() var protocolFactory thrift.TProtocolFactory switch protocol { case "compact": protocolFactory = thrift.NewTCompactProtocolFactory() break case "simplejson": protocolFactory = thrift.NewTSimpleJSONProtocolFactory() break case "json": protocolFactory = thrift.NewTJSONProtocolFactory() break case "binary", "": protocolFactory = thrift.NewTBinaryProtocolFactoryDefault() break default: fmt.Fprintln(os.Stderr, "Invalid protocol specified: ", protocol) Usage() os.Exit(1) } iprot := protocolFactory.GetProtocol(trans) oprot := protocolFactory.GetProtocol(trans) client := addsvc.NewAddServiceClient(thrift.NewTStandardClient(iprot, oprot)) if err := trans.Open(); err != nil { fmt.Fprintln(os.Stderr, "Error opening socket to ", host, ":", port, " ", err) os.Exit(1) } switch cmd { case "Sum": if flag.NArg()-1 != 2 { fmt.Fprintln(os.Stderr, "Sum requires 2 args") flag.Usage() } argvalue0, err6 := (strconv.ParseInt(flag.Arg(1), 10, 64)) if err6 != nil { Usage() return } value0 := argvalue0 argvalue1, err7 := (strconv.ParseInt(flag.Arg(2), 10, 64)) if err7 != nil { Usage() return } value1 := argvalue1 fmt.Print(client.Sum(context.Background(), value0, value1)) fmt.Print("\n") break case "Concat": if flag.NArg()-1 != 2 { fmt.Fprintln(os.Stderr, "Concat requires 2 args") flag.Usage() } argvalue0 := flag.Arg(1) value0 := argvalue0 argvalue1 := flag.Arg(2) value1 := argvalue1 fmt.Print(client.Concat(context.Background(), value0, value1)) fmt.Print("\n") break case "": Usage() break default: fmt.Fprintln(os.Stderr, "Invalid function ", cmd) } } golang-github-go-kit-kit-0.10.0/examples/addsvc/thrift/gen-go/addsvc/addsvc-consts.go000066400000000000000000000006541362256312400304110ustar00rootroot00000000000000// Autogenerated by Thrift Compiler (1.0.0-dev) // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING package addsvc import ( "bytes" "context" "reflect" "fmt" "github.com/apache/thrift/lib/go/thrift" ) // (needed to ensure safety because of naive import list construction.) var _ = thrift.ZERO var _ = fmt.Printf var _ = context.Background var _ = reflect.DeepEqual var _ = bytes.Equal func init() { } golang-github-go-kit-kit-0.10.0/examples/addsvc/thrift/gen-go/addsvc/addsvc.go000066400000000000000000000665121362256312400271070ustar00rootroot00000000000000// Autogenerated by Thrift Compiler (1.0.0-dev) // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING package addsvc import ( "bytes" "context" "reflect" "fmt" "github.com/apache/thrift/lib/go/thrift" ) // (needed to ensure safety because of naive import list construction.) var _ = thrift.ZERO var _ = fmt.Printf var _ = context.Background var _ = reflect.DeepEqual var _ = bytes.Equal // Attributes: // - Value // - Err type SumReply struct { Value int64 `thrift:"value,1" db:"value" json:"value"` Err string `thrift:"err,2" db:"err" json:"err"` } func NewSumReply() *SumReply { return &SumReply{} } func (p *SumReply) GetValue() int64 { return p.Value } func (p *SumReply) GetErr() string { return p.Err } func (p *SumReply) Read(iprot thrift.TProtocol) error { if _, err := iprot.ReadStructBegin(); err != nil { return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) } for { _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() if err != nil { return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) } if fieldTypeId == thrift.STOP { break; } switch fieldId { case 1: if fieldTypeId == thrift.I64 { if err := p.ReadField1(iprot); err != nil { return err } } else { if err := iprot.Skip(fieldTypeId); err != nil { return err } } case 2: if fieldTypeId == thrift.STRING { if err := p.ReadField2(iprot); err != nil { return err } } else { if err := iprot.Skip(fieldTypeId); err != nil { return err } } default: if err := iprot.Skip(fieldTypeId); err != nil { return err } } if err := iprot.ReadFieldEnd(); err != nil { return err } } if err := iprot.ReadStructEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) } return nil } func (p *SumReply) ReadField1(iprot thrift.TProtocol) error { if v, err := iprot.ReadI64(); err != nil { return thrift.PrependError("error reading field 1: ", err) } else { p.Value = v } return nil } func (p *SumReply) ReadField2(iprot thrift.TProtocol) error { if v, err := iprot.ReadString(); err != nil { return thrift.PrependError("error reading field 2: ", err) } else { p.Err = v } return nil } func (p *SumReply) Write(oprot thrift.TProtocol) error { if err := oprot.WriteStructBegin("SumReply"); err != nil { return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } if p != nil { if err := p.writeField1(oprot); err != nil { return err } if err := p.writeField2(oprot); err != nil { return err } } if err := oprot.WriteFieldStop(); err != nil { return thrift.PrependError("write field stop error: ", err) } if err := oprot.WriteStructEnd(); err != nil { return thrift.PrependError("write struct stop error: ", err) } return nil } func (p *SumReply) writeField1(oprot thrift.TProtocol) (err error) { if err := oprot.WriteFieldBegin("value", thrift.I64, 1); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:value: ", p), err) } if err := oprot.WriteI64(int64(p.Value)); err != nil { return thrift.PrependError(fmt.Sprintf("%T.value (1) field write error: ", p), err) } if err := oprot.WriteFieldEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field end error 1:value: ", p), err) } return err } func (p *SumReply) writeField2(oprot thrift.TProtocol) (err error) { if err := oprot.WriteFieldBegin("err", thrift.STRING, 2); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:err: ", p), err) } if err := oprot.WriteString(string(p.Err)); err != nil { return thrift.PrependError(fmt.Sprintf("%T.err (2) field write error: ", p), err) } if err := oprot.WriteFieldEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field end error 2:err: ", p), err) } return err } func (p *SumReply) String() string { if p == nil { return "" } return fmt.Sprintf("SumReply(%+v)", *p) } // Attributes: // - Value // - Err type ConcatReply struct { Value string `thrift:"value,1" db:"value" json:"value"` Err string `thrift:"err,2" db:"err" json:"err"` } func NewConcatReply() *ConcatReply { return &ConcatReply{} } func (p *ConcatReply) GetValue() string { return p.Value } func (p *ConcatReply) GetErr() string { return p.Err } func (p *ConcatReply) Read(iprot thrift.TProtocol) error { if _, err := iprot.ReadStructBegin(); err != nil { return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) } for { _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() if err != nil { return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) } if fieldTypeId == thrift.STOP { break; } switch fieldId { case 1: if fieldTypeId == thrift.STRING { if err := p.ReadField1(iprot); err != nil { return err } } else { if err := iprot.Skip(fieldTypeId); err != nil { return err } } case 2: if fieldTypeId == thrift.STRING { if err := p.ReadField2(iprot); err != nil { return err } } else { if err := iprot.Skip(fieldTypeId); err != nil { return err } } default: if err := iprot.Skip(fieldTypeId); err != nil { return err } } if err := iprot.ReadFieldEnd(); err != nil { return err } } if err := iprot.ReadStructEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) } return nil } func (p *ConcatReply) ReadField1(iprot thrift.TProtocol) error { if v, err := iprot.ReadString(); err != nil { return thrift.PrependError("error reading field 1: ", err) } else { p.Value = v } return nil } func (p *ConcatReply) ReadField2(iprot thrift.TProtocol) error { if v, err := iprot.ReadString(); err != nil { return thrift.PrependError("error reading field 2: ", err) } else { p.Err = v } return nil } func (p *ConcatReply) Write(oprot thrift.TProtocol) error { if err := oprot.WriteStructBegin("ConcatReply"); err != nil { return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } if p != nil { if err := p.writeField1(oprot); err != nil { return err } if err := p.writeField2(oprot); err != nil { return err } } if err := oprot.WriteFieldStop(); err != nil { return thrift.PrependError("write field stop error: ", err) } if err := oprot.WriteStructEnd(); err != nil { return thrift.PrependError("write struct stop error: ", err) } return nil } func (p *ConcatReply) writeField1(oprot thrift.TProtocol) (err error) { if err := oprot.WriteFieldBegin("value", thrift.STRING, 1); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:value: ", p), err) } if err := oprot.WriteString(string(p.Value)); err != nil { return thrift.PrependError(fmt.Sprintf("%T.value (1) field write error: ", p), err) } if err := oprot.WriteFieldEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field end error 1:value: ", p), err) } return err } func (p *ConcatReply) writeField2(oprot thrift.TProtocol) (err error) { if err := oprot.WriteFieldBegin("err", thrift.STRING, 2); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:err: ", p), err) } if err := oprot.WriteString(string(p.Err)); err != nil { return thrift.PrependError(fmt.Sprintf("%T.err (2) field write error: ", p), err) } if err := oprot.WriteFieldEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field end error 2:err: ", p), err) } return err } func (p *ConcatReply) String() string { if p == nil { return "" } return fmt.Sprintf("ConcatReply(%+v)", *p) } type AddService interface { // Parameters: // - A // - B Sum(ctx context.Context, a int64, b int64) (r *SumReply, err error) // Parameters: // - A // - B Concat(ctx context.Context, a string, b string) (r *ConcatReply, err error) } type AddServiceClient struct { c thrift.TClient } func NewAddServiceClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *AddServiceClient { return &AddServiceClient{ c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t)), } } func NewAddServiceClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *AddServiceClient { return &AddServiceClient{ c: thrift.NewTStandardClient(iprot, oprot), } } func NewAddServiceClient(c thrift.TClient) *AddServiceClient { return &AddServiceClient{ c: c, } } func (p *AddServiceClient) Client_() thrift.TClient { return p.c } // Parameters: // - A // - B func (p *AddServiceClient) Sum(ctx context.Context, a int64, b int64) (r *SumReply, err error) { var _args0 AddServiceSumArgs _args0.A = a _args0.B = b var _result1 AddServiceSumResult if err = p.Client_().Call(ctx, "Sum", &_args0, &_result1); err != nil { return } return _result1.GetSuccess(), nil } // Parameters: // - A // - B func (p *AddServiceClient) Concat(ctx context.Context, a string, b string) (r *ConcatReply, err error) { var _args2 AddServiceConcatArgs _args2.A = a _args2.B = b var _result3 AddServiceConcatResult if err = p.Client_().Call(ctx, "Concat", &_args2, &_result3); err != nil { return } return _result3.GetSuccess(), nil } type AddServiceProcessor struct { processorMap map[string]thrift.TProcessorFunction handler AddService } func (p *AddServiceProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { p.processorMap[key] = processor } func (p *AddServiceProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { processor, ok = p.processorMap[key] return processor, ok } func (p *AddServiceProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { return p.processorMap } func NewAddServiceProcessor(handler AddService) *AddServiceProcessor { self4 := &AddServiceProcessor{handler:handler, processorMap:make(map[string]thrift.TProcessorFunction)} self4.processorMap["Sum"] = &addServiceProcessorSum{handler:handler} self4.processorMap["Concat"] = &addServiceProcessorConcat{handler:handler} return self4 } func (p *AddServiceProcessor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { name, _, seqId, err := iprot.ReadMessageBegin() if err != nil { return false, err } if processor, ok := p.GetProcessorFunction(name); ok { return processor.Process(ctx, seqId, iprot, oprot) } iprot.Skip(thrift.STRUCT) iprot.ReadMessageEnd() x5 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function " + name) oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) x5.Write(oprot) oprot.WriteMessageEnd() oprot.Flush(ctx) return false, x5 } type addServiceProcessorSum struct { handler AddService } func (p *addServiceProcessorSum) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { args := AddServiceSumArgs{} if err = args.Read(iprot); err != nil { iprot.ReadMessageEnd() x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) oprot.WriteMessageBegin("Sum", thrift.EXCEPTION, seqId) x.Write(oprot) oprot.WriteMessageEnd() oprot.Flush(ctx) return false, err } iprot.ReadMessageEnd() result := AddServiceSumResult{} var retval *SumReply var err2 error if retval, err2 = p.handler.Sum(ctx, args.A, args.B); err2 != nil { x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing Sum: " + err2.Error()) oprot.WriteMessageBegin("Sum", thrift.EXCEPTION, seqId) x.Write(oprot) oprot.WriteMessageEnd() oprot.Flush(ctx) return true, err2 } else { result.Success = retval } if err2 = oprot.WriteMessageBegin("Sum", thrift.REPLY, seqId); err2 != nil { err = err2 } if err2 = result.Write(oprot); err == nil && err2 != nil { err = err2 } if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { err = err2 } if err2 = oprot.Flush(ctx); err == nil && err2 != nil { err = err2 } if err != nil { return } return true, err } type addServiceProcessorConcat struct { handler AddService } func (p *addServiceProcessorConcat) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { args := AddServiceConcatArgs{} if err = args.Read(iprot); err != nil { iprot.ReadMessageEnd() x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) oprot.WriteMessageBegin("Concat", thrift.EXCEPTION, seqId) x.Write(oprot) oprot.WriteMessageEnd() oprot.Flush(ctx) return false, err } iprot.ReadMessageEnd() result := AddServiceConcatResult{} var retval *ConcatReply var err2 error if retval, err2 = p.handler.Concat(ctx, args.A, args.B); err2 != nil { x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing Concat: " + err2.Error()) oprot.WriteMessageBegin("Concat", thrift.EXCEPTION, seqId) x.Write(oprot) oprot.WriteMessageEnd() oprot.Flush(ctx) return true, err2 } else { result.Success = retval } if err2 = oprot.WriteMessageBegin("Concat", thrift.REPLY, seqId); err2 != nil { err = err2 } if err2 = result.Write(oprot); err == nil && err2 != nil { err = err2 } if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { err = err2 } if err2 = oprot.Flush(ctx); err == nil && err2 != nil { err = err2 } if err != nil { return } return true, err } // HELPER FUNCTIONS AND STRUCTURES // Attributes: // - A // - B type AddServiceSumArgs struct { A int64 `thrift:"a,1" db:"a" json:"a"` B int64 `thrift:"b,2" db:"b" json:"b"` } func NewAddServiceSumArgs() *AddServiceSumArgs { return &AddServiceSumArgs{} } func (p *AddServiceSumArgs) GetA() int64 { return p.A } func (p *AddServiceSumArgs) GetB() int64 { return p.B } func (p *AddServiceSumArgs) Read(iprot thrift.TProtocol) error { if _, err := iprot.ReadStructBegin(); err != nil { return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) } for { _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() if err != nil { return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) } if fieldTypeId == thrift.STOP { break; } switch fieldId { case 1: if fieldTypeId == thrift.I64 { if err := p.ReadField1(iprot); err != nil { return err } } else { if err := iprot.Skip(fieldTypeId); err != nil { return err } } case 2: if fieldTypeId == thrift.I64 { if err := p.ReadField2(iprot); err != nil { return err } } else { if err := iprot.Skip(fieldTypeId); err != nil { return err } } default: if err := iprot.Skip(fieldTypeId); err != nil { return err } } if err := iprot.ReadFieldEnd(); err != nil { return err } } if err := iprot.ReadStructEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) } return nil } func (p *AddServiceSumArgs) ReadField1(iprot thrift.TProtocol) error { if v, err := iprot.ReadI64(); err != nil { return thrift.PrependError("error reading field 1: ", err) } else { p.A = v } return nil } func (p *AddServiceSumArgs) ReadField2(iprot thrift.TProtocol) error { if v, err := iprot.ReadI64(); err != nil { return thrift.PrependError("error reading field 2: ", err) } else { p.B = v } return nil } func (p *AddServiceSumArgs) Write(oprot thrift.TProtocol) error { if err := oprot.WriteStructBegin("Sum_args"); err != nil { return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } if p != nil { if err := p.writeField1(oprot); err != nil { return err } if err := p.writeField2(oprot); err != nil { return err } } if err := oprot.WriteFieldStop(); err != nil { return thrift.PrependError("write field stop error: ", err) } if err := oprot.WriteStructEnd(); err != nil { return thrift.PrependError("write struct stop error: ", err) } return nil } func (p *AddServiceSumArgs) writeField1(oprot thrift.TProtocol) (err error) { if err := oprot.WriteFieldBegin("a", thrift.I64, 1); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:a: ", p), err) } if err := oprot.WriteI64(int64(p.A)); err != nil { return thrift.PrependError(fmt.Sprintf("%T.a (1) field write error: ", p), err) } if err := oprot.WriteFieldEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field end error 1:a: ", p), err) } return err } func (p *AddServiceSumArgs) writeField2(oprot thrift.TProtocol) (err error) { if err := oprot.WriteFieldBegin("b", thrift.I64, 2); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:b: ", p), err) } if err := oprot.WriteI64(int64(p.B)); err != nil { return thrift.PrependError(fmt.Sprintf("%T.b (2) field write error: ", p), err) } if err := oprot.WriteFieldEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field end error 2:b: ", p), err) } return err } func (p *AddServiceSumArgs) String() string { if p == nil { return "" } return fmt.Sprintf("AddServiceSumArgs(%+v)", *p) } // Attributes: // - Success type AddServiceSumResult struct { Success *SumReply `thrift:"success,0" db:"success" json:"success,omitempty"` } func NewAddServiceSumResult() *AddServiceSumResult { return &AddServiceSumResult{} } var AddServiceSumResult_Success_DEFAULT *SumReply func (p *AddServiceSumResult) GetSuccess() *SumReply { if !p.IsSetSuccess() { return AddServiceSumResult_Success_DEFAULT } return p.Success } func (p *AddServiceSumResult) IsSetSuccess() bool { return p.Success != nil } func (p *AddServiceSumResult) Read(iprot thrift.TProtocol) error { if _, err := iprot.ReadStructBegin(); err != nil { return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) } for { _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() if err != nil { return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) } if fieldTypeId == thrift.STOP { break; } switch fieldId { case 0: if fieldTypeId == thrift.STRUCT { if err := p.ReadField0(iprot); err != nil { return err } } else { if err := iprot.Skip(fieldTypeId); err != nil { return err } } default: if err := iprot.Skip(fieldTypeId); err != nil { return err } } if err := iprot.ReadFieldEnd(); err != nil { return err } } if err := iprot.ReadStructEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) } return nil } func (p *AddServiceSumResult) ReadField0(iprot thrift.TProtocol) error { p.Success = &SumReply{} if err := p.Success.Read(iprot); err != nil { return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Success), err) } return nil } func (p *AddServiceSumResult) Write(oprot thrift.TProtocol) error { if err := oprot.WriteStructBegin("Sum_result"); err != nil { return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } if p != nil { if err := p.writeField0(oprot); err != nil { return err } } if err := oprot.WriteFieldStop(); err != nil { return thrift.PrependError("write field stop error: ", err) } if err := oprot.WriteStructEnd(); err != nil { return thrift.PrependError("write struct stop error: ", err) } return nil } func (p *AddServiceSumResult) writeField0(oprot thrift.TProtocol) (err error) { if p.IsSetSuccess() { if err := oprot.WriteFieldBegin("success", thrift.STRUCT, 0); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) } if err := p.Success.Write(oprot); err != nil { return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Success), err) } if err := oprot.WriteFieldEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) } } return err } func (p *AddServiceSumResult) String() string { if p == nil { return "" } return fmt.Sprintf("AddServiceSumResult(%+v)", *p) } // Attributes: // - A // - B type AddServiceConcatArgs struct { A string `thrift:"a,1" db:"a" json:"a"` B string `thrift:"b,2" db:"b" json:"b"` } func NewAddServiceConcatArgs() *AddServiceConcatArgs { return &AddServiceConcatArgs{} } func (p *AddServiceConcatArgs) GetA() string { return p.A } func (p *AddServiceConcatArgs) GetB() string { return p.B } func (p *AddServiceConcatArgs) Read(iprot thrift.TProtocol) error { if _, err := iprot.ReadStructBegin(); err != nil { return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) } for { _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() if err != nil { return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) } if fieldTypeId == thrift.STOP { break; } switch fieldId { case 1: if fieldTypeId == thrift.STRING { if err := p.ReadField1(iprot); err != nil { return err } } else { if err := iprot.Skip(fieldTypeId); err != nil { return err } } case 2: if fieldTypeId == thrift.STRING { if err := p.ReadField2(iprot); err != nil { return err } } else { if err := iprot.Skip(fieldTypeId); err != nil { return err } } default: if err := iprot.Skip(fieldTypeId); err != nil { return err } } if err := iprot.ReadFieldEnd(); err != nil { return err } } if err := iprot.ReadStructEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) } return nil } func (p *AddServiceConcatArgs) ReadField1(iprot thrift.TProtocol) error { if v, err := iprot.ReadString(); err != nil { return thrift.PrependError("error reading field 1: ", err) } else { p.A = v } return nil } func (p *AddServiceConcatArgs) ReadField2(iprot thrift.TProtocol) error { if v, err := iprot.ReadString(); err != nil { return thrift.PrependError("error reading field 2: ", err) } else { p.B = v } return nil } func (p *AddServiceConcatArgs) Write(oprot thrift.TProtocol) error { if err := oprot.WriteStructBegin("Concat_args"); err != nil { return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } if p != nil { if err := p.writeField1(oprot); err != nil { return err } if err := p.writeField2(oprot); err != nil { return err } } if err := oprot.WriteFieldStop(); err != nil { return thrift.PrependError("write field stop error: ", err) } if err := oprot.WriteStructEnd(); err != nil { return thrift.PrependError("write struct stop error: ", err) } return nil } func (p *AddServiceConcatArgs) writeField1(oprot thrift.TProtocol) (err error) { if err := oprot.WriteFieldBegin("a", thrift.STRING, 1); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:a: ", p), err) } if err := oprot.WriteString(string(p.A)); err != nil { return thrift.PrependError(fmt.Sprintf("%T.a (1) field write error: ", p), err) } if err := oprot.WriteFieldEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field end error 1:a: ", p), err) } return err } func (p *AddServiceConcatArgs) writeField2(oprot thrift.TProtocol) (err error) { if err := oprot.WriteFieldBegin("b", thrift.STRING, 2); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:b: ", p), err) } if err := oprot.WriteString(string(p.B)); err != nil { return thrift.PrependError(fmt.Sprintf("%T.b (2) field write error: ", p), err) } if err := oprot.WriteFieldEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field end error 2:b: ", p), err) } return err } func (p *AddServiceConcatArgs) String() string { if p == nil { return "" } return fmt.Sprintf("AddServiceConcatArgs(%+v)", *p) } // Attributes: // - Success type AddServiceConcatResult struct { Success *ConcatReply `thrift:"success,0" db:"success" json:"success,omitempty"` } func NewAddServiceConcatResult() *AddServiceConcatResult { return &AddServiceConcatResult{} } var AddServiceConcatResult_Success_DEFAULT *ConcatReply func (p *AddServiceConcatResult) GetSuccess() *ConcatReply { if !p.IsSetSuccess() { return AddServiceConcatResult_Success_DEFAULT } return p.Success } func (p *AddServiceConcatResult) IsSetSuccess() bool { return p.Success != nil } func (p *AddServiceConcatResult) Read(iprot thrift.TProtocol) error { if _, err := iprot.ReadStructBegin(); err != nil { return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) } for { _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() if err != nil { return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) } if fieldTypeId == thrift.STOP { break; } switch fieldId { case 0: if fieldTypeId == thrift.STRUCT { if err := p.ReadField0(iprot); err != nil { return err } } else { if err := iprot.Skip(fieldTypeId); err != nil { return err } } default: if err := iprot.Skip(fieldTypeId); err != nil { return err } } if err := iprot.ReadFieldEnd(); err != nil { return err } } if err := iprot.ReadStructEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) } return nil } func (p *AddServiceConcatResult) ReadField0(iprot thrift.TProtocol) error { p.Success = &ConcatReply{} if err := p.Success.Read(iprot); err != nil { return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Success), err) } return nil } func (p *AddServiceConcatResult) Write(oprot thrift.TProtocol) error { if err := oprot.WriteStructBegin("Concat_result"); err != nil { return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } if p != nil { if err := p.writeField0(oprot); err != nil { return err } } if err := oprot.WriteFieldStop(); err != nil { return thrift.PrependError("write field stop error: ", err) } if err := oprot.WriteStructEnd(); err != nil { return thrift.PrependError("write struct stop error: ", err) } return nil } func (p *AddServiceConcatResult) writeField0(oprot thrift.TProtocol) (err error) { if p.IsSetSuccess() { if err := oprot.WriteFieldBegin("success", thrift.STRUCT, 0); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) } if err := p.Success.Write(oprot); err != nil { return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Success), err) } if err := oprot.WriteFieldEnd(); err != nil { return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) } } return err } func (p *AddServiceConcatResult) String() string { if p == nil { return "" } return fmt.Sprintf("AddServiceConcatResult(%+v)", *p) } golang-github-go-kit-kit-0.10.0/examples/apigateway/000077500000000000000000000000001362256312400222515ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/apigateway/main.go000066400000000000000000000221141362256312400235240ustar00rootroot00000000000000package main import ( "bytes" "context" "encoding/json" "flag" "fmt" "io" "io/ioutil" "net/http" "net/url" "os" "os/signal" "strings" "syscall" "time" consulsd "github.com/go-kit/kit/sd/consul" "github.com/gorilla/mux" "github.com/hashicorp/consul/api" stdopentracing "github.com/opentracing/opentracing-go" stdzipkin "github.com/openzipkin/zipkin-go" "google.golang.org/grpc" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/log" "github.com/go-kit/kit/sd" "github.com/go-kit/kit/sd/lb" httptransport "github.com/go-kit/kit/transport/http" "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint" "github.com/go-kit/kit/examples/addsvc/pkg/addservice" "github.com/go-kit/kit/examples/addsvc/pkg/addtransport" ) func main() { var ( httpAddr = flag.String("http.addr", ":8000", "Address for HTTP (JSON) server") consulAddr = flag.String("consul.addr", "", "Consul agent address") retryMax = flag.Int("retry.max", 3, "per-request retries to different instances") retryTimeout = flag.Duration("retry.timeout", 500*time.Millisecond, "per-request timeout, including retries") ) flag.Parse() // Logging domain. var logger log.Logger { logger = log.NewLogfmtLogger(os.Stderr) logger = log.With(logger, "ts", log.DefaultTimestampUTC) logger = log.With(logger, "caller", log.DefaultCaller) } // Service discovery domain. In this example we use Consul. var client consulsd.Client { consulConfig := api.DefaultConfig() if len(*consulAddr) > 0 { consulConfig.Address = *consulAddr } consulClient, err := api.NewClient(consulConfig) if err != nil { logger.Log("err", err) os.Exit(1) } client = consulsd.NewClient(consulClient) } // Transport domain. tracer := stdopentracing.GlobalTracer() // no-op zipkinTracer, _ := stdzipkin.NewTracer(nil, stdzipkin.WithNoopTracer(true)) ctx := context.Background() r := mux.NewRouter() // Now we begin installing the routes. Each route corresponds to a single // method: sum, concat, uppercase, and count. // addsvc routes. { // Each method gets constructed with a factory. Factories take an // instance string, and return a specific endpoint. In the factory we // dial the instance string we get from Consul, and then leverage an // addsvc client package to construct a complete service. We can then // leverage the addsvc.Make{Sum,Concat}Endpoint constructors to convert // the complete service to specific endpoint. var ( tags = []string{} passingOnly = true endpoints = addendpoint.Set{} instancer = consulsd.NewInstancer(client, logger, "addsvc", tags, passingOnly) ) { factory := addsvcFactory(addendpoint.MakeSumEndpoint, tracer, zipkinTracer, logger) endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(*retryMax, *retryTimeout, balancer) endpoints.SumEndpoint = retry } { factory := addsvcFactory(addendpoint.MakeConcatEndpoint, tracer, zipkinTracer, logger) endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(*retryMax, *retryTimeout, balancer) endpoints.ConcatEndpoint = retry } // Here we leverage the fact that addsvc comes with a constructor for an // HTTP handler, and just install it under a particular path prefix in // our router. r.PathPrefix("/addsvc").Handler(http.StripPrefix("/addsvc", addtransport.NewHTTPHandler(endpoints, tracer, zipkinTracer, logger))) } // stringsvc routes. { // addsvc had lots of nice importable Go packages we could leverage. // With stringsvc we are not so fortunate, it just has some endpoints // that we assume will exist. So we have to write that logic here. This // is by design, so you can see two totally different methods of // proxying to a remote service. var ( tags = []string{} passingOnly = true uppercase endpoint.Endpoint count endpoint.Endpoint instancer = consulsd.NewInstancer(client, logger, "stringsvc", tags, passingOnly) ) { factory := stringsvcFactory(ctx, "GET", "/uppercase") endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(*retryMax, *retryTimeout, balancer) uppercase = retry } { factory := stringsvcFactory(ctx, "GET", "/count") endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(*retryMax, *retryTimeout, balancer) count = retry } // We can use the transport/http.Server to act as our handler, all we // have to do provide it with the encode and decode functions for our // stringsvc methods. r.Handle("/stringsvc/uppercase", httptransport.NewServer(uppercase, decodeUppercaseRequest, encodeJSONResponse)) r.Handle("/stringsvc/count", httptransport.NewServer(count, decodeCountRequest, encodeJSONResponse)) } // Interrupt handler. errc := make(chan error) go func() { c := make(chan os.Signal) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) errc <- fmt.Errorf("%s", <-c) }() // HTTP transport. go func() { logger.Log("transport", "HTTP", "addr", *httpAddr) errc <- http.ListenAndServe(*httpAddr, r) }() // Run! logger.Log("exit", <-errc) } func addsvcFactory(makeEndpoint func(addservice.Service) endpoint.Endpoint, tracer stdopentracing.Tracer, zipkinTracer *stdzipkin.Tracer, logger log.Logger) sd.Factory { return func(instance string) (endpoint.Endpoint, io.Closer, error) { // We could just as easily use the HTTP or Thrift client package to make // the connection to addsvc. We've chosen gRPC arbitrarily. Note that // the transport is an implementation detail: it doesn't leak out of // this function. Nice! conn, err := grpc.Dial(instance, grpc.WithInsecure()) if err != nil { return nil, nil, err } service := addtransport.NewGRPCClient(conn, tracer, zipkinTracer, logger) endpoint := makeEndpoint(service) // Notice that the addsvc gRPC client converts the connection to a // complete addsvc, and we just throw away everything except the method // we're interested in. A smarter factory would mux multiple methods // over the same connection. But that would require more work to manage // the returned io.Closer, e.g. reference counting. Since this is for // the purposes of demonstration, we'll just keep it simple. return endpoint, conn, nil } } func stringsvcFactory(ctx context.Context, method, path string) sd.Factory { return func(instance string) (endpoint.Endpoint, io.Closer, error) { if !strings.HasPrefix(instance, "http") { instance = "http://" + instance } tgt, err := url.Parse(instance) if err != nil { return nil, nil, err } tgt.Path = path // Since stringsvc doesn't have any kind of package we can import, or // any formal spec, we are forced to just assert where the endpoints // live, and write our own code to encode and decode requests and // responses. Ideally, if you write the service, you will want to // provide stronger guarantees to your clients. var ( enc httptransport.EncodeRequestFunc dec httptransport.DecodeResponseFunc ) switch path { case "/uppercase": enc, dec = encodeJSONRequest, decodeUppercaseResponse case "/count": enc, dec = encodeJSONRequest, decodeCountResponse default: return nil, nil, fmt.Errorf("unknown stringsvc path %q", path) } return httptransport.NewClient(method, tgt, enc, dec).Endpoint(), nil, nil } } func encodeJSONRequest(_ context.Context, req *http.Request, request interface{}) error { // Both uppercase and count requests are encoded in the same way: // simple JSON serialization to the request body. var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(request); err != nil { return err } req.Body = ioutil.NopCloser(&buf) return nil } func encodeJSONResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } // I've just copied these functions from stringsvc3/transport.go, inlining the // struct definitions. func decodeUppercaseResponse(ctx context.Context, resp *http.Response) (interface{}, error) { var response struct { V string `json:"v"` Err string `json:"err,omitempty"` } if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { return nil, err } return response, nil } func decodeCountResponse(ctx context.Context, resp *http.Response) (interface{}, error) { var response struct { V int `json:"v"` } if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { return nil, err } return response, nil } func decodeUppercaseRequest(ctx context.Context, req *http.Request) (interface{}, error) { var request struct { S string `json:"s"` } if err := json.NewDecoder(req.Body).Decode(&request); err != nil { return nil, err } return request, nil } func decodeCountRequest(ctx context.Context, req *http.Request) (interface{}, error) { var request struct { S string `json:"s"` } if err := json.NewDecoder(req.Body).Decode(&request); err != nil { return nil, err } return request, nil } golang-github-go-kit-kit-0.10.0/examples/profilesvc/000077500000000000000000000000001362256312400222725ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/profilesvc/README.md000066400000000000000000000012421362256312400235500ustar00rootroot00000000000000# profilesvc This example demonstrates how to use Go kit to implement a REST-y HTTP service. It leverages the excellent [gorilla mux package](https://github.com/gorilla/mux) for routing. Run the example with the optional port address for the service: ```bash $ go run ./cmd/profilesvc/main.go -http.addr :8080 ts=2018-05-01T16:13:12.849086255Z caller=main.go:47 transport=HTTP addr=:8080 ``` Create a Profile: ```bash $ curl -d '{"id":"1234","Name":"Go Kit"}' -H "Content-Type: application/json" -X POST http://localhost:8080/profiles/ {} ``` Get the profile you just created ```bash $ curl localhost:8080/profiles/1234 {"profile":{"id":"1234","name":"Go Kit"}} ``` golang-github-go-kit-kit-0.10.0/examples/profilesvc/client/000077500000000000000000000000001362256312400235505ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/profilesvc/client/client.go000066400000000000000000000077131362256312400253650ustar00rootroot00000000000000// Package client provides a profilesvc client based on a predefined Consul // service name and relevant tags. Users must only provide the address of a // Consul server. package client import ( "io" "time" consulapi "github.com/hashicorp/consul/api" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/examples/profilesvc" "github.com/go-kit/kit/log" "github.com/go-kit/kit/sd" "github.com/go-kit/kit/sd/consul" "github.com/go-kit/kit/sd/lb" ) // New returns a service that's load-balanced over instances of profilesvc found // in the provided Consul server. The mechanism of looking up profilesvc // instances in Consul is hard-coded into the client. func New(consulAddr string, logger log.Logger) (profilesvc.Service, error) { apiclient, err := consulapi.NewClient(&consulapi.Config{ Address: consulAddr, }) if err != nil { return nil, err } // As the implementer of profilesvc, we declare and enforce these // parameters for all of the profilesvc consumers. var ( consulService = "profilesvc" consulTags = []string{"prod"} passingOnly = true retryMax = 3 retryTimeout = 500 * time.Millisecond ) var ( sdclient = consul.NewClient(apiclient) instancer = consul.NewInstancer(sdclient, logger, consulService, consulTags, passingOnly) endpoints profilesvc.Endpoints ) { factory := factoryFor(profilesvc.MakePostProfileEndpoint) endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(retryMax, retryTimeout, balancer) endpoints.PostProfileEndpoint = retry } { factory := factoryFor(profilesvc.MakeGetProfileEndpoint) endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(retryMax, retryTimeout, balancer) endpoints.GetProfileEndpoint = retry } { factory := factoryFor(profilesvc.MakePutProfileEndpoint) endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(retryMax, retryTimeout, balancer) endpoints.PutProfileEndpoint = retry } { factory := factoryFor(profilesvc.MakePatchProfileEndpoint) endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(retryMax, retryTimeout, balancer) endpoints.PatchProfileEndpoint = retry } { factory := factoryFor(profilesvc.MakeDeleteProfileEndpoint) endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(retryMax, retryTimeout, balancer) endpoints.DeleteProfileEndpoint = retry } { factory := factoryFor(profilesvc.MakeGetAddressesEndpoint) endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(retryMax, retryTimeout, balancer) endpoints.GetAddressesEndpoint = retry } { factory := factoryFor(profilesvc.MakeGetAddressEndpoint) endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(retryMax, retryTimeout, balancer) endpoints.GetAddressEndpoint = retry } { factory := factoryFor(profilesvc.MakePostAddressEndpoint) endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(retryMax, retryTimeout, balancer) endpoints.PostAddressEndpoint = retry } { factory := factoryFor(profilesvc.MakeDeleteAddressEndpoint) endpointer := sd.NewEndpointer(instancer, factory, logger) balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(retryMax, retryTimeout, balancer) endpoints.DeleteAddressEndpoint = retry } return endpoints, nil } func factoryFor(makeEndpoint func(profilesvc.Service) endpoint.Endpoint) sd.Factory { return func(instance string) (endpoint.Endpoint, io.Closer, error) { service, err := profilesvc.MakeClientEndpoints(instance) if err != nil { return nil, nil, err } return makeEndpoint(service), nil, nil } } golang-github-go-kit-kit-0.10.0/examples/profilesvc/cmd/000077500000000000000000000000001362256312400230355ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/profilesvc/cmd/profilesvc/000077500000000000000000000000001362256312400252115ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/profilesvc/cmd/profilesvc/main.go000066400000000000000000000017161362256312400264710ustar00rootroot00000000000000package main import ( "flag" "fmt" "net/http" "os" "os/signal" "syscall" "github.com/go-kit/kit/examples/profilesvc" "github.com/go-kit/kit/log" ) func main() { var ( httpAddr = flag.String("http.addr", ":8080", "HTTP listen address") ) flag.Parse() var logger log.Logger { logger = log.NewLogfmtLogger(os.Stderr) logger = log.With(logger, "ts", log.DefaultTimestampUTC) logger = log.With(logger, "caller", log.DefaultCaller) } var s profilesvc.Service { s = profilesvc.NewInmemService() s = profilesvc.LoggingMiddleware(logger)(s) } var h http.Handler { h = profilesvc.MakeHTTPHandler(s, log.With(logger, "component", "HTTP")) } errs := make(chan error) go func() { c := make(chan os.Signal) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) errs <- fmt.Errorf("%s", <-c) }() go func() { logger.Log("transport", "HTTP", "addr", *httpAddr) errs <- http.ListenAndServe(*httpAddr, h) }() logger.Log("exit", <-errs) } golang-github-go-kit-kit-0.10.0/examples/profilesvc/endpoints.go000066400000000000000000000323601362256312400246300ustar00rootroot00000000000000package profilesvc import ( "context" "net/url" "strings" "github.com/go-kit/kit/endpoint" httptransport "github.com/go-kit/kit/transport/http" ) // Endpoints collects all of the endpoints that compose a profile service. It's // meant to be used as a helper struct, to collect all of the endpoints into a // single parameter. // // In a server, it's useful for functions that need to operate on a per-endpoint // basis. For example, you might pass an Endpoints to a function that produces // an http.Handler, with each method (endpoint) wired up to a specific path. (It // is probably a mistake in design to invoke the Service methods on the // Endpoints struct in a server.) // // In a client, it's useful to collect individually constructed endpoints into a // single type that implements the Service interface. For example, you might // construct individual endpoints using transport/http.NewClient, combine them // into an Endpoints, and return it to the caller as a Service. type Endpoints struct { PostProfileEndpoint endpoint.Endpoint GetProfileEndpoint endpoint.Endpoint PutProfileEndpoint endpoint.Endpoint PatchProfileEndpoint endpoint.Endpoint DeleteProfileEndpoint endpoint.Endpoint GetAddressesEndpoint endpoint.Endpoint GetAddressEndpoint endpoint.Endpoint PostAddressEndpoint endpoint.Endpoint DeleteAddressEndpoint endpoint.Endpoint } // MakeServerEndpoints returns an Endpoints struct where each endpoint invokes // the corresponding method on the provided service. Useful in a profilesvc // server. func MakeServerEndpoints(s Service) Endpoints { return Endpoints{ PostProfileEndpoint: MakePostProfileEndpoint(s), GetProfileEndpoint: MakeGetProfileEndpoint(s), PutProfileEndpoint: MakePutProfileEndpoint(s), PatchProfileEndpoint: MakePatchProfileEndpoint(s), DeleteProfileEndpoint: MakeDeleteProfileEndpoint(s), GetAddressesEndpoint: MakeGetAddressesEndpoint(s), GetAddressEndpoint: MakeGetAddressEndpoint(s), PostAddressEndpoint: MakePostAddressEndpoint(s), DeleteAddressEndpoint: MakeDeleteAddressEndpoint(s), } } // MakeClientEndpoints returns an Endpoints struct where each endpoint invokes // the corresponding method on the remote instance, via a transport/http.Client. // Useful in a profilesvc client. func MakeClientEndpoints(instance string) (Endpoints, error) { if !strings.HasPrefix(instance, "http") { instance = "http://" + instance } tgt, err := url.Parse(instance) if err != nil { return Endpoints{}, err } tgt.Path = "" options := []httptransport.ClientOption{} // Note that the request encoders need to modify the request URL, changing // the path. That's fine: we simply need to provide specific encoders for // each endpoint. return Endpoints{ PostProfileEndpoint: httptransport.NewClient("POST", tgt, encodePostProfileRequest, decodePostProfileResponse, options...).Endpoint(), GetProfileEndpoint: httptransport.NewClient("GET", tgt, encodeGetProfileRequest, decodeGetProfileResponse, options...).Endpoint(), PutProfileEndpoint: httptransport.NewClient("PUT", tgt, encodePutProfileRequest, decodePutProfileResponse, options...).Endpoint(), PatchProfileEndpoint: httptransport.NewClient("PATCH", tgt, encodePatchProfileRequest, decodePatchProfileResponse, options...).Endpoint(), DeleteProfileEndpoint: httptransport.NewClient("DELETE", tgt, encodeDeleteProfileRequest, decodeDeleteProfileResponse, options...).Endpoint(), GetAddressesEndpoint: httptransport.NewClient("GET", tgt, encodeGetAddressesRequest, decodeGetAddressesResponse, options...).Endpoint(), GetAddressEndpoint: httptransport.NewClient("GET", tgt, encodeGetAddressRequest, decodeGetAddressResponse, options...).Endpoint(), PostAddressEndpoint: httptransport.NewClient("POST", tgt, encodePostAddressRequest, decodePostAddressResponse, options...).Endpoint(), DeleteAddressEndpoint: httptransport.NewClient("DELETE", tgt, encodeDeleteAddressRequest, decodeDeleteAddressResponse, options...).Endpoint(), }, nil } // PostProfile implements Service. Primarily useful in a client. func (e Endpoints) PostProfile(ctx context.Context, p Profile) error { request := postProfileRequest{Profile: p} response, err := e.PostProfileEndpoint(ctx, request) if err != nil { return err } resp := response.(postProfileResponse) return resp.Err } // GetProfile implements Service. Primarily useful in a client. func (e Endpoints) GetProfile(ctx context.Context, id string) (Profile, error) { request := getProfileRequest{ID: id} response, err := e.GetProfileEndpoint(ctx, request) if err != nil { return Profile{}, err } resp := response.(getProfileResponse) return resp.Profile, resp.Err } // PutProfile implements Service. Primarily useful in a client. func (e Endpoints) PutProfile(ctx context.Context, id string, p Profile) error { request := putProfileRequest{ID: id, Profile: p} response, err := e.PutProfileEndpoint(ctx, request) if err != nil { return err } resp := response.(putProfileResponse) return resp.Err } // PatchProfile implements Service. Primarily useful in a client. func (e Endpoints) PatchProfile(ctx context.Context, id string, p Profile) error { request := patchProfileRequest{ID: id, Profile: p} response, err := e.PatchProfileEndpoint(ctx, request) if err != nil { return err } resp := response.(patchProfileResponse) return resp.Err } // DeleteProfile implements Service. Primarily useful in a client. func (e Endpoints) DeleteProfile(ctx context.Context, id string) error { request := deleteProfileRequest{ID: id} response, err := e.DeleteProfileEndpoint(ctx, request) if err != nil { return err } resp := response.(deleteProfileResponse) return resp.Err } // GetAddresses implements Service. Primarily useful in a client. func (e Endpoints) GetAddresses(ctx context.Context, profileID string) ([]Address, error) { request := getAddressesRequest{ProfileID: profileID} response, err := e.GetAddressesEndpoint(ctx, request) if err != nil { return nil, err } resp := response.(getAddressesResponse) return resp.Addresses, resp.Err } // GetAddress implements Service. Primarily useful in a client. func (e Endpoints) GetAddress(ctx context.Context, profileID string, addressID string) (Address, error) { request := getAddressRequest{ProfileID: profileID, AddressID: addressID} response, err := e.GetAddressEndpoint(ctx, request) if err != nil { return Address{}, err } resp := response.(getAddressResponse) return resp.Address, resp.Err } // PostAddress implements Service. Primarily useful in a client. func (e Endpoints) PostAddress(ctx context.Context, profileID string, a Address) error { request := postAddressRequest{ProfileID: profileID, Address: a} response, err := e.PostAddressEndpoint(ctx, request) if err != nil { return err } resp := response.(postAddressResponse) return resp.Err } // DeleteAddress implements Service. Primarily useful in a client. func (e Endpoints) DeleteAddress(ctx context.Context, profileID string, addressID string) error { request := deleteAddressRequest{ProfileID: profileID, AddressID: addressID} response, err := e.DeleteAddressEndpoint(ctx, request) if err != nil { return err } resp := response.(deleteAddressResponse) return resp.Err } // MakePostProfileEndpoint returns an endpoint via the passed service. // Primarily useful in a server. func MakePostProfileEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { req := request.(postProfileRequest) e := s.PostProfile(ctx, req.Profile) return postProfileResponse{Err: e}, nil } } // MakeGetProfileEndpoint returns an endpoint via the passed service. // Primarily useful in a server. func MakeGetProfileEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { req := request.(getProfileRequest) p, e := s.GetProfile(ctx, req.ID) return getProfileResponse{Profile: p, Err: e}, nil } } // MakePutProfileEndpoint returns an endpoint via the passed service. // Primarily useful in a server. func MakePutProfileEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { req := request.(putProfileRequest) e := s.PutProfile(ctx, req.ID, req.Profile) return putProfileResponse{Err: e}, nil } } // MakePatchProfileEndpoint returns an endpoint via the passed service. // Primarily useful in a server. func MakePatchProfileEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { req := request.(patchProfileRequest) e := s.PatchProfile(ctx, req.ID, req.Profile) return patchProfileResponse{Err: e}, nil } } // MakeDeleteProfileEndpoint returns an endpoint via the passed service. // Primarily useful in a server. func MakeDeleteProfileEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { req := request.(deleteProfileRequest) e := s.DeleteProfile(ctx, req.ID) return deleteProfileResponse{Err: e}, nil } } // MakeGetAddressesEndpoint returns an endpoint via the passed service. // Primarily useful in a server. func MakeGetAddressesEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { req := request.(getAddressesRequest) a, e := s.GetAddresses(ctx, req.ProfileID) return getAddressesResponse{Addresses: a, Err: e}, nil } } // MakeGetAddressEndpoint returns an endpoint via the passed service. // Primarily useful in a server. func MakeGetAddressEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { req := request.(getAddressRequest) a, e := s.GetAddress(ctx, req.ProfileID, req.AddressID) return getAddressResponse{Address: a, Err: e}, nil } } // MakePostAddressEndpoint returns an endpoint via the passed service. // Primarily useful in a server. func MakePostAddressEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { req := request.(postAddressRequest) e := s.PostAddress(ctx, req.ProfileID, req.Address) return postAddressResponse{Err: e}, nil } } // MakeDeleteAddressEndpoint returns an endpoint via the passed service. // Primarily useful in a server. func MakeDeleteAddressEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { req := request.(deleteAddressRequest) e := s.DeleteAddress(ctx, req.ProfileID, req.AddressID) return deleteAddressResponse{Err: e}, nil } } // We have two options to return errors from the business logic. // // We could return the error via the endpoint itself. That makes certain things // a little bit easier, like providing non-200 HTTP responses to the client. But // Go kit assumes that endpoint errors are (or may be treated as) // transport-domain errors. For example, an endpoint error will count against a // circuit breaker error count. // // Therefore, it's often better to return service (business logic) errors in the // response object. This means we have to do a bit more work in the HTTP // response encoder to detect e.g. a not-found error and provide a proper HTTP // status code. That work is done with the errorer interface, in transport.go. // Response types that may contain business-logic errors implement that // interface. type postProfileRequest struct { Profile Profile } type postProfileResponse struct { Err error `json:"err,omitempty"` } func (r postProfileResponse) error() error { return r.Err } type getProfileRequest struct { ID string } type getProfileResponse struct { Profile Profile `json:"profile,omitempty"` Err error `json:"err,omitempty"` } func (r getProfileResponse) error() error { return r.Err } type putProfileRequest struct { ID string Profile Profile } type putProfileResponse struct { Err error `json:"err,omitempty"` } func (r putProfileResponse) error() error { return nil } type patchProfileRequest struct { ID string Profile Profile } type patchProfileResponse struct { Err error `json:"err,omitempty"` } func (r patchProfileResponse) error() error { return r.Err } type deleteProfileRequest struct { ID string } type deleteProfileResponse struct { Err error `json:"err,omitempty"` } func (r deleteProfileResponse) error() error { return r.Err } type getAddressesRequest struct { ProfileID string } type getAddressesResponse struct { Addresses []Address `json:"addresses,omitempty"` Err error `json:"err,omitempty"` } func (r getAddressesResponse) error() error { return r.Err } type getAddressRequest struct { ProfileID string AddressID string } type getAddressResponse struct { Address Address `json:"address,omitempty"` Err error `json:"err,omitempty"` } func (r getAddressResponse) error() error { return r.Err } type postAddressRequest struct { ProfileID string Address Address } type postAddressResponse struct { Err error `json:"err,omitempty"` } func (r postAddressResponse) error() error { return r.Err } type deleteAddressRequest struct { ProfileID string AddressID string } type deleteAddressResponse struct { Err error `json:"err,omitempty"` } func (r deleteAddressResponse) error() error { return r.Err } golang-github-go-kit-kit-0.10.0/examples/profilesvc/middlewares.go000066400000000000000000000060321362256312400251220ustar00rootroot00000000000000package profilesvc import ( "context" "time" "github.com/go-kit/kit/log" ) // Middleware describes a service (as opposed to endpoint) middleware. type Middleware func(Service) Service func LoggingMiddleware(logger log.Logger) Middleware { return func(next Service) Service { return &loggingMiddleware{ next: next, logger: logger, } } } type loggingMiddleware struct { next Service logger log.Logger } func (mw loggingMiddleware) PostProfile(ctx context.Context, p Profile) (err error) { defer func(begin time.Time) { mw.logger.Log("method", "PostProfile", "id", p.ID, "took", time.Since(begin), "err", err) }(time.Now()) return mw.next.PostProfile(ctx, p) } func (mw loggingMiddleware) GetProfile(ctx context.Context, id string) (p Profile, err error) { defer func(begin time.Time) { mw.logger.Log("method", "GetProfile", "id", id, "took", time.Since(begin), "err", err) }(time.Now()) return mw.next.GetProfile(ctx, id) } func (mw loggingMiddleware) PutProfile(ctx context.Context, id string, p Profile) (err error) { defer func(begin time.Time) { mw.logger.Log("method", "PutProfile", "id", id, "took", time.Since(begin), "err", err) }(time.Now()) return mw.next.PutProfile(ctx, id, p) } func (mw loggingMiddleware) PatchProfile(ctx context.Context, id string, p Profile) (err error) { defer func(begin time.Time) { mw.logger.Log("method", "PatchProfile", "id", id, "took", time.Since(begin), "err", err) }(time.Now()) return mw.next.PatchProfile(ctx, id, p) } func (mw loggingMiddleware) DeleteProfile(ctx context.Context, id string) (err error) { defer func(begin time.Time) { mw.logger.Log("method", "DeleteProfile", "id", id, "took", time.Since(begin), "err", err) }(time.Now()) return mw.next.DeleteProfile(ctx, id) } func (mw loggingMiddleware) GetAddresses(ctx context.Context, profileID string) (addresses []Address, err error) { defer func(begin time.Time) { mw.logger.Log("method", "GetAddresses", "profileID", profileID, "took", time.Since(begin), "err", err) }(time.Now()) return mw.next.GetAddresses(ctx, profileID) } func (mw loggingMiddleware) GetAddress(ctx context.Context, profileID string, addressID string) (a Address, err error) { defer func(begin time.Time) { mw.logger.Log("method", "GetAddress", "profileID", profileID, "addressID", addressID, "took", time.Since(begin), "err", err) }(time.Now()) return mw.next.GetAddress(ctx, profileID, addressID) } func (mw loggingMiddleware) PostAddress(ctx context.Context, profileID string, a Address) (err error) { defer func(begin time.Time) { mw.logger.Log("method", "PostAddress", "profileID", profileID, "took", time.Since(begin), "err", err) }(time.Now()) return mw.next.PostAddress(ctx, profileID, a) } func (mw loggingMiddleware) DeleteAddress(ctx context.Context, profileID string, addressID string) (err error) { defer func(begin time.Time) { mw.logger.Log("method", "DeleteAddress", "profileID", profileID, "addressID", addressID, "took", time.Since(begin), "err", err) }(time.Now()) return mw.next.DeleteAddress(ctx, profileID, addressID) } golang-github-go-kit-kit-0.10.0/examples/profilesvc/service.go000066400000000000000000000107441362256312400242670ustar00rootroot00000000000000package profilesvc import ( "context" "errors" "sync" ) // Service is a simple CRUD interface for user profiles. type Service interface { PostProfile(ctx context.Context, p Profile) error GetProfile(ctx context.Context, id string) (Profile, error) PutProfile(ctx context.Context, id string, p Profile) error PatchProfile(ctx context.Context, id string, p Profile) error DeleteProfile(ctx context.Context, id string) error GetAddresses(ctx context.Context, profileID string) ([]Address, error) GetAddress(ctx context.Context, profileID string, addressID string) (Address, error) PostAddress(ctx context.Context, profileID string, a Address) error DeleteAddress(ctx context.Context, profileID string, addressID string) error } // Profile represents a single user profile. // ID should be globally unique. type Profile struct { ID string `json:"id"` Name string `json:"name,omitempty"` Addresses []Address `json:"addresses,omitempty"` } // Address is a field of a user profile. // ID should be unique within the profile (at a minimum). type Address struct { ID string `json:"id"` Location string `json:"location,omitempty"` } var ( ErrInconsistentIDs = errors.New("inconsistent IDs") ErrAlreadyExists = errors.New("already exists") ErrNotFound = errors.New("not found") ) type inmemService struct { mtx sync.RWMutex m map[string]Profile } func NewInmemService() Service { return &inmemService{ m: map[string]Profile{}, } } func (s *inmemService) PostProfile(ctx context.Context, p Profile) error { s.mtx.Lock() defer s.mtx.Unlock() if _, ok := s.m[p.ID]; ok { return ErrAlreadyExists // POST = create, don't overwrite } s.m[p.ID] = p return nil } func (s *inmemService) GetProfile(ctx context.Context, id string) (Profile, error) { s.mtx.RLock() defer s.mtx.RUnlock() p, ok := s.m[id] if !ok { return Profile{}, ErrNotFound } return p, nil } func (s *inmemService) PutProfile(ctx context.Context, id string, p Profile) error { if id != p.ID { return ErrInconsistentIDs } s.mtx.Lock() defer s.mtx.Unlock() s.m[id] = p // PUT = create or update return nil } func (s *inmemService) PatchProfile(ctx context.Context, id string, p Profile) error { if p.ID != "" && id != p.ID { return ErrInconsistentIDs } s.mtx.Lock() defer s.mtx.Unlock() existing, ok := s.m[id] if !ok { return ErrNotFound // PATCH = update existing, don't create } // We assume that it's not possible to PATCH the ID, and that it's not // possible to PATCH any field to its zero value. That is, the zero value // means not specified. The way around this is to use e.g. Name *string in // the Profile definition. But since this is just a demonstrative example, // I'm leaving that out. if p.Name != "" { existing.Name = p.Name } if len(p.Addresses) > 0 { existing.Addresses = p.Addresses } s.m[id] = existing return nil } func (s *inmemService) DeleteProfile(ctx context.Context, id string) error { s.mtx.Lock() defer s.mtx.Unlock() if _, ok := s.m[id]; !ok { return ErrNotFound } delete(s.m, id) return nil } func (s *inmemService) GetAddresses(ctx context.Context, profileID string) ([]Address, error) { s.mtx.RLock() defer s.mtx.RUnlock() p, ok := s.m[profileID] if !ok { return []Address{}, ErrNotFound } return p.Addresses, nil } func (s *inmemService) GetAddress(ctx context.Context, profileID string, addressID string) (Address, error) { s.mtx.RLock() defer s.mtx.RUnlock() p, ok := s.m[profileID] if !ok { return Address{}, ErrNotFound } for _, address := range p.Addresses { if address.ID == addressID { return address, nil } } return Address{}, ErrNotFound } func (s *inmemService) PostAddress(ctx context.Context, profileID string, a Address) error { s.mtx.Lock() defer s.mtx.Unlock() p, ok := s.m[profileID] if !ok { return ErrNotFound } for _, address := range p.Addresses { if address.ID == a.ID { return ErrAlreadyExists } } p.Addresses = append(p.Addresses, a) s.m[profileID] = p return nil } func (s *inmemService) DeleteAddress(ctx context.Context, profileID string, addressID string) error { s.mtx.Lock() defer s.mtx.Unlock() p, ok := s.m[profileID] if !ok { return ErrNotFound } newAddresses := make([]Address, 0, len(p.Addresses)) for _, address := range p.Addresses { if address.ID == addressID { continue // delete } newAddresses = append(newAddresses, address) } if len(newAddresses) == len(p.Addresses) { return ErrNotFound } p.Addresses = newAddresses s.m[profileID] = p return nil } golang-github-go-kit-kit-0.10.0/examples/profilesvc/transport.go000066400000000000000000000306241362256312400246620ustar00rootroot00000000000000package profilesvc // The profilesvc is just over HTTP, so we just have a single transport.go. import ( "bytes" "context" "encoding/json" "errors" "io/ioutil" "net/http" "net/url" "github.com/gorilla/mux" "github.com/go-kit/kit/log" "github.com/go-kit/kit/transport" httptransport "github.com/go-kit/kit/transport/http" ) var ( // ErrBadRouting is returned when an expected path variable is missing. // It always indicates programmer error. ErrBadRouting = errors.New("inconsistent mapping between route and handler (programmer error)") ) // MakeHTTPHandler mounts all of the service endpoints into an http.Handler. // Useful in a profilesvc server. func MakeHTTPHandler(s Service, logger log.Logger) http.Handler { r := mux.NewRouter() e := MakeServerEndpoints(s) options := []httptransport.ServerOption{ httptransport.ServerErrorHandler(transport.NewLogErrorHandler(logger)), httptransport.ServerErrorEncoder(encodeError), } // POST /profiles/ adds another profile // GET /profiles/:id retrieves the given profile by id // PUT /profiles/:id post updated profile information about the profile // PATCH /profiles/:id partial updated profile information // DELETE /profiles/:id remove the given profile // GET /profiles/:id/addresses/ retrieve addresses associated with the profile // GET /profiles/:id/addresses/:addressID retrieve a particular profile address // POST /profiles/:id/addresses/ add a new address // DELETE /profiles/:id/addresses/:addressID remove an address r.Methods("POST").Path("/profiles/").Handler(httptransport.NewServer( e.PostProfileEndpoint, decodePostProfileRequest, encodeResponse, options..., )) r.Methods("GET").Path("/profiles/{id}").Handler(httptransport.NewServer( e.GetProfileEndpoint, decodeGetProfileRequest, encodeResponse, options..., )) r.Methods("PUT").Path("/profiles/{id}").Handler(httptransport.NewServer( e.PutProfileEndpoint, decodePutProfileRequest, encodeResponse, options..., )) r.Methods("PATCH").Path("/profiles/{id}").Handler(httptransport.NewServer( e.PatchProfileEndpoint, decodePatchProfileRequest, encodeResponse, options..., )) r.Methods("DELETE").Path("/profiles/{id}").Handler(httptransport.NewServer( e.DeleteProfileEndpoint, decodeDeleteProfileRequest, encodeResponse, options..., )) r.Methods("GET").Path("/profiles/{id}/addresses/").Handler(httptransport.NewServer( e.GetAddressesEndpoint, decodeGetAddressesRequest, encodeResponse, options..., )) r.Methods("GET").Path("/profiles/{id}/addresses/{addressID}").Handler(httptransport.NewServer( e.GetAddressEndpoint, decodeGetAddressRequest, encodeResponse, options..., )) r.Methods("POST").Path("/profiles/{id}/addresses/").Handler(httptransport.NewServer( e.PostAddressEndpoint, decodePostAddressRequest, encodeResponse, options..., )) r.Methods("DELETE").Path("/profiles/{id}/addresses/{addressID}").Handler(httptransport.NewServer( e.DeleteAddressEndpoint, decodeDeleteAddressRequest, encodeResponse, options..., )) return r } func decodePostProfileRequest(_ context.Context, r *http.Request) (request interface{}, err error) { var req postProfileRequest if e := json.NewDecoder(r.Body).Decode(&req.Profile); e != nil { return nil, e } return req, nil } func decodeGetProfileRequest(_ context.Context, r *http.Request) (request interface{}, err error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, ErrBadRouting } return getProfileRequest{ID: id}, nil } func decodePutProfileRequest(_ context.Context, r *http.Request) (request interface{}, err error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, ErrBadRouting } var profile Profile if err := json.NewDecoder(r.Body).Decode(&profile); err != nil { return nil, err } return putProfileRequest{ ID: id, Profile: profile, }, nil } func decodePatchProfileRequest(_ context.Context, r *http.Request) (request interface{}, err error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, ErrBadRouting } var profile Profile if err := json.NewDecoder(r.Body).Decode(&profile); err != nil { return nil, err } return patchProfileRequest{ ID: id, Profile: profile, }, nil } func decodeDeleteProfileRequest(_ context.Context, r *http.Request) (request interface{}, err error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, ErrBadRouting } return deleteProfileRequest{ID: id}, nil } func decodeGetAddressesRequest(_ context.Context, r *http.Request) (request interface{}, err error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, ErrBadRouting } return getAddressesRequest{ProfileID: id}, nil } func decodeGetAddressRequest(_ context.Context, r *http.Request) (request interface{}, err error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, ErrBadRouting } addressID, ok := vars["addressID"] if !ok { return nil, ErrBadRouting } return getAddressRequest{ ProfileID: id, AddressID: addressID, }, nil } func decodePostAddressRequest(_ context.Context, r *http.Request) (request interface{}, err error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, ErrBadRouting } var address Address if err := json.NewDecoder(r.Body).Decode(&address); err != nil { return nil, err } return postAddressRequest{ ProfileID: id, Address: address, }, nil } func decodeDeleteAddressRequest(_ context.Context, r *http.Request) (request interface{}, err error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, ErrBadRouting } addressID, ok := vars["addressID"] if !ok { return nil, ErrBadRouting } return deleteAddressRequest{ ProfileID: id, AddressID: addressID, }, nil } func encodePostProfileRequest(ctx context.Context, req *http.Request, request interface{}) error { // r.Methods("POST").Path("/profiles/") req.URL.Path = "/profiles/" return encodeRequest(ctx, req, request) } func encodeGetProfileRequest(ctx context.Context, req *http.Request, request interface{}) error { // r.Methods("GET").Path("/profiles/{id}") r := request.(getProfileRequest) profileID := url.QueryEscape(r.ID) req.URL.Path = "/profiles/" + profileID return encodeRequest(ctx, req, request) } func encodePutProfileRequest(ctx context.Context, req *http.Request, request interface{}) error { // r.Methods("PUT").Path("/profiles/{id}") r := request.(putProfileRequest) profileID := url.QueryEscape(r.ID) req.URL.Path = "/profiles/" + profileID return encodeRequest(ctx, req, request) } func encodePatchProfileRequest(ctx context.Context, req *http.Request, request interface{}) error { // r.Methods("PATCH").Path("/profiles/{id}") r := request.(patchProfileRequest) profileID := url.QueryEscape(r.ID) req.URL.Path = "/profiles/" + profileID return encodeRequest(ctx, req, request) } func encodeDeleteProfileRequest(ctx context.Context, req *http.Request, request interface{}) error { // r.Methods("DELETE").Path("/profiles/{id}") r := request.(deleteProfileRequest) profileID := url.QueryEscape(r.ID) req.URL.Path = "/profiles/" + profileID return encodeRequest(ctx, req, request) } func encodeGetAddressesRequest(ctx context.Context, req *http.Request, request interface{}) error { // r.Methods("GET").Path("/profiles/{id}/addresses/") r := request.(getAddressesRequest) profileID := url.QueryEscape(r.ProfileID) req.URL.Path = "/profiles/" + profileID + "/addresses/" return encodeRequest(ctx, req, request) } func encodeGetAddressRequest(ctx context.Context, req *http.Request, request interface{}) error { // r.Methods("GET").Path("/profiles/{id}/addresses/{addressID}") r := request.(getAddressRequest) profileID := url.QueryEscape(r.ProfileID) addressID := url.QueryEscape(r.AddressID) req.URL.Path = "/profiles/" + profileID + "/addresses/" + addressID return encodeRequest(ctx, req, request) } func encodePostAddressRequest(ctx context.Context, req *http.Request, request interface{}) error { // r.Methods("POST").Path("/profiles/{id}/addresses/") r := request.(postAddressRequest) profileID := url.QueryEscape(r.ProfileID) req.URL.Path = "/profiles/" + profileID + "/addresses/" return encodeRequest(ctx, req, request) } func encodeDeleteAddressRequest(ctx context.Context, req *http.Request, request interface{}) error { // r.Methods("DELETE").Path("/profiles/{id}/addresses/{addressID}") r := request.(deleteAddressRequest) profileID := url.QueryEscape(r.ProfileID) addressID := url.QueryEscape(r.AddressID) req.URL.Path = "/profiles/" + profileID + "/addresses/" + addressID return encodeRequest(ctx, req, request) } func decodePostProfileResponse(_ context.Context, resp *http.Response) (interface{}, error) { var response postProfileResponse err := json.NewDecoder(resp.Body).Decode(&response) return response, err } func decodeGetProfileResponse(_ context.Context, resp *http.Response) (interface{}, error) { var response getProfileResponse err := json.NewDecoder(resp.Body).Decode(&response) return response, err } func decodePutProfileResponse(_ context.Context, resp *http.Response) (interface{}, error) { var response putProfileResponse err := json.NewDecoder(resp.Body).Decode(&response) return response, err } func decodePatchProfileResponse(_ context.Context, resp *http.Response) (interface{}, error) { var response patchProfileResponse err := json.NewDecoder(resp.Body).Decode(&response) return response, err } func decodeDeleteProfileResponse(_ context.Context, resp *http.Response) (interface{}, error) { var response deleteProfileResponse err := json.NewDecoder(resp.Body).Decode(&response) return response, err } func decodeGetAddressesResponse(_ context.Context, resp *http.Response) (interface{}, error) { var response getAddressesResponse err := json.NewDecoder(resp.Body).Decode(&response) return response, err } func decodeGetAddressResponse(_ context.Context, resp *http.Response) (interface{}, error) { var response getAddressResponse err := json.NewDecoder(resp.Body).Decode(&response) return response, err } func decodePostAddressResponse(_ context.Context, resp *http.Response) (interface{}, error) { var response postAddressResponse err := json.NewDecoder(resp.Body).Decode(&response) return response, err } func decodeDeleteAddressResponse(_ context.Context, resp *http.Response) (interface{}, error) { var response deleteAddressResponse err := json.NewDecoder(resp.Body).Decode(&response) return response, err } // errorer is implemented by all concrete response types that may contain // errors. It allows us to change the HTTP response code without needing to // trigger an endpoint (transport-level) error. For more information, read the // big comment in endpoints.go. type errorer interface { error() error } // encodeResponse is the common method to encode all response types to the // client. I chose to do it this way because, since we're using JSON, there's no // reason to provide anything more specific. It's certainly possible to // specialize on a per-response (per-method) basis. func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error { if e, ok := response.(errorer); ok && e.error() != nil { // Not a Go kit transport error, but a business-logic error. // Provide those as HTTP errors. encodeError(ctx, e.error(), w) return nil } w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } // encodeRequest likewise JSON-encodes the request to the HTTP request body. // Don't use it directly as a transport/http.Client EncodeRequestFunc: // profilesvc endpoints require mutating the HTTP method and request path. func encodeRequest(_ context.Context, req *http.Request, request interface{}) error { var buf bytes.Buffer err := json.NewEncoder(&buf).Encode(request) if err != nil { return err } req.Body = ioutil.NopCloser(&buf) return nil } func encodeError(_ context.Context, err error, w http.ResponseWriter) { if err == nil { panic("encodeError with nil error") } w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(codeFrom(err)) json.NewEncoder(w).Encode(map[string]interface{}{ "error": err.Error(), }) } func codeFrom(err error) int { switch err { case ErrNotFound: return http.StatusNotFound case ErrAlreadyExists, ErrInconsistentIDs: return http.StatusBadRequest default: return http.StatusInternalServerError } } golang-github-go-kit-kit-0.10.0/examples/shipping/000077500000000000000000000000001362256312400217375ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/shipping/README.md000066400000000000000000000034601362256312400232210ustar00rootroot00000000000000# shipping This example demonstrates a more real-world application consisting of multiple services. ## Description The implementation is based on the container shipping domain from the [Domain Driven Design](http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215) book by Eric Evans, which was [originally](http://dddsample.sourceforge.net/) implemented in Java but has since been ported to Go. This example is a somewhat stripped down version to demonstrate the use of Go kit. The [original Go application](https://github.com/marcusolsson/goddd) is maintained separately and accompanied by an [AngularJS application](https://github.com/marcusolsson/dddelivery-angularjs) as well as a mock [routing service](https://github.com/marcusolsson/pathfinder). ### Organization The application consists of three application services, `booking`, `handling` and `tracking`. Each of these is an individual Go kit service as seen in previous examples. - __booking__ - used by the shipping company to book and route cargos. - __handling__ - used by our staff around the world to register whenever the cargo has been received, loaded etc. - __tracking__ - used by the customer to track the cargo along the route There are also a few pure domain packages that contain some intricate business-logic. They provide domain objects and services that are used by each application service to provide interesting use-cases for the user. `inmem` contains in-memory implementations for the repositories found in the domain packages. The `routing` package provides a _domain service_ that is used to query an external application for possible routes. ## Contributing As with all Go kit examples you are more than welcome to contribute. If you do however, please consider contributing back to the original project as well. golang-github-go-kit-kit-0.10.0/examples/shipping/booking/000077500000000000000000000000001362256312400233675ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/shipping/booking/endpoint.go000066400000000000000000000073421362256312400255440ustar00rootroot00000000000000package booking import ( "context" "time" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" ) type bookCargoRequest struct { Origin location.UNLocode Destination location.UNLocode ArrivalDeadline time.Time } type bookCargoResponse struct { ID cargo.TrackingID `json:"tracking_id,omitempty"` Err error `json:"error,omitempty"` } func (r bookCargoResponse) error() error { return r.Err } func makeBookCargoEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(bookCargoRequest) id, err := s.BookNewCargo(req.Origin, req.Destination, req.ArrivalDeadline) return bookCargoResponse{ID: id, Err: err}, nil } } type loadCargoRequest struct { ID cargo.TrackingID } type loadCargoResponse struct { Cargo *Cargo `json:"cargo,omitempty"` Err error `json:"error,omitempty"` } func (r loadCargoResponse) error() error { return r.Err } func makeLoadCargoEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(loadCargoRequest) c, err := s.LoadCargo(req.ID) return loadCargoResponse{Cargo: &c, Err: err}, nil } } type requestRoutesRequest struct { ID cargo.TrackingID } type requestRoutesResponse struct { Routes []cargo.Itinerary `json:"routes,omitempty"` Err error `json:"error,omitempty"` } func (r requestRoutesResponse) error() error { return r.Err } func makeRequestRoutesEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(requestRoutesRequest) itin := s.RequestPossibleRoutesForCargo(req.ID) return requestRoutesResponse{Routes: itin, Err: nil}, nil } } type assignToRouteRequest struct { ID cargo.TrackingID Itinerary cargo.Itinerary } type assignToRouteResponse struct { Err error `json:"error,omitempty"` } func (r assignToRouteResponse) error() error { return r.Err } func makeAssignToRouteEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(assignToRouteRequest) err := s.AssignCargoToRoute(req.ID, req.Itinerary) return assignToRouteResponse{Err: err}, nil } } type changeDestinationRequest struct { ID cargo.TrackingID Destination location.UNLocode } type changeDestinationResponse struct { Err error `json:"error,omitempty"` } func (r changeDestinationResponse) error() error { return r.Err } func makeChangeDestinationEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(changeDestinationRequest) err := s.ChangeDestination(req.ID, req.Destination) return changeDestinationResponse{Err: err}, nil } } type listCargosRequest struct{} type listCargosResponse struct { Cargos []Cargo `json:"cargos,omitempty"` Err error `json:"error,omitempty"` } func (r listCargosResponse) error() error { return r.Err } func makeListCargosEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { _ = request.(listCargosRequest) return listCargosResponse{Cargos: s.Cargos(), Err: nil}, nil } } type listLocationsRequest struct { } type listLocationsResponse struct { Locations []Location `json:"locations,omitempty"` Err error `json:"error,omitempty"` } func makeListLocationsEndpoint(s Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { _ = request.(listLocationsRequest) return listLocationsResponse{Locations: s.Locations(), Err: nil}, nil } } golang-github-go-kit-kit-0.10.0/examples/shipping/booking/instrumenting.go000066400000000000000000000054421362256312400266310ustar00rootroot00000000000000package booking import ( "time" "github.com/go-kit/kit/metrics" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" ) type instrumentingService struct { requestCount metrics.Counter requestLatency metrics.Histogram Service } // NewInstrumentingService returns an instance of an instrumenting Service. func NewInstrumentingService(counter metrics.Counter, latency metrics.Histogram, s Service) Service { return &instrumentingService{ requestCount: counter, requestLatency: latency, Service: s, } } func (s *instrumentingService) BookNewCargo(origin, destination location.UNLocode, deadline time.Time) (cargo.TrackingID, error) { defer func(begin time.Time) { s.requestCount.With("method", "book").Add(1) s.requestLatency.With("method", "book").Observe(time.Since(begin).Seconds()) }(time.Now()) return s.Service.BookNewCargo(origin, destination, deadline) } func (s *instrumentingService) LoadCargo(id cargo.TrackingID) (c Cargo, err error) { defer func(begin time.Time) { s.requestCount.With("method", "load").Add(1) s.requestLatency.With("method", "load").Observe(time.Since(begin).Seconds()) }(time.Now()) return s.Service.LoadCargo(id) } func (s *instrumentingService) RequestPossibleRoutesForCargo(id cargo.TrackingID) []cargo.Itinerary { defer func(begin time.Time) { s.requestCount.With("method", "request_routes").Add(1) s.requestLatency.With("method", "request_routes").Observe(time.Since(begin).Seconds()) }(time.Now()) return s.Service.RequestPossibleRoutesForCargo(id) } func (s *instrumentingService) AssignCargoToRoute(id cargo.TrackingID, itinerary cargo.Itinerary) (err error) { defer func(begin time.Time) { s.requestCount.With("method", "assign_to_route").Add(1) s.requestLatency.With("method", "assign_to_route").Observe(time.Since(begin).Seconds()) }(time.Now()) return s.Service.AssignCargoToRoute(id, itinerary) } func (s *instrumentingService) ChangeDestination(id cargo.TrackingID, l location.UNLocode) (err error) { defer func(begin time.Time) { s.requestCount.With("method", "change_destination").Add(1) s.requestLatency.With("method", "change_destination").Observe(time.Since(begin).Seconds()) }(time.Now()) return s.Service.ChangeDestination(id, l) } func (s *instrumentingService) Cargos() []Cargo { defer func(begin time.Time) { s.requestCount.With("method", "list_cargos").Add(1) s.requestLatency.With("method", "list_cargos").Observe(time.Since(begin).Seconds()) }(time.Now()) return s.Service.Cargos() } func (s *instrumentingService) Locations() []Location { defer func(begin time.Time) { s.requestCount.With("method", "list_locations").Add(1) s.requestLatency.With("method", "list_locations").Observe(time.Since(begin).Seconds()) }(time.Now()) return s.Service.Locations() } golang-github-go-kit-kit-0.10.0/examples/shipping/booking/logging.go000066400000000000000000000046371362256312400253560ustar00rootroot00000000000000package booking import ( "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" ) type loggingService struct { logger log.Logger Service } // NewLoggingService returns a new instance of a logging Service. func NewLoggingService(logger log.Logger, s Service) Service { return &loggingService{logger, s} } func (s *loggingService) BookNewCargo(origin location.UNLocode, destination location.UNLocode, deadline time.Time) (id cargo.TrackingID, err error) { defer func(begin time.Time) { s.logger.Log( "method", "book", "origin", origin, "destination", destination, "arrival_deadline", deadline, "took", time.Since(begin), "err", err, ) }(time.Now()) return s.Service.BookNewCargo(origin, destination, deadline) } func (s *loggingService) LoadCargo(id cargo.TrackingID) (c Cargo, err error) { defer func(begin time.Time) { s.logger.Log( "method", "load", "tracking_id", id, "took", time.Since(begin), "err", err, ) }(time.Now()) return s.Service.LoadCargo(id) } func (s *loggingService) RequestPossibleRoutesForCargo(id cargo.TrackingID) []cargo.Itinerary { defer func(begin time.Time) { s.logger.Log( "method", "request_routes", "tracking_id", id, "took", time.Since(begin), ) }(time.Now()) return s.Service.RequestPossibleRoutesForCargo(id) } func (s *loggingService) AssignCargoToRoute(id cargo.TrackingID, itinerary cargo.Itinerary) (err error) { defer func(begin time.Time) { s.logger.Log( "method", "assign_to_route", "tracking_id", id, "took", time.Since(begin), "err", err, ) }(time.Now()) return s.Service.AssignCargoToRoute(id, itinerary) } func (s *loggingService) ChangeDestination(id cargo.TrackingID, l location.UNLocode) (err error) { defer func(begin time.Time) { s.logger.Log( "method", "change_destination", "tracking_id", id, "destination", l, "took", time.Since(begin), "err", err, ) }(time.Now()) return s.Service.ChangeDestination(id, l) } func (s *loggingService) Cargos() []Cargo { defer func(begin time.Time) { s.logger.Log( "method", "list_cargos", "took", time.Since(begin), ) }(time.Now()) return s.Service.Cargos() } func (s *loggingService) Locations() []Location { defer func(begin time.Time) { s.logger.Log( "method", "list_locations", "took", time.Since(begin), ) }(time.Now()) return s.Service.Locations() } golang-github-go-kit-kit-0.10.0/examples/shipping/booking/service.go000066400000000000000000000121041362256312400253540ustar00rootroot00000000000000// Package booking provides the use-case of booking a cargo. Used by views // facing an administrator. package booking import ( "errors" "time" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/routing" ) // ErrInvalidArgument is returned when one or more arguments are invalid. var ErrInvalidArgument = errors.New("invalid argument") // Service is the interface that provides booking methods. type Service interface { // BookNewCargo registers a new cargo in the tracking system, not yet // routed. BookNewCargo(origin location.UNLocode, destination location.UNLocode, deadline time.Time) (cargo.TrackingID, error) // LoadCargo returns a read model of a cargo. LoadCargo(id cargo.TrackingID) (Cargo, error) // RequestPossibleRoutesForCargo requests a list of itineraries describing // possible routes for this cargo. RequestPossibleRoutesForCargo(id cargo.TrackingID) []cargo.Itinerary // AssignCargoToRoute assigns a cargo to the route specified by the // itinerary. AssignCargoToRoute(id cargo.TrackingID, itinerary cargo.Itinerary) error // ChangeDestination changes the destination of a cargo. ChangeDestination(id cargo.TrackingID, destination location.UNLocode) error // Cargos returns a list of all cargos that have been booked. Cargos() []Cargo // Locations returns a list of registered locations. Locations() []Location } type service struct { cargos cargo.Repository locations location.Repository handlingEvents cargo.HandlingEventRepository routingService routing.Service } func (s *service) AssignCargoToRoute(id cargo.TrackingID, itinerary cargo.Itinerary) error { if id == "" || len(itinerary.Legs) == 0 { return ErrInvalidArgument } c, err := s.cargos.Find(id) if err != nil { return err } c.AssignToRoute(itinerary) return s.cargos.Store(c) } func (s *service) BookNewCargo(origin, destination location.UNLocode, deadline time.Time) (cargo.TrackingID, error) { if origin == "" || destination == "" || deadline.IsZero() { return "", ErrInvalidArgument } id := cargo.NextTrackingID() rs := cargo.RouteSpecification{ Origin: origin, Destination: destination, ArrivalDeadline: deadline, } c := cargo.New(id, rs) if err := s.cargos.Store(c); err != nil { return "", err } return c.TrackingID, nil } func (s *service) LoadCargo(id cargo.TrackingID) (Cargo, error) { if id == "" { return Cargo{}, ErrInvalidArgument } c, err := s.cargos.Find(id) if err != nil { return Cargo{}, err } return assemble(c, s.handlingEvents), nil } func (s *service) ChangeDestination(id cargo.TrackingID, destination location.UNLocode) error { if id == "" || destination == "" { return ErrInvalidArgument } c, err := s.cargos.Find(id) if err != nil { return err } l, err := s.locations.Find(destination) if err != nil { return err } c.SpecifyNewRoute(cargo.RouteSpecification{ Origin: c.Origin, Destination: l.UNLocode, ArrivalDeadline: c.RouteSpecification.ArrivalDeadline, }) if err := s.cargos.Store(c); err != nil { return err } return nil } func (s *service) RequestPossibleRoutesForCargo(id cargo.TrackingID) []cargo.Itinerary { if id == "" { return nil } c, err := s.cargos.Find(id) if err != nil { return []cargo.Itinerary{} } return s.routingService.FetchRoutesForSpecification(c.RouteSpecification) } func (s *service) Cargos() []Cargo { var result []Cargo for _, c := range s.cargos.FindAll() { result = append(result, assemble(c, s.handlingEvents)) } return result } func (s *service) Locations() []Location { var result []Location for _, v := range s.locations.FindAll() { result = append(result, Location{ UNLocode: string(v.UNLocode), Name: v.Name, }) } return result } // NewService creates a booking service with necessary dependencies. func NewService(cargos cargo.Repository, locations location.Repository, events cargo.HandlingEventRepository, rs routing.Service) Service { return &service{ cargos: cargos, locations: locations, handlingEvents: events, routingService: rs, } } // Location is a read model for booking views. type Location struct { UNLocode string `json:"locode"` Name string `json:"name"` } // Cargo is a read model for booking views. type Cargo struct { ArrivalDeadline time.Time `json:"arrival_deadline"` Destination string `json:"destination"` Legs []cargo.Leg `json:"legs,omitempty"` Misrouted bool `json:"misrouted"` Origin string `json:"origin"` Routed bool `json:"routed"` TrackingID string `json:"tracking_id"` } func assemble(c *cargo.Cargo, events cargo.HandlingEventRepository) Cargo { return Cargo{ TrackingID: string(c.TrackingID), Origin: string(c.Origin), Destination: string(c.RouteSpecification.Destination), Misrouted: c.Delivery.RoutingStatus == cargo.Misrouted, Routed: !c.Itinerary.IsEmpty(), ArrivalDeadline: c.RouteSpecification.ArrivalDeadline, Legs: c.Itinerary.Legs, } } golang-github-go-kit-kit-0.10.0/examples/shipping/booking/transport.go000066400000000000000000000117671362256312400257660ustar00rootroot00000000000000package booking import ( "context" "encoding/json" "errors" "net/http" "time" "github.com/gorilla/mux" kitlog "github.com/go-kit/kit/log" "github.com/go-kit/kit/transport" kithttp "github.com/go-kit/kit/transport/http" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" ) // MakeHandler returns a handler for the booking service. func MakeHandler(bs Service, logger kitlog.Logger) http.Handler { opts := []kithttp.ServerOption{ kithttp.ServerErrorHandler(transport.NewLogErrorHandler(logger)), kithttp.ServerErrorEncoder(encodeError), } bookCargoHandler := kithttp.NewServer( makeBookCargoEndpoint(bs), decodeBookCargoRequest, encodeResponse, opts..., ) loadCargoHandler := kithttp.NewServer( makeLoadCargoEndpoint(bs), decodeLoadCargoRequest, encodeResponse, opts..., ) requestRoutesHandler := kithttp.NewServer( makeRequestRoutesEndpoint(bs), decodeRequestRoutesRequest, encodeResponse, opts..., ) assignToRouteHandler := kithttp.NewServer( makeAssignToRouteEndpoint(bs), decodeAssignToRouteRequest, encodeResponse, opts..., ) changeDestinationHandler := kithttp.NewServer( makeChangeDestinationEndpoint(bs), decodeChangeDestinationRequest, encodeResponse, opts..., ) listCargosHandler := kithttp.NewServer( makeListCargosEndpoint(bs), decodeListCargosRequest, encodeResponse, opts..., ) listLocationsHandler := kithttp.NewServer( makeListLocationsEndpoint(bs), decodeListLocationsRequest, encodeResponse, opts..., ) r := mux.NewRouter() r.Handle("/booking/v1/cargos", bookCargoHandler).Methods("POST") r.Handle("/booking/v1/cargos", listCargosHandler).Methods("GET") r.Handle("/booking/v1/cargos/{id}", loadCargoHandler).Methods("GET") r.Handle("/booking/v1/cargos/{id}/request_routes", requestRoutesHandler).Methods("GET") r.Handle("/booking/v1/cargos/{id}/assign_to_route", assignToRouteHandler).Methods("POST") r.Handle("/booking/v1/cargos/{id}/change_destination", changeDestinationHandler).Methods("POST") r.Handle("/booking/v1/locations", listLocationsHandler).Methods("GET") return r } var errBadRoute = errors.New("bad route") func decodeBookCargoRequest(_ context.Context, r *http.Request) (interface{}, error) { var body struct { Origin string `json:"origin"` Destination string `json:"destination"` ArrivalDeadline time.Time `json:"arrival_deadline"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { return nil, err } return bookCargoRequest{ Origin: location.UNLocode(body.Origin), Destination: location.UNLocode(body.Destination), ArrivalDeadline: body.ArrivalDeadline, }, nil } func decodeLoadCargoRequest(_ context.Context, r *http.Request) (interface{}, error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, errBadRoute } return loadCargoRequest{ID: cargo.TrackingID(id)}, nil } func decodeRequestRoutesRequest(_ context.Context, r *http.Request) (interface{}, error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, errBadRoute } return requestRoutesRequest{ID: cargo.TrackingID(id)}, nil } func decodeAssignToRouteRequest(_ context.Context, r *http.Request) (interface{}, error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, errBadRoute } var itinerary cargo.Itinerary if err := json.NewDecoder(r.Body).Decode(&itinerary); err != nil { return nil, err } return assignToRouteRequest{ ID: cargo.TrackingID(id), Itinerary: itinerary, }, nil } func decodeChangeDestinationRequest(_ context.Context, r *http.Request) (interface{}, error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, errBadRoute } var body struct { Destination string `json:"destination"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { return nil, err } return changeDestinationRequest{ ID: cargo.TrackingID(id), Destination: location.UNLocode(body.Destination), }, nil } func decodeListCargosRequest(_ context.Context, r *http.Request) (interface{}, error) { return listCargosRequest{}, nil } func decodeListLocationsRequest(_ context.Context, r *http.Request) (interface{}, error) { return listLocationsRequest{}, nil } func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error { if e, ok := response.(errorer); ok && e.error() != nil { encodeError(ctx, e.error(), w) return nil } w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } type errorer interface { error() error } // encode errors from business-logic func encodeError(_ context.Context, err error, w http.ResponseWriter) { w.Header().Set("Content-Type", "application/json; charset=utf-8") switch err { case cargo.ErrUnknown: w.WriteHeader(http.StatusNotFound) case ErrInvalidArgument: w.WriteHeader(http.StatusBadRequest) default: w.WriteHeader(http.StatusInternalServerError) } json.NewEncoder(w).Encode(map[string]interface{}{ "error": err.Error(), }) } golang-github-go-kit-kit-0.10.0/examples/shipping/cargo/000077500000000000000000000000001362256312400230325ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/shipping/cargo/cargo.go000066400000000000000000000065101362256312400244560ustar00rootroot00000000000000// Package cargo contains the heart of the domain model. package cargo import ( "errors" "strings" "time" "github.com/pborman/uuid" "github.com/go-kit/kit/examples/shipping/location" ) // TrackingID uniquely identifies a particular cargo. type TrackingID string // Cargo is the central class in the domain model. type Cargo struct { TrackingID TrackingID Origin location.UNLocode RouteSpecification RouteSpecification Itinerary Itinerary Delivery Delivery } // SpecifyNewRoute specifies a new route for this cargo. func (c *Cargo) SpecifyNewRoute(rs RouteSpecification) { c.RouteSpecification = rs c.Delivery = c.Delivery.UpdateOnRouting(c.RouteSpecification, c.Itinerary) } // AssignToRoute attaches a new itinerary to this cargo. func (c *Cargo) AssignToRoute(itinerary Itinerary) { c.Itinerary = itinerary c.Delivery = c.Delivery.UpdateOnRouting(c.RouteSpecification, c.Itinerary) } // DeriveDeliveryProgress updates all aspects of the cargo aggregate status // based on the current route specification, itinerary and handling of the cargo. func (c *Cargo) DeriveDeliveryProgress(history HandlingHistory) { c.Delivery = DeriveDeliveryFrom(c.RouteSpecification, c.Itinerary, history) } // New creates a new, unrouted cargo. func New(id TrackingID, rs RouteSpecification) *Cargo { itinerary := Itinerary{} history := HandlingHistory{make([]HandlingEvent, 0)} return &Cargo{ TrackingID: id, Origin: rs.Origin, RouteSpecification: rs, Delivery: DeriveDeliveryFrom(rs, itinerary, history), } } // Repository provides access a cargo store. type Repository interface { Store(cargo *Cargo) error Find(id TrackingID) (*Cargo, error) FindAll() []*Cargo } // ErrUnknown is used when a cargo could not be found. var ErrUnknown = errors.New("unknown cargo") // NextTrackingID generates a new tracking ID. // TODO: Move to infrastructure(?) func NextTrackingID() TrackingID { return TrackingID(strings.Split(strings.ToUpper(uuid.New()), "-")[0]) } // RouteSpecification Contains information about a route: its origin, // destination and arrival deadline. type RouteSpecification struct { Origin location.UNLocode Destination location.UNLocode ArrivalDeadline time.Time } // IsSatisfiedBy checks whether provided itinerary satisfies this // specification. func (s RouteSpecification) IsSatisfiedBy(itinerary Itinerary) bool { return itinerary.Legs != nil && s.Origin == itinerary.InitialDepartureLocation() && s.Destination == itinerary.FinalArrivalLocation() } // RoutingStatus describes status of cargo routing. type RoutingStatus int // Valid routing statuses. const ( NotRouted RoutingStatus = iota Misrouted Routed ) func (s RoutingStatus) String() string { switch s { case NotRouted: return "Not routed" case Misrouted: return "Misrouted" case Routed: return "Routed" } return "" } // TransportStatus describes status of cargo transportation. type TransportStatus int // Valid transport statuses. const ( NotReceived TransportStatus = iota InPort OnboardCarrier Claimed Unknown ) func (s TransportStatus) String() string { switch s { case NotReceived: return "Not received" case InPort: return "In port" case OnboardCarrier: return "Onboard carrier" case Claimed: return "Claimed" case Unknown: return "Unknown" } return "" } golang-github-go-kit-kit-0.10.0/examples/shipping/cargo/delivery.go000066400000000000000000000121561362256312400252110ustar00rootroot00000000000000package cargo import ( "time" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" ) // Delivery is the actual transportation of the cargo, as opposed to the // customer requirement (RouteSpecification) and the plan (Itinerary). type Delivery struct { Itinerary Itinerary RouteSpecification RouteSpecification RoutingStatus RoutingStatus TransportStatus TransportStatus NextExpectedActivity HandlingActivity LastEvent HandlingEvent LastKnownLocation location.UNLocode CurrentVoyage voyage.Number ETA time.Time IsMisdirected bool IsUnloadedAtDestination bool } // UpdateOnRouting creates a new delivery snapshot to reflect changes in // routing, i.e. when the route specification or the itinerary has changed but // no additional handling of the cargo has been performed. func (d Delivery) UpdateOnRouting(rs RouteSpecification, itinerary Itinerary) Delivery { return newDelivery(d.LastEvent, itinerary, rs) } // IsOnTrack checks if the delivery is on track. func (d Delivery) IsOnTrack() bool { return d.RoutingStatus == Routed && !d.IsMisdirected } // DeriveDeliveryFrom creates a new delivery snapshot based on the complete // handling history of a cargo, as well as its route specification and // itinerary. func DeriveDeliveryFrom(rs RouteSpecification, itinerary Itinerary, history HandlingHistory) Delivery { lastEvent, _ := history.MostRecentlyCompletedEvent() return newDelivery(lastEvent, itinerary, rs) } // newDelivery creates a up-to-date delivery based on an handling event, // itinerary and a route specification. func newDelivery(lastEvent HandlingEvent, itinerary Itinerary, rs RouteSpecification) Delivery { var ( routingStatus = calculateRoutingStatus(itinerary, rs) transportStatus = calculateTransportStatus(lastEvent) lastKnownLocation = calculateLastKnownLocation(lastEvent) isMisdirected = calculateMisdirectedStatus(lastEvent, itinerary) isUnloadedAtDestination = calculateUnloadedAtDestination(lastEvent, rs) currentVoyage = calculateCurrentVoyage(transportStatus, lastEvent) ) d := Delivery{ LastEvent: lastEvent, Itinerary: itinerary, RouteSpecification: rs, RoutingStatus: routingStatus, TransportStatus: transportStatus, LastKnownLocation: lastKnownLocation, IsMisdirected: isMisdirected, IsUnloadedAtDestination: isUnloadedAtDestination, CurrentVoyage: currentVoyage, } d.NextExpectedActivity = calculateNextExpectedActivity(d) d.ETA = calculateETA(d) return d } // Below are internal functions used when creating a new delivery. func calculateRoutingStatus(itinerary Itinerary, rs RouteSpecification) RoutingStatus { if itinerary.Legs == nil { return NotRouted } if rs.IsSatisfiedBy(itinerary) { return Routed } return Misrouted } func calculateMisdirectedStatus(event HandlingEvent, itinerary Itinerary) bool { if event.Activity.Type == NotHandled { return false } return !itinerary.IsExpected(event) } func calculateUnloadedAtDestination(event HandlingEvent, rs RouteSpecification) bool { if event.Activity.Type == NotHandled { return false } return event.Activity.Type == Unload && rs.Destination == event.Activity.Location } func calculateTransportStatus(event HandlingEvent) TransportStatus { switch event.Activity.Type { case NotHandled: return NotReceived case Load: return OnboardCarrier case Unload: return InPort case Receive: return InPort case Customs: return InPort case Claim: return Claimed } return Unknown } func calculateLastKnownLocation(event HandlingEvent) location.UNLocode { return event.Activity.Location } func calculateNextExpectedActivity(d Delivery) HandlingActivity { if !d.IsOnTrack() { return HandlingActivity{} } switch d.LastEvent.Activity.Type { case NotHandled: return HandlingActivity{Type: Receive, Location: d.RouteSpecification.Origin} case Receive: l := d.Itinerary.Legs[0] return HandlingActivity{Type: Load, Location: l.LoadLocation, VoyageNumber: l.VoyageNumber} case Load: for _, l := range d.Itinerary.Legs { if l.LoadLocation == d.LastEvent.Activity.Location { return HandlingActivity{Type: Unload, Location: l.UnloadLocation, VoyageNumber: l.VoyageNumber} } } case Unload: for i, l := range d.Itinerary.Legs { if l.UnloadLocation == d.LastEvent.Activity.Location { if i < len(d.Itinerary.Legs)-1 { return HandlingActivity{Type: Load, Location: d.Itinerary.Legs[i+1].LoadLocation, VoyageNumber: d.Itinerary.Legs[i+1].VoyageNumber} } return HandlingActivity{Type: Claim, Location: l.UnloadLocation} } } } return HandlingActivity{} } func calculateCurrentVoyage(transportStatus TransportStatus, event HandlingEvent) voyage.Number { if transportStatus == OnboardCarrier && event.Activity.Type != NotHandled { return event.Activity.VoyageNumber } return voyage.Number("") } func calculateETA(d Delivery) time.Time { if !d.IsOnTrack() { return time.Time{} } return d.Itinerary.FinalArrivalTime() } golang-github-go-kit-kit-0.10.0/examples/shipping/cargo/handling.go000066400000000000000000000062671362256312400251600ustar00rootroot00000000000000package cargo // TODO: It would make sense to have this in its own package. Unfortunately, // then there would be a circular dependency between the cargo and handling // packages since cargo.Delivery would use handling.HandlingEvent and // handling.HandlingEvent would use cargo.TrackingID. Also, // HandlingEventFactory depends on the cargo repository. // // It would make sense not having the cargo package depend on handling. import ( "errors" "time" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" ) // HandlingActivity represents how and where a cargo can be handled, and can // be used to express predictions about what is expected to happen to a cargo // in the future. type HandlingActivity struct { Type HandlingEventType Location location.UNLocode VoyageNumber voyage.Number } // HandlingEvent is used to register the event when, for instance, a cargo is // unloaded from a carrier at a some location at a given time. type HandlingEvent struct { TrackingID TrackingID Activity HandlingActivity } // HandlingEventType describes type of a handling event. type HandlingEventType int // Valid handling event types. const ( NotHandled HandlingEventType = iota Load Unload Receive Claim Customs ) func (t HandlingEventType) String() string { switch t { case NotHandled: return "Not Handled" case Load: return "Load" case Unload: return "Unload" case Receive: return "Receive" case Claim: return "Claim" case Customs: return "Customs" } return "" } // HandlingHistory is the handling history of a cargo. type HandlingHistory struct { HandlingEvents []HandlingEvent } // MostRecentlyCompletedEvent returns most recently completed handling event. func (h HandlingHistory) MostRecentlyCompletedEvent() (HandlingEvent, error) { if len(h.HandlingEvents) == 0 { return HandlingEvent{}, errors.New("delivery history is empty") } return h.HandlingEvents[len(h.HandlingEvents)-1], nil } // HandlingEventRepository provides access a handling event store. type HandlingEventRepository interface { Store(e HandlingEvent) QueryHandlingHistory(TrackingID) HandlingHistory } // HandlingEventFactory creates handling events. type HandlingEventFactory struct { CargoRepository Repository VoyageRepository voyage.Repository LocationRepository location.Repository } // CreateHandlingEvent creates a validated handling event. func (f *HandlingEventFactory) CreateHandlingEvent(registered time.Time, completed time.Time, id TrackingID, voyageNumber voyage.Number, unLocode location.UNLocode, eventType HandlingEventType) (HandlingEvent, error) { if _, err := f.CargoRepository.Find(id); err != nil { return HandlingEvent{}, err } if _, err := f.VoyageRepository.Find(voyageNumber); err != nil { // TODO: This is pretty ugly, but when creating a Receive event, the voyage number is not known. if len(voyageNumber) > 0 { return HandlingEvent{}, err } } if _, err := f.LocationRepository.Find(unLocode); err != nil { return HandlingEvent{}, err } return HandlingEvent{ TrackingID: id, Activity: HandlingActivity{ Type: eventType, Location: unLocode, VoyageNumber: voyageNumber, }, }, nil } golang-github-go-kit-kit-0.10.0/examples/shipping/cargo/itinerary.go000066400000000000000000000046611362256312400253760ustar00rootroot00000000000000package cargo import ( "time" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" ) // Leg describes the transportation between two locations on a voyage. type Leg struct { VoyageNumber voyage.Number `json:"voyage_number"` LoadLocation location.UNLocode `json:"from"` UnloadLocation location.UNLocode `json:"to"` LoadTime time.Time `json:"load_time"` UnloadTime time.Time `json:"unload_time"` } // NewLeg creates a new itinerary leg. func NewLeg(voyageNumber voyage.Number, loadLocation, unloadLocation location.UNLocode, loadTime, unloadTime time.Time) Leg { return Leg{ VoyageNumber: voyageNumber, LoadLocation: loadLocation, UnloadLocation: unloadLocation, LoadTime: loadTime, UnloadTime: unloadTime, } } // Itinerary specifies steps required to transport a cargo from its origin to // destination. type Itinerary struct { Legs []Leg `json:"legs"` } // InitialDepartureLocation returns the start of the itinerary. func (i Itinerary) InitialDepartureLocation() location.UNLocode { if i.IsEmpty() { return location.UNLocode("") } return i.Legs[0].LoadLocation } // FinalArrivalLocation returns the end of the itinerary. func (i Itinerary) FinalArrivalLocation() location.UNLocode { if i.IsEmpty() { return location.UNLocode("") } return i.Legs[len(i.Legs)-1].UnloadLocation } // FinalArrivalTime returns the expected arrival time at final destination. func (i Itinerary) FinalArrivalTime() time.Time { return i.Legs[len(i.Legs)-1].UnloadTime } // IsEmpty checks if the itinerary contains at least one leg. func (i Itinerary) IsEmpty() bool { return i.Legs == nil || len(i.Legs) == 0 } // IsExpected checks if the given handling event is expected when executing // this itinerary. func (i Itinerary) IsExpected(event HandlingEvent) bool { if i.IsEmpty() { return true } switch event.Activity.Type { case Receive: return i.InitialDepartureLocation() == event.Activity.Location case Load: for _, l := range i.Legs { if l.LoadLocation == event.Activity.Location && l.VoyageNumber == event.Activity.VoyageNumber { return true } } return false case Unload: for _, l := range i.Legs { if l.UnloadLocation == event.Activity.Location && l.VoyageNumber == event.Activity.VoyageNumber { return true } } return false case Claim: return i.FinalArrivalLocation() == event.Activity.Location } return true } golang-github-go-kit-kit-0.10.0/examples/shipping/handling/000077500000000000000000000000001362256312400235235ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/shipping/handling/endpoint.go000066400000000000000000000016401362256312400256730ustar00rootroot00000000000000package handling import ( "context" "time" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" ) type registerIncidentRequest struct { ID cargo.TrackingID Location location.UNLocode Voyage voyage.Number EventType cargo.HandlingEventType CompletionTime time.Time } type registerIncidentResponse struct { Err error `json:"error,omitempty"` } func (r registerIncidentResponse) error() error { return r.Err } func makeRegisterIncidentEndpoint(hs Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(registerIncidentRequest) err := hs.RegisterHandlingEvent(req.CompletionTime, req.ID, req.Voyage, req.Location, req.EventType) return registerIncidentResponse{Err: err}, nil } } golang-github-go-kit-kit-0.10.0/examples/shipping/handling/instrumenting.go000066400000000000000000000021201362256312400267530ustar00rootroot00000000000000package handling import ( "time" "github.com/go-kit/kit/metrics" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" ) type instrumentingService struct { requestCount metrics.Counter requestLatency metrics.Histogram Service } // NewInstrumentingService returns an instance of an instrumenting Service. func NewInstrumentingService(counter metrics.Counter, latency metrics.Histogram, s Service) Service { return &instrumentingService{ requestCount: counter, requestLatency: latency, Service: s, } } func (s *instrumentingService) RegisterHandlingEvent(completed time.Time, id cargo.TrackingID, voyageNumber voyage.Number, loc location.UNLocode, eventType cargo.HandlingEventType) error { defer func(begin time.Time) { s.requestCount.With("method", "register_incident").Add(1) s.requestLatency.With("method", "register_incident").Observe(time.Since(begin).Seconds()) }(time.Now()) return s.Service.RegisterHandlingEvent(completed, id, voyageNumber, loc, eventType) } golang-github-go-kit-kit-0.10.0/examples/shipping/handling/logging.go000066400000000000000000000017661362256312400255120ustar00rootroot00000000000000package handling import ( "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" ) type loggingService struct { logger log.Logger Service } // NewLoggingService returns a new instance of a logging Service. func NewLoggingService(logger log.Logger, s Service) Service { return &loggingService{logger, s} } func (s *loggingService) RegisterHandlingEvent(completed time.Time, id cargo.TrackingID, voyageNumber voyage.Number, unLocode location.UNLocode, eventType cargo.HandlingEventType) (err error) { defer func(begin time.Time) { s.logger.Log( "method", "register_incident", "tracking_id", id, "location", unLocode, "voyage", voyageNumber, "event_type", eventType, "completion_time", completed, "took", time.Since(begin), "err", err, ) }(time.Now()) return s.Service.RegisterHandlingEvent(completed, id, voyageNumber, unLocode, eventType) } golang-github-go-kit-kit-0.10.0/examples/shipping/handling/service.go000066400000000000000000000045721362256312400255220ustar00rootroot00000000000000// Package handling provides the use-case for registering incidents. Used by // views facing the people handling the cargo along its route. package handling import ( "errors" "time" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/inspection" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" ) // ErrInvalidArgument is returned when one or more arguments are invalid. var ErrInvalidArgument = errors.New("invalid argument") // EventHandler provides a means of subscribing to registered handling events. type EventHandler interface { CargoWasHandled(cargo.HandlingEvent) } // Service provides handling operations. type Service interface { // RegisterHandlingEvent registers a handling event in the system, and // notifies interested parties that a cargo has been handled. RegisterHandlingEvent(completed time.Time, id cargo.TrackingID, voyageNumber voyage.Number, unLocode location.UNLocode, eventType cargo.HandlingEventType) error } type service struct { handlingEventRepository cargo.HandlingEventRepository handlingEventFactory cargo.HandlingEventFactory handlingEventHandler EventHandler } func (s *service) RegisterHandlingEvent(completed time.Time, id cargo.TrackingID, voyageNumber voyage.Number, loc location.UNLocode, eventType cargo.HandlingEventType) error { if completed.IsZero() || id == "" || loc == "" || eventType == cargo.NotHandled { return ErrInvalidArgument } e, err := s.handlingEventFactory.CreateHandlingEvent(time.Now(), completed, id, voyageNumber, loc, eventType) if err != nil { return err } s.handlingEventRepository.Store(e) s.handlingEventHandler.CargoWasHandled(e) return nil } // NewService creates a handling event service with necessary dependencies. func NewService(r cargo.HandlingEventRepository, f cargo.HandlingEventFactory, h EventHandler) Service { return &service{ handlingEventRepository: r, handlingEventFactory: f, handlingEventHandler: h, } } type handlingEventHandler struct { InspectionService inspection.Service } func (h *handlingEventHandler) CargoWasHandled(event cargo.HandlingEvent) { h.InspectionService.InspectCargo(event.TrackingID) } // NewEventHandler returns a new instance of a EventHandler. func NewEventHandler(s inspection.Service) EventHandler { return &handlingEventHandler{ InspectionService: s, } } golang-github-go-kit-kit-0.10.0/examples/shipping/handling/transport.go000066400000000000000000000053421362256312400261120ustar00rootroot00000000000000package handling import ( "context" "encoding/json" "net/http" "time" "github.com/gorilla/mux" kitlog "github.com/go-kit/kit/log" "github.com/go-kit/kit/transport" kithttp "github.com/go-kit/kit/transport/http" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" ) // MakeHandler returns a handler for the handling service. func MakeHandler(hs Service, logger kitlog.Logger) http.Handler { r := mux.NewRouter() opts := []kithttp.ServerOption{ kithttp.ServerErrorHandler(transport.NewLogErrorHandler(logger)), kithttp.ServerErrorEncoder(encodeError), } registerIncidentHandler := kithttp.NewServer( makeRegisterIncidentEndpoint(hs), decodeRegisterIncidentRequest, encodeResponse, opts..., ) r.Handle("/handling/v1/incidents", registerIncidentHandler).Methods("POST") return r } func decodeRegisterIncidentRequest(_ context.Context, r *http.Request) (interface{}, error) { var body struct { CompletionTime time.Time `json:"completion_time"` TrackingID string `json:"tracking_id"` VoyageNumber string `json:"voyage"` Location string `json:"location"` EventType string `json:"event_type"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { return nil, err } return registerIncidentRequest{ CompletionTime: body.CompletionTime, ID: cargo.TrackingID(body.TrackingID), Voyage: voyage.Number(body.VoyageNumber), Location: location.UNLocode(body.Location), EventType: stringToEventType(body.EventType), }, nil } func stringToEventType(s string) cargo.HandlingEventType { types := map[string]cargo.HandlingEventType{ cargo.Receive.String(): cargo.Receive, cargo.Load.String(): cargo.Load, cargo.Unload.String(): cargo.Unload, cargo.Customs.String(): cargo.Customs, cargo.Claim.String(): cargo.Claim, } return types[s] } func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error { if e, ok := response.(errorer); ok && e.error() != nil { encodeError(ctx, e.error(), w) return nil } w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } type errorer interface { error() error } // encode errors from business-logic func encodeError(_ context.Context, err error, w http.ResponseWriter) { w.Header().Set("Content-Type", "application/json; charset=utf-8") switch err { case cargo.ErrUnknown: w.WriteHeader(http.StatusNotFound) case ErrInvalidArgument: w.WriteHeader(http.StatusBadRequest) default: w.WriteHeader(http.StatusInternalServerError) } json.NewEncoder(w).Encode(map[string]interface{}{ "error": err.Error(), }) } golang-github-go-kit-kit-0.10.0/examples/shipping/inmem/000077500000000000000000000000001362256312400230445ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/shipping/inmem/inmem.go000066400000000000000000000074421362256312400245070ustar00rootroot00000000000000// Package inmem provides in-memory implementations of all the domain repositories. package inmem import ( "sync" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" ) type cargoRepository struct { mtx sync.RWMutex cargos map[cargo.TrackingID]*cargo.Cargo } func (r *cargoRepository) Store(c *cargo.Cargo) error { r.mtx.Lock() defer r.mtx.Unlock() r.cargos[c.TrackingID] = c return nil } func (r *cargoRepository) Find(id cargo.TrackingID) (*cargo.Cargo, error) { r.mtx.RLock() defer r.mtx.RUnlock() if val, ok := r.cargos[id]; ok { return val, nil } return nil, cargo.ErrUnknown } func (r *cargoRepository) FindAll() []*cargo.Cargo { r.mtx.RLock() defer r.mtx.RUnlock() c := make([]*cargo.Cargo, 0, len(r.cargos)) for _, val := range r.cargos { c = append(c, val) } return c } // NewCargoRepository returns a new instance of a in-memory cargo repository. func NewCargoRepository() cargo.Repository { return &cargoRepository{ cargos: make(map[cargo.TrackingID]*cargo.Cargo), } } type locationRepository struct { locations map[location.UNLocode]*location.Location } func (r *locationRepository) Find(locode location.UNLocode) (*location.Location, error) { if l, ok := r.locations[locode]; ok { return l, nil } return nil, location.ErrUnknown } func (r *locationRepository) FindAll() []*location.Location { l := make([]*location.Location, 0, len(r.locations)) for _, val := range r.locations { l = append(l, val) } return l } // NewLocationRepository returns a new instance of a in-memory location repository. func NewLocationRepository() location.Repository { r := &locationRepository{ locations: make(map[location.UNLocode]*location.Location), } r.locations[location.SESTO] = location.Stockholm r.locations[location.AUMEL] = location.Melbourne r.locations[location.CNHKG] = location.Hongkong r.locations[location.JNTKO] = location.Tokyo r.locations[location.NLRTM] = location.Rotterdam r.locations[location.DEHAM] = location.Hamburg return r } type voyageRepository struct { voyages map[voyage.Number]*voyage.Voyage } func (r *voyageRepository) Find(voyageNumber voyage.Number) (*voyage.Voyage, error) { if v, ok := r.voyages[voyageNumber]; ok { return v, nil } return nil, voyage.ErrUnknown } // NewVoyageRepository returns a new instance of a in-memory voyage repository. func NewVoyageRepository() voyage.Repository { r := &voyageRepository{ voyages: make(map[voyage.Number]*voyage.Voyage), } r.voyages[voyage.V100.Number] = voyage.V100 r.voyages[voyage.V300.Number] = voyage.V300 r.voyages[voyage.V400.Number] = voyage.V400 r.voyages[voyage.V0100S.Number] = voyage.V0100S r.voyages[voyage.V0200T.Number] = voyage.V0200T r.voyages[voyage.V0300A.Number] = voyage.V0300A r.voyages[voyage.V0301S.Number] = voyage.V0301S r.voyages[voyage.V0400S.Number] = voyage.V0400S return r } type handlingEventRepository struct { mtx sync.RWMutex events map[cargo.TrackingID][]cargo.HandlingEvent } func (r *handlingEventRepository) Store(e cargo.HandlingEvent) { r.mtx.Lock() defer r.mtx.Unlock() // Make array if it's the first event with this tracking ID. if _, ok := r.events[e.TrackingID]; !ok { r.events[e.TrackingID] = make([]cargo.HandlingEvent, 0) } r.events[e.TrackingID] = append(r.events[e.TrackingID], e) } func (r *handlingEventRepository) QueryHandlingHistory(id cargo.TrackingID) cargo.HandlingHistory { r.mtx.RLock() defer r.mtx.RUnlock() return cargo.HandlingHistory{HandlingEvents: r.events[id]} } // NewHandlingEventRepository returns a new instance of a in-memory handling event repository. func NewHandlingEventRepository() cargo.HandlingEventRepository { return &handlingEventRepository{ events: make(map[cargo.TrackingID][]cargo.HandlingEvent), } } golang-github-go-kit-kit-0.10.0/examples/shipping/inspection/000077500000000000000000000000001362256312400241125ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/shipping/inspection/inspection.go000066400000000000000000000024461362256312400266220ustar00rootroot00000000000000// Package inspection provides means to inspect cargos. package inspection import ( "github.com/go-kit/kit/examples/shipping/cargo" ) // EventHandler provides means of subscribing to inspection events. type EventHandler interface { CargoWasMisdirected(*cargo.Cargo) CargoHasArrived(*cargo.Cargo) } // Service provides cargo inspection operations. type Service interface { // InspectCargo inspects cargo and send relevant notifications to // interested parties, for example if a cargo has been misdirected, or // unloaded at the final destination. InspectCargo(id cargo.TrackingID) } type service struct { cargos cargo.Repository events cargo.HandlingEventRepository handler EventHandler } // TODO: Should be transactional func (s *service) InspectCargo(id cargo.TrackingID) { c, err := s.cargos.Find(id) if err != nil { return } h := s.events.QueryHandlingHistory(id) c.DeriveDeliveryProgress(h) if c.Delivery.IsMisdirected { s.handler.CargoWasMisdirected(c) } if c.Delivery.IsUnloadedAtDestination { s.handler.CargoHasArrived(c) } s.cargos.Store(c) } // NewService creates a inspection service with necessary dependencies. func NewService(cargos cargo.Repository, events cargo.HandlingEventRepository, handler EventHandler) Service { return &service{cargos, events, handler} } golang-github-go-kit-kit-0.10.0/examples/shipping/location/000077500000000000000000000000001362256312400235475ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/shipping/location/location.go000066400000000000000000000014031362256312400257040ustar00rootroot00000000000000// Package location provides the Location aggregate. package location import ( "errors" ) // UNLocode is the United Nations location code that uniquely identifies a // particular location. // // http://www.unece.org/cefact/locode/ // http://www.unece.org/cefact/locode/DocColumnDescription.htm#LOCODE type UNLocode string // Location is a location is our model is stops on a journey, such as cargo // origin or destination, or carrier movement endpoints. type Location struct { UNLocode UNLocode Name string } // ErrUnknown is used when a location could not be found. var ErrUnknown = errors.New("unknown location") // Repository provides access a location store. type Repository interface { Find(locode UNLocode) (*Location, error) FindAll() []*Location } golang-github-go-kit-kit-0.10.0/examples/shipping/location/sample_locations.go000066400000000000000000000012601362256312400274310ustar00rootroot00000000000000package location // Sample UN locodes. var ( SESTO UNLocode = "SESTO" AUMEL UNLocode = "AUMEL" CNHKG UNLocode = "CNHKG" USNYC UNLocode = "USNYC" USCHI UNLocode = "USCHI" JNTKO UNLocode = "JNTKO" DEHAM UNLocode = "DEHAM" NLRTM UNLocode = "NLRTM" FIHEL UNLocode = "FIHEL" ) // Sample locations. var ( Stockholm = &Location{SESTO, "Stockholm"} Melbourne = &Location{AUMEL, "Melbourne"} Hongkong = &Location{CNHKG, "Hongkong"} NewYork = &Location{USNYC, "New York"} Chicago = &Location{USCHI, "Chicago"} Tokyo = &Location{JNTKO, "Tokyo"} Hamburg = &Location{DEHAM, "Hamburg"} Rotterdam = &Location{NLRTM, "Rotterdam"} Helsinki = &Location{FIHEL, "Helsinki"} ) golang-github-go-kit-kit-0.10.0/examples/shipping/main.go000066400000000000000000000131361362256312400232160ustar00rootroot00000000000000package main import ( "context" "flag" "fmt" "net/http" "os" "os/signal" "syscall" "time" stdprometheus "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/go-kit/kit/log" kitprometheus "github.com/go-kit/kit/metrics/prometheus" "github.com/go-kit/kit/examples/shipping/booking" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/handling" "github.com/go-kit/kit/examples/shipping/inmem" "github.com/go-kit/kit/examples/shipping/inspection" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/routing" "github.com/go-kit/kit/examples/shipping/tracking" ) const ( defaultPort = "8080" defaultRoutingServiceURL = "http://localhost:7878" ) func main() { var ( addr = envString("PORT", defaultPort) rsurl = envString("ROUTINGSERVICE_URL", defaultRoutingServiceURL) httpAddr = flag.String("http.addr", ":"+addr, "HTTP listen address") routingServiceURL = flag.String("service.routing", rsurl, "routing service URL") ctx = context.Background() ) flag.Parse() var logger log.Logger logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) logger = log.With(logger, "ts", log.DefaultTimestampUTC) var ( cargos = inmem.NewCargoRepository() locations = inmem.NewLocationRepository() voyages = inmem.NewVoyageRepository() handlingEvents = inmem.NewHandlingEventRepository() ) // Configure some questionable dependencies. var ( handlingEventFactory = cargo.HandlingEventFactory{ CargoRepository: cargos, VoyageRepository: voyages, LocationRepository: locations, } handlingEventHandler = handling.NewEventHandler( inspection.NewService(cargos, handlingEvents, nil), ) ) // Facilitate testing by adding some cargos. storeTestData(cargos) fieldKeys := []string{"method"} var rs routing.Service rs = routing.NewProxyingMiddleware(ctx, *routingServiceURL)(rs) var bs booking.Service bs = booking.NewService(cargos, locations, handlingEvents, rs) bs = booking.NewLoggingService(log.With(logger, "component", "booking"), bs) bs = booking.NewInstrumentingService( kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{ Namespace: "api", Subsystem: "booking_service", Name: "request_count", Help: "Number of requests received.", }, fieldKeys), kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{ Namespace: "api", Subsystem: "booking_service", Name: "request_latency_microseconds", Help: "Total duration of requests in microseconds.", }, fieldKeys), bs, ) var ts tracking.Service ts = tracking.NewService(cargos, handlingEvents) ts = tracking.NewLoggingService(log.With(logger, "component", "tracking"), ts) ts = tracking.NewInstrumentingService( kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{ Namespace: "api", Subsystem: "tracking_service", Name: "request_count", Help: "Number of requests received.", }, fieldKeys), kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{ Namespace: "api", Subsystem: "tracking_service", Name: "request_latency_microseconds", Help: "Total duration of requests in microseconds.", }, fieldKeys), ts, ) var hs handling.Service hs = handling.NewService(handlingEvents, handlingEventFactory, handlingEventHandler) hs = handling.NewLoggingService(log.With(logger, "component", "handling"), hs) hs = handling.NewInstrumentingService( kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{ Namespace: "api", Subsystem: "handling_service", Name: "request_count", Help: "Number of requests received.", }, fieldKeys), kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{ Namespace: "api", Subsystem: "handling_service", Name: "request_latency_microseconds", Help: "Total duration of requests in microseconds.", }, fieldKeys), hs, ) httpLogger := log.With(logger, "component", "http") mux := http.NewServeMux() mux.Handle("/booking/v1/", booking.MakeHandler(bs, httpLogger)) mux.Handle("/tracking/v1/", tracking.MakeHandler(ts, httpLogger)) mux.Handle("/handling/v1/", handling.MakeHandler(hs, httpLogger)) http.Handle("/", accessControl(mux)) http.Handle("/metrics", promhttp.Handler()) errs := make(chan error, 2) go func() { logger.Log("transport", "http", "address", *httpAddr, "msg", "listening") errs <- http.ListenAndServe(*httpAddr, nil) }() go func() { c := make(chan os.Signal) signal.Notify(c, syscall.SIGINT) errs <- fmt.Errorf("%s", <-c) }() logger.Log("terminated", <-errs) } func accessControl(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type") if r.Method == "OPTIONS" { return } h.ServeHTTP(w, r) }) } func envString(env, fallback string) string { e := os.Getenv(env) if e == "" { return fallback } return e } func storeTestData(r cargo.Repository) { test1 := cargo.New("FTL456", cargo.RouteSpecification{ Origin: location.AUMEL, Destination: location.SESTO, ArrivalDeadline: time.Now().AddDate(0, 0, 7), }) if err := r.Store(test1); err != nil { panic(err) } test2 := cargo.New("ABC123", cargo.RouteSpecification{ Origin: location.SESTO, Destination: location.CNHKG, ArrivalDeadline: time.Now().AddDate(0, 0, 14), }) if err := r.Store(test2); err != nil { panic(err) } } golang-github-go-kit-kit-0.10.0/examples/shipping/routing/000077500000000000000000000000001362256312400234265ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/shipping/routing/proxying.go000066400000000000000000000055371362256312400256460ustar00rootroot00000000000000package routing import ( "context" "encoding/json" "net/http" "net/url" "time" "github.com/go-kit/kit/circuitbreaker" "github.com/go-kit/kit/endpoint" kithttp "github.com/go-kit/kit/transport/http" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" ) type proxyService struct { context.Context FetchRoutesEndpoint endpoint.Endpoint Service } func (s proxyService) FetchRoutesForSpecification(rs cargo.RouteSpecification) []cargo.Itinerary { response, err := s.FetchRoutesEndpoint(s.Context, fetchRoutesRequest{ From: string(rs.Origin), To: string(rs.Destination), }) if err != nil { return []cargo.Itinerary{} } resp := response.(fetchRoutesResponse) var itineraries []cargo.Itinerary for _, r := range resp.Paths { var legs []cargo.Leg for _, e := range r.Edges { legs = append(legs, cargo.Leg{ VoyageNumber: voyage.Number(e.Voyage), LoadLocation: location.UNLocode(e.Origin), UnloadLocation: location.UNLocode(e.Destination), LoadTime: e.Departure, UnloadTime: e.Arrival, }) } itineraries = append(itineraries, cargo.Itinerary{Legs: legs}) } return itineraries } // ServiceMiddleware defines a middleware for a routing service. type ServiceMiddleware func(Service) Service // NewProxyingMiddleware returns a new instance of a proxying middleware. func NewProxyingMiddleware(ctx context.Context, proxyURL string) ServiceMiddleware { return func(next Service) Service { var e endpoint.Endpoint e = makeFetchRoutesEndpoint(ctx, proxyURL) e = circuitbreaker.Hystrix("fetch-routes")(e) return proxyService{ctx, e, next} } } type fetchRoutesRequest struct { From string To string } type fetchRoutesResponse struct { Paths []struct { Edges []struct { Origin string `json:"origin"` Destination string `json:"destination"` Voyage string `json:"voyage"` Departure time.Time `json:"departure"` Arrival time.Time `json:"arrival"` } `json:"edges"` } `json:"paths"` } func makeFetchRoutesEndpoint(ctx context.Context, instance string) endpoint.Endpoint { u, err := url.Parse(instance) if err != nil { panic(err) } if u.Path == "" { u.Path = "/paths" } return kithttp.NewClient( "GET", u, encodeFetchRoutesRequest, decodeFetchRoutesResponse, ).Endpoint() } func decodeFetchRoutesResponse(_ context.Context, resp *http.Response) (interface{}, error) { var response fetchRoutesResponse if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { return nil, err } return response, nil } func encodeFetchRoutesRequest(_ context.Context, r *http.Request, request interface{}) error { req := request.(fetchRoutesRequest) vals := r.URL.Query() vals.Add("from", req.From) vals.Add("to", req.To) r.URL.RawQuery = vals.Encode() return nil } golang-github-go-kit-kit-0.10.0/examples/shipping/routing/routing.go000066400000000000000000000007761362256312400254560ustar00rootroot00000000000000// Package routing provides the routing domain service. It does not actually // implement the routing service but merely acts as a proxy for a separate // bounded context. package routing import ( "github.com/go-kit/kit/examples/shipping/cargo" ) // Service provides access to an external routing service. type Service interface { // FetchRoutesForSpecification finds all possible routes that satisfy a // given specification. FetchRoutesForSpecification(rs cargo.RouteSpecification) []cargo.Itinerary } golang-github-go-kit-kit-0.10.0/examples/shipping/tracking/000077500000000000000000000000001362256312400235415ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/shipping/tracking/endpoint.go000066400000000000000000000010571362256312400257130ustar00rootroot00000000000000package tracking import ( "context" "github.com/go-kit/kit/endpoint" ) type trackCargoRequest struct { ID string } type trackCargoResponse struct { Cargo *Cargo `json:"cargo,omitempty"` Err error `json:"error,omitempty"` } func (r trackCargoResponse) error() error { return r.Err } func makeTrackCargoEndpoint(ts Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(trackCargoRequest) c, err := ts.Track(req.ID) return trackCargoResponse{Cargo: &c, Err: err}, nil } } golang-github-go-kit-kit-0.10.0/examples/shipping/tracking/instrumenting.go000066400000000000000000000013511362256312400267760ustar00rootroot00000000000000package tracking import ( "time" "github.com/go-kit/kit/metrics" ) type instrumentingService struct { requestCount metrics.Counter requestLatency metrics.Histogram Service } // NewInstrumentingService returns an instance of an instrumenting Service. func NewInstrumentingService(counter metrics.Counter, latency metrics.Histogram, s Service) Service { return &instrumentingService{ requestCount: counter, requestLatency: latency, Service: s, } } func (s *instrumentingService) Track(id string) (Cargo, error) { defer func(begin time.Time) { s.requestCount.With("method", "track").Add(1) s.requestLatency.With("method", "track").Observe(time.Since(begin).Seconds()) }(time.Now()) return s.Service.Track(id) } golang-github-go-kit-kit-0.10.0/examples/shipping/tracking/logging.go000066400000000000000000000010201362256312400255070ustar00rootroot00000000000000package tracking import ( "time" "github.com/go-kit/kit/log" ) type loggingService struct { logger log.Logger Service } // NewLoggingService returns a new instance of a logging Service. func NewLoggingService(logger log.Logger, s Service) Service { return &loggingService{logger, s} } func (s *loggingService) Track(id string) (c Cargo, err error) { defer func(begin time.Time) { s.logger.Log("method", "track", "tracking_id", id, "took", time.Since(begin), "err", err) }(time.Now()) return s.Service.Track(id) } golang-github-go-kit-kit-0.10.0/examples/shipping/tracking/service.go000066400000000000000000000120011362256312400255220ustar00rootroot00000000000000// Package tracking provides the use-case of tracking a cargo. Used by views // facing the end-user. package tracking import ( "errors" "fmt" "strings" "time" "github.com/go-kit/kit/examples/shipping/cargo" ) // ErrInvalidArgument is returned when one or more arguments are invalid. var ErrInvalidArgument = errors.New("invalid argument") // Service is the interface that provides the basic Track method. type Service interface { // Track returns a cargo matching a tracking ID. Track(id string) (Cargo, error) } type service struct { cargos cargo.Repository handlingEvents cargo.HandlingEventRepository } func (s *service) Track(id string) (Cargo, error) { if id == "" { return Cargo{}, ErrInvalidArgument } c, err := s.cargos.Find(cargo.TrackingID(id)) if err != nil { return Cargo{}, err } return assemble(c, s.handlingEvents), nil } // NewService returns a new instance of the default Service. func NewService(cargos cargo.Repository, events cargo.HandlingEventRepository) Service { return &service{ cargos: cargos, handlingEvents: events, } } // Cargo is a read model for tracking views. type Cargo struct { TrackingID string `json:"tracking_id"` StatusText string `json:"status_text"` Origin string `json:"origin"` Destination string `json:"destination"` ETA time.Time `json:"eta"` NextExpectedActivity string `json:"next_expected_activity"` ArrivalDeadline time.Time `json:"arrival_deadline"` Events []Event `json:"events"` } // Leg is a read model for booking views. type Leg struct { VoyageNumber string `json:"voyage_number"` From string `json:"from"` To string `json:"to"` LoadTime time.Time `json:"load_time"` UnloadTime time.Time `json:"unload_time"` } // Event is a read model for tracking views. type Event struct { Description string `json:"description"` Expected bool `json:"expected"` } func assemble(c *cargo.Cargo, events cargo.HandlingEventRepository) Cargo { return Cargo{ TrackingID: string(c.TrackingID), Origin: string(c.Origin), Destination: string(c.RouteSpecification.Destination), ETA: c.Delivery.ETA, NextExpectedActivity: nextExpectedActivity(c), ArrivalDeadline: c.RouteSpecification.ArrivalDeadline, StatusText: assembleStatusText(c), Events: assembleEvents(c, events), } } func assembleLegs(c cargo.Cargo) []Leg { var legs []Leg for _, l := range c.Itinerary.Legs { legs = append(legs, Leg{ VoyageNumber: string(l.VoyageNumber), From: string(l.LoadLocation), To: string(l.UnloadLocation), LoadTime: l.LoadTime, UnloadTime: l.UnloadTime, }) } return legs } func nextExpectedActivity(c *cargo.Cargo) string { a := c.Delivery.NextExpectedActivity prefix := "Next expected activity is to" switch a.Type { case cargo.Load: return fmt.Sprintf("%s %s cargo onto voyage %s in %s.", prefix, strings.ToLower(a.Type.String()), a.VoyageNumber, a.Location) case cargo.Unload: return fmt.Sprintf("%s %s cargo off of voyage %s in %s.", prefix, strings.ToLower(a.Type.String()), a.VoyageNumber, a.Location) case cargo.NotHandled: return "There are currently no expected activities for this cargo." } return fmt.Sprintf("%s %s cargo in %s.", prefix, strings.ToLower(a.Type.String()), a.Location) } func assembleStatusText(c *cargo.Cargo) string { switch c.Delivery.TransportStatus { case cargo.NotReceived: return "Not received" case cargo.InPort: return fmt.Sprintf("In port %s", c.Delivery.LastKnownLocation) case cargo.OnboardCarrier: return fmt.Sprintf("Onboard voyage %s", c.Delivery.CurrentVoyage) case cargo.Claimed: return "Claimed" default: return "Unknown" } } func assembleEvents(c *cargo.Cargo, handlingEvents cargo.HandlingEventRepository) []Event { h := handlingEvents.QueryHandlingHistory(c.TrackingID) var events []Event for _, e := range h.HandlingEvents { var description string switch e.Activity.Type { case cargo.NotHandled: description = "Cargo has not yet been received." case cargo.Receive: description = fmt.Sprintf("Received in %s, at %s", e.Activity.Location, time.Now().Format(time.RFC3339)) case cargo.Load: description = fmt.Sprintf("Loaded onto voyage %s in %s, at %s.", e.Activity.VoyageNumber, e.Activity.Location, time.Now().Format(time.RFC3339)) case cargo.Unload: description = fmt.Sprintf("Unloaded off voyage %s in %s, at %s.", e.Activity.VoyageNumber, e.Activity.Location, time.Now().Format(time.RFC3339)) case cargo.Claim: description = fmt.Sprintf("Claimed in %s, at %s.", e.Activity.Location, time.Now().Format(time.RFC3339)) case cargo.Customs: description = fmt.Sprintf("Cleared customs in %s, at %s.", e.Activity.Location, time.Now().Format(time.RFC3339)) default: description = "[Unknown status]" } events = append(events, Event{ Description: description, Expected: c.Itinerary.IsExpected(e), }) } return events } golang-github-go-kit-kit-0.10.0/examples/shipping/tracking/transport.go000066400000000000000000000034661362256312400261350ustar00rootroot00000000000000package tracking import ( "context" "encoding/json" "errors" "net/http" "github.com/gorilla/mux" kitlog "github.com/go-kit/kit/log" kittransport "github.com/go-kit/kit/transport" kithttp "github.com/go-kit/kit/transport/http" "github.com/go-kit/kit/examples/shipping/cargo" ) // MakeHandler returns a handler for the tracking service. func MakeHandler(ts Service, logger kitlog.Logger) http.Handler { r := mux.NewRouter() opts := []kithttp.ServerOption{ kithttp.ServerErrorHandler(kittransport.NewLogErrorHandler(logger)), kithttp.ServerErrorEncoder(encodeError), } trackCargoHandler := kithttp.NewServer( makeTrackCargoEndpoint(ts), decodeTrackCargoRequest, encodeResponse, opts..., ) r.Handle("/tracking/v1/cargos/{id}", trackCargoHandler).Methods("GET") return r } func decodeTrackCargoRequest(_ context.Context, r *http.Request) (interface{}, error) { vars := mux.Vars(r) id, ok := vars["id"] if !ok { return nil, errors.New("bad route") } return trackCargoRequest{ID: id}, nil } func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error { if e, ok := response.(errorer); ok && e.error() != nil { encodeError(ctx, e.error(), w) return nil } w.Header().Set("Content-Type", "application/json; charset=utf-8") return json.NewEncoder(w).Encode(response) } type errorer interface { error() error } // encode errors from business-logic func encodeError(_ context.Context, err error, w http.ResponseWriter) { w.Header().Set("Content-Type", "application/json; charset=utf-8") switch err { case cargo.ErrUnknown: w.WriteHeader(http.StatusNotFound) case ErrInvalidArgument: w.WriteHeader(http.StatusBadRequest) default: w.WriteHeader(http.StatusInternalServerError) } json.NewEncoder(w).Encode(map[string]interface{}{ "error": err.Error(), }) } golang-github-go-kit-kit-0.10.0/examples/shipping/voyage/000077500000000000000000000000001362256312400232315ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/shipping/voyage/sample_voyages.go000066400000000000000000000024431362256312400266010ustar00rootroot00000000000000package voyage import "github.com/go-kit/kit/examples/shipping/location" // A set of sample voyages. var ( V100 = New("V100", Schedule{ []CarrierMovement{ {DepartureLocation: location.CNHKG, ArrivalLocation: location.JNTKO}, {DepartureLocation: location.JNTKO, ArrivalLocation: location.USNYC}, }, }) V300 = New("V300", Schedule{ []CarrierMovement{ {DepartureLocation: location.JNTKO, ArrivalLocation: location.NLRTM}, {DepartureLocation: location.NLRTM, ArrivalLocation: location.DEHAM}, {DepartureLocation: location.DEHAM, ArrivalLocation: location.AUMEL}, {DepartureLocation: location.AUMEL, ArrivalLocation: location.JNTKO}, }, }) V400 = New("V400", Schedule{ []CarrierMovement{ {DepartureLocation: location.DEHAM, ArrivalLocation: location.SESTO}, {DepartureLocation: location.SESTO, ArrivalLocation: location.FIHEL}, {DepartureLocation: location.FIHEL, ArrivalLocation: location.DEHAM}, }, }) ) // These voyages are hard-coded into the current pathfinder. Make sure // they exist. var ( V0100S = New("0100S", Schedule{[]CarrierMovement{}}) V0200T = New("0200T", Schedule{[]CarrierMovement{}}) V0300A = New("0300A", Schedule{[]CarrierMovement{}}) V0301S = New("0301S", Schedule{[]CarrierMovement{}}) V0400S = New("0400S", Schedule{[]CarrierMovement{}}) ) golang-github-go-kit-kit-0.10.0/examples/shipping/voyage/voyage.go000066400000000000000000000020251362256312400250510ustar00rootroot00000000000000// Package voyage provides the Voyage aggregate. package voyage import ( "errors" "time" "github.com/go-kit/kit/examples/shipping/location" ) // Number uniquely identifies a particular Voyage. type Number string // Voyage is a uniquely identifiable series of carrier movements. type Voyage struct { Number Number Schedule Schedule } // New creates a voyage with a voyage number and a provided schedule. func New(n Number, s Schedule) *Voyage { return &Voyage{Number: n, Schedule: s} } // Schedule describes a voyage schedule. type Schedule struct { CarrierMovements []CarrierMovement } // CarrierMovement is a vessel voyage from one location to another. type CarrierMovement struct { DepartureLocation location.UNLocode ArrivalLocation location.UNLocode DepartureTime time.Time ArrivalTime time.Time } // ErrUnknown is used when a voyage could not be found. var ErrUnknown = errors.New("unknown voyage") // Repository provides access a voyage store. type Repository interface { Find(Number) (*Voyage, error) } golang-github-go-kit-kit-0.10.0/examples/stringsvc1/000077500000000000000000000000001362256312400222215ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/stringsvc1/main.go000066400000000000000000000054021362256312400234750ustar00rootroot00000000000000package main import ( "context" "encoding/json" "errors" "log" "net/http" "strings" "github.com/go-kit/kit/endpoint" httptransport "github.com/go-kit/kit/transport/http" ) // StringService provides operations on strings. type StringService interface { Uppercase(string) (string, error) Count(string) int } // stringService is a concrete implementation of StringService type stringService struct{} func (stringService) Uppercase(s string) (string, error) { if s == "" { return "", ErrEmpty } return strings.ToUpper(s), nil } func (stringService) Count(s string) int { return len(s) } // ErrEmpty is returned when an input string is empty. var ErrEmpty = errors.New("empty string") // For each method, we define request and response structs type uppercaseRequest struct { S string `json:"s"` } type uppercaseResponse struct { V string `json:"v"` Err string `json:"err,omitempty"` // errors don't define JSON marshaling } type countRequest struct { S string `json:"s"` } type countResponse struct { V int `json:"v"` } // Endpoints are a primary abstraction in go-kit. An endpoint represents a single RPC (method in our service interface) func makeUppercaseEndpoint(svc StringService) endpoint.Endpoint { return func(_ context.Context, request interface{}) (interface{}, error) { req := request.(uppercaseRequest) v, err := svc.Uppercase(req.S) if err != nil { return uppercaseResponse{v, err.Error()}, nil } return uppercaseResponse{v, ""}, nil } } func makeCountEndpoint(svc StringService) endpoint.Endpoint { return func(_ context.Context, request interface{}) (interface{}, error) { req := request.(countRequest) v := svc.Count(req.S) return countResponse{v}, nil } } // Transports expose the service to the network. In this first example we utilize JSON over HTTP. func main() { svc := stringService{} uppercaseHandler := httptransport.NewServer( makeUppercaseEndpoint(svc), decodeUppercaseRequest, encodeResponse, ) countHandler := httptransport.NewServer( makeCountEndpoint(svc), decodeCountRequest, encodeResponse, ) http.Handle("/uppercase", uppercaseHandler) http.Handle("/count", countHandler) log.Fatal(http.ListenAndServe(":8080", nil)) } func decodeUppercaseRequest(_ context.Context, r *http.Request) (interface{}, error) { var request uppercaseRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { return nil, err } return request, nil } func decodeCountRequest(_ context.Context, r *http.Request) (interface{}, error) { var request countRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { return nil, err } return request, nil } func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { return json.NewEncoder(w).Encode(response) } golang-github-go-kit-kit-0.10.0/examples/stringsvc2/000077500000000000000000000000001362256312400222225ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/stringsvc2/instrumenting.go000066400000000000000000000016601362256312400254620ustar00rootroot00000000000000package main import ( "fmt" "time" "github.com/go-kit/kit/metrics" ) type instrumentingMiddleware struct { requestCount metrics.Counter requestLatency metrics.Histogram countResult metrics.Histogram next StringService } func (mw instrumentingMiddleware) Uppercase(s string) (output string, err error) { defer func(begin time.Time) { lvs := []string{"method", "uppercase", "error", fmt.Sprint(err != nil)} mw.requestCount.With(lvs...).Add(1) mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds()) }(time.Now()) output, err = mw.next.Uppercase(s) return } func (mw instrumentingMiddleware) Count(s string) (n int) { defer func(begin time.Time) { lvs := []string{"method", "count", "error", "false"} mw.requestCount.With(lvs...).Add(1) mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds()) mw.countResult.Observe(float64(n)) }(time.Now()) n = mw.next.Count(s) return } golang-github-go-kit-kit-0.10.0/examples/stringsvc2/logging.go000066400000000000000000000012471362256312400242030ustar00rootroot00000000000000package main import ( "time" "github.com/go-kit/kit/log" ) type loggingMiddleware struct { logger log.Logger next StringService } func (mw loggingMiddleware) Uppercase(s string) (output string, err error) { defer func(begin time.Time) { _ = mw.logger.Log( "method", "uppercase", "input", s, "output", output, "err", err, "took", time.Since(begin), ) }(time.Now()) output, err = mw.next.Uppercase(s) return } func (mw loggingMiddleware) Count(s string) (n int) { defer func(begin time.Time) { _ = mw.logger.Log( "method", "count", "input", s, "n", n, "took", time.Since(begin), ) }(time.Now()) n = mw.next.Count(s) return } golang-github-go-kit-kit-0.10.0/examples/stringsvc2/main.go000066400000000000000000000033231362256312400234760ustar00rootroot00000000000000package main import ( "net/http" "os" stdprometheus "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/go-kit/kit/log" kitprometheus "github.com/go-kit/kit/metrics/prometheus" httptransport "github.com/go-kit/kit/transport/http" ) func main() { logger := log.NewLogfmtLogger(os.Stderr) fieldKeys := []string{"method", "error"} requestCount := kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{ Namespace: "my_group", Subsystem: "string_service", Name: "request_count", Help: "Number of requests received.", }, fieldKeys) requestLatency := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{ Namespace: "my_group", Subsystem: "string_service", Name: "request_latency_microseconds", Help: "Total duration of requests in microseconds.", }, fieldKeys) countResult := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{ Namespace: "my_group", Subsystem: "string_service", Name: "count_result", Help: "The result of each count method.", }, []string{}) // no fields here var svc StringService svc = stringService{} svc = loggingMiddleware{logger, svc} svc = instrumentingMiddleware{requestCount, requestLatency, countResult, svc} uppercaseHandler := httptransport.NewServer( makeUppercaseEndpoint(svc), decodeUppercaseRequest, encodeResponse, ) countHandler := httptransport.NewServer( makeCountEndpoint(svc), decodeCountRequest, encodeResponse, ) http.Handle("/uppercase", uppercaseHandler) http.Handle("/count", countHandler) http.Handle("/metrics", promhttp.Handler()) logger.Log("msg", "HTTP", "addr", ":8080") logger.Log("err", http.ListenAndServe(":8080", nil)) } golang-github-go-kit-kit-0.10.0/examples/stringsvc2/service.go000066400000000000000000000007701362256312400242150ustar00rootroot00000000000000package main import ( "errors" "strings" ) // StringService provides operations on strings. type StringService interface { Uppercase(string) (string, error) Count(string) int } type stringService struct{} func (stringService) Uppercase(s string) (string, error) { if s == "" { return "", ErrEmpty } return strings.ToUpper(s), nil } func (stringService) Count(s string) int { return len(s) } // ErrEmpty is returned when an input string is empty. var ErrEmpty = errors.New("empty string") golang-github-go-kit-kit-0.10.0/examples/stringsvc2/transport.go000066400000000000000000000027251362256312400246130ustar00rootroot00000000000000package main import ( "context" "encoding/json" "net/http" "github.com/go-kit/kit/endpoint" ) func makeUppercaseEndpoint(svc StringService) endpoint.Endpoint { return func(_ context.Context, request interface{}) (interface{}, error) { req := request.(uppercaseRequest) v, err := svc.Uppercase(req.S) if err != nil { return uppercaseResponse{v, err.Error()}, nil } return uppercaseResponse{v, ""}, nil } } func makeCountEndpoint(svc StringService) endpoint.Endpoint { return func(_ context.Context, request interface{}) (interface{}, error) { req := request.(countRequest) v := svc.Count(req.S) return countResponse{v}, nil } } func decodeUppercaseRequest(_ context.Context, r *http.Request) (interface{}, error) { var request uppercaseRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { return nil, err } return request, nil } func decodeCountRequest(_ context.Context, r *http.Request) (interface{}, error) { var request countRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { return nil, err } return request, nil } func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { return json.NewEncoder(w).Encode(response) } type uppercaseRequest struct { S string `json:"s"` } type uppercaseResponse struct { V string `json:"v"` Err string `json:"err,omitempty"` } type countRequest struct { S string `json:"s"` } type countResponse struct { V int `json:"v"` } golang-github-go-kit-kit-0.10.0/examples/stringsvc3/000077500000000000000000000000001362256312400222235ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/stringsvc3/instrumenting.go000066400000000000000000000022221362256312400254560ustar00rootroot00000000000000package main import ( "fmt" "time" "github.com/go-kit/kit/metrics" ) func instrumentingMiddleware( requestCount metrics.Counter, requestLatency metrics.Histogram, countResult metrics.Histogram, ) ServiceMiddleware { return func(next StringService) StringService { return instrmw{requestCount, requestLatency, countResult, next} } } type instrmw struct { requestCount metrics.Counter requestLatency metrics.Histogram countResult metrics.Histogram StringService } func (mw instrmw) Uppercase(s string) (output string, err error) { defer func(begin time.Time) { lvs := []string{"method", "uppercase", "error", fmt.Sprint(err != nil)} mw.requestCount.With(lvs...).Add(1) mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds()) }(time.Now()) output, err = mw.StringService.Uppercase(s) return } func (mw instrmw) Count(s string) (n int) { defer func(begin time.Time) { lvs := []string{"method", "count", "error", "false"} mw.requestCount.With(lvs...).Add(1) mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds()) mw.countResult.Observe(float64(n)) }(time.Now()) n = mw.StringService.Count(s) return } golang-github-go-kit-kit-0.10.0/examples/stringsvc3/logging.go000066400000000000000000000014401362256312400241770ustar00rootroot00000000000000package main import ( "time" "github.com/go-kit/kit/log" ) func loggingMiddleware(logger log.Logger) ServiceMiddleware { return func(next StringService) StringService { return logmw{logger, next} } } type logmw struct { logger log.Logger StringService } func (mw logmw) Uppercase(s string) (output string, err error) { defer func(begin time.Time) { _ = mw.logger.Log( "method", "uppercase", "input", s, "output", output, "err", err, "took", time.Since(begin), ) }(time.Now()) output, err = mw.StringService.Uppercase(s) return } func (mw logmw) Count(s string) (n int) { defer func(begin time.Time) { _ = mw.logger.Log( "method", "count", "input", s, "n", n, "took", time.Since(begin), ) }(time.Now()) n = mw.StringService.Count(s) return } golang-github-go-kit-kit-0.10.0/examples/stringsvc3/main.go000066400000000000000000000040741362256312400235030ustar00rootroot00000000000000package main import ( "context" "flag" "net/http" "os" stdprometheus "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/go-kit/kit/log" kitprometheus "github.com/go-kit/kit/metrics/prometheus" httptransport "github.com/go-kit/kit/transport/http" ) func main() { var ( listen = flag.String("listen", ":8080", "HTTP listen address") proxy = flag.String("proxy", "", "Optional comma-separated list of URLs to proxy uppercase requests") ) flag.Parse() var logger log.Logger logger = log.NewLogfmtLogger(os.Stderr) logger = log.With(logger, "listen", *listen, "caller", log.DefaultCaller) fieldKeys := []string{"method", "error"} requestCount := kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{ Namespace: "my_group", Subsystem: "string_service", Name: "request_count", Help: "Number of requests received.", }, fieldKeys) requestLatency := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{ Namespace: "my_group", Subsystem: "string_service", Name: "request_latency_microseconds", Help: "Total duration of requests in microseconds.", }, fieldKeys) countResult := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{ Namespace: "my_group", Subsystem: "string_service", Name: "count_result", Help: "The result of each count method.", }, []string{}) var svc StringService svc = stringService{} svc = proxyingMiddleware(context.Background(), *proxy, logger)(svc) svc = loggingMiddleware(logger)(svc) svc = instrumentingMiddleware(requestCount, requestLatency, countResult)(svc) uppercaseHandler := httptransport.NewServer( makeUppercaseEndpoint(svc), decodeUppercaseRequest, encodeResponse, ) countHandler := httptransport.NewServer( makeCountEndpoint(svc), decodeCountRequest, encodeResponse, ) http.Handle("/uppercase", uppercaseHandler) http.Handle("/count", countHandler) http.Handle("/metrics", promhttp.Handler()) logger.Log("msg", "HTTP", "addr", *listen) logger.Log("err", http.ListenAndServe(*listen, nil)) } golang-github-go-kit-kit-0.10.0/examples/stringsvc3/proxying.go000066400000000000000000000062321362256312400244340ustar00rootroot00000000000000package main import ( "context" "errors" "fmt" "net/url" "strings" "time" "golang.org/x/time/rate" "github.com/sony/gobreaker" "github.com/go-kit/kit/circuitbreaker" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/log" "github.com/go-kit/kit/ratelimit" "github.com/go-kit/kit/sd" "github.com/go-kit/kit/sd/lb" httptransport "github.com/go-kit/kit/transport/http" ) func proxyingMiddleware(ctx context.Context, instances string, logger log.Logger) ServiceMiddleware { // If instances is empty, don't proxy. if instances == "" { logger.Log("proxy_to", "none") return func(next StringService) StringService { return next } } // Set some parameters for our client. var ( qps = 100 // beyond which we will return an error maxAttempts = 3 // per request, before giving up maxTime = 250 * time.Millisecond // wallclock time, before giving up ) // Otherwise, construct an endpoint for each instance in the list, and add // it to a fixed set of endpoints. In a real service, rather than doing this // by hand, you'd probably use package sd's support for your service // discovery system. var ( instanceList = split(instances) endpointer sd.FixedEndpointer ) logger.Log("proxy_to", fmt.Sprint(instanceList)) for _, instance := range instanceList { var e endpoint.Endpoint e = makeUppercaseProxy(ctx, instance) e = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{}))(e) e = ratelimit.NewErroringLimiter(rate.NewLimiter(rate.Every(time.Second), qps))(e) endpointer = append(endpointer, e) } // Now, build a single, retrying, load-balancing endpoint out of all of // those individual endpoints. balancer := lb.NewRoundRobin(endpointer) retry := lb.Retry(maxAttempts, maxTime, balancer) // And finally, return the ServiceMiddleware, implemented by proxymw. return func(next StringService) StringService { return proxymw{ctx, next, retry} } } // proxymw implements StringService, forwarding Uppercase requests to the // provided endpoint, and serving all other (i.e. Count) requests via the // next StringService. type proxymw struct { ctx context.Context next StringService // Serve most requests via this service... uppercase endpoint.Endpoint // ...except Uppercase, which gets served by this endpoint } func (mw proxymw) Count(s string) int { return mw.next.Count(s) } func (mw proxymw) Uppercase(s string) (string, error) { response, err := mw.uppercase(mw.ctx, uppercaseRequest{S: s}) if err != nil { return "", err } resp := response.(uppercaseResponse) if resp.Err != "" { return resp.V, errors.New(resp.Err) } return resp.V, nil } func makeUppercaseProxy(ctx context.Context, instance string) endpoint.Endpoint { if !strings.HasPrefix(instance, "http") { instance = "http://" + instance } u, err := url.Parse(instance) if err != nil { panic(err) } if u.Path == "" { u.Path = "/uppercase" } return httptransport.NewClient( "GET", u, encodeRequest, decodeUppercaseResponse, ).Endpoint() } func split(s string) []string { a := strings.Split(s, ",") for i := range a { a[i] = strings.TrimSpace(a[i]) } return a } golang-github-go-kit-kit-0.10.0/examples/stringsvc3/service.go000066400000000000000000000011731362256312400242140ustar00rootroot00000000000000package main import ( "errors" "strings" ) // StringService provides operations on strings. type StringService interface { Uppercase(string) (string, error) Count(string) int } type stringService struct{} func (stringService) Uppercase(s string) (string, error) { if s == "" { return "", ErrEmpty } return strings.ToUpper(s), nil } func (stringService) Count(s string) int { return len(s) } // ErrEmpty is returned when an input string is empty. var ErrEmpty = errors.New("empty string") // ServiceMiddleware is a chainable behavior modifier for StringService. type ServiceMiddleware func(StringService) StringService golang-github-go-kit-kit-0.10.0/examples/stringsvc3/transport.go000066400000000000000000000037021362256312400246100ustar00rootroot00000000000000package main import ( "bytes" "context" "encoding/json" "io/ioutil" "net/http" "github.com/go-kit/kit/endpoint" ) func makeUppercaseEndpoint(svc StringService) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(uppercaseRequest) v, err := svc.Uppercase(req.S) if err != nil { return uppercaseResponse{v, err.Error()}, nil } return uppercaseResponse{v, ""}, nil } } func makeCountEndpoint(svc StringService) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(countRequest) v := svc.Count(req.S) return countResponse{v}, nil } } func decodeUppercaseRequest(_ context.Context, r *http.Request) (interface{}, error) { var request uppercaseRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { return nil, err } return request, nil } func decodeCountRequest(_ context.Context, r *http.Request) (interface{}, error) { var request countRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { return nil, err } return request, nil } func decodeUppercaseResponse(_ context.Context, r *http.Response) (interface{}, error) { var response uppercaseResponse if err := json.NewDecoder(r.Body).Decode(&response); err != nil { return nil, err } return response, nil } func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { return json.NewEncoder(w).Encode(response) } func encodeRequest(_ context.Context, r *http.Request, request interface{}) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(request); err != nil { return err } r.Body = ioutil.NopCloser(&buf) return nil } type uppercaseRequest struct { S string `json:"s"` } type uppercaseResponse struct { V string `json:"v"` Err string `json:"err,omitempty"` } type countRequest struct { S string `json:"s"` } type countResponse struct { V int `json:"v"` } golang-github-go-kit-kit-0.10.0/examples/stringsvc4/000077500000000000000000000000001362256312400222245ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/examples/stringsvc4/main.go000066400000000000000000000116371362256312400235070ustar00rootroot00000000000000package main import ( "context" "encoding/json" "errors" "log" "strings" "flag" "net/http" "github.com/go-kit/kit/endpoint" natstransport "github.com/go-kit/kit/transport/nats" httptransport "github.com/go-kit/kit/transport/http" "github.com/nats-io/nats.go" ) // StringService provides operations on strings. type StringService interface { Uppercase(context.Context, string) (string, error) Count(context.Context, string) int } // stringService is a concrete implementation of StringService type stringService struct{} func (stringService) Uppercase(_ context.Context, s string) (string, error) { if s == "" { return "", ErrEmpty } return strings.ToUpper(s), nil } func (stringService) Count(_ context.Context, s string) int { return len(s) } // ErrEmpty is returned when an input string is empty. var ErrEmpty = errors.New("empty string") // For each method, we define request and response structs type uppercaseRequest struct { S string `json:"s"` } type uppercaseResponse struct { V string `json:"v"` Err string `json:"err,omitempty"` // errors don't define JSON marshaling } type countRequest struct { S string `json:"s"` } type countResponse struct { V int `json:"v"` } // Endpoints are a primary abstraction in go-kit. An endpoint represents a single RPC (method in our service interface) func makeUppercaseHTTPEndpoint(nc *nats.Conn) endpoint.Endpoint { return natstransport.NewPublisher( nc, "stringsvc.uppercase", natstransport.EncodeJSONRequest, decodeUppercaseResponse, ).Endpoint() } func makeCountHTTPEndpoint(nc *nats.Conn) endpoint.Endpoint { return natstransport.NewPublisher( nc, "stringsvc.count", natstransport.EncodeJSONRequest, decodeCountResponse, ).Endpoint() } func makeUppercaseEndpoint(svc StringService) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(uppercaseRequest) v, err := svc.Uppercase(ctx, req.S) if err != nil { return uppercaseResponse{v, err.Error()}, nil } return uppercaseResponse{v, ""}, nil } } func makeCountEndpoint(svc StringService) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(countRequest) v := svc.Count(ctx, req.S) return countResponse{v}, nil } } // Transports expose the service to the network. In this fourth example we utilize JSON over NATS and HTTP. func main() { svc := stringService{} natsURL := flag.String("nats-url", nats.DefaultURL, "URL for connection to NATS") flag.Parse() nc, err := nats.Connect(*natsURL) if err != nil { log.Fatal(err) } defer nc.Close() uppercaseHTTPHandler := httptransport.NewServer( makeUppercaseHTTPEndpoint(nc), decodeUppercaseHTTPRequest, httptransport.EncodeJSONResponse, ) countHTTPHandler := httptransport.NewServer( makeCountHTTPEndpoint(nc), decodeCountHTTPRequest, httptransport.EncodeJSONResponse, ) uppercaseHandler := natstransport.NewSubscriber( makeUppercaseEndpoint(svc), decodeUppercaseRequest, natstransport.EncodeJSONResponse, ) countHandler := natstransport.NewSubscriber( makeCountEndpoint(svc), decodeCountRequest, natstransport.EncodeJSONResponse, ) uSub, err := nc.QueueSubscribe("stringsvc.uppercase", "stringsvc", uppercaseHandler.ServeMsg(nc)) if err != nil { log.Fatal(err) } defer uSub.Unsubscribe() cSub, err := nc.QueueSubscribe("stringsvc.count", "stringsvc", countHandler.ServeMsg(nc)) if err != nil { log.Fatal(err) } defer cSub.Unsubscribe() http.Handle("/uppercase", uppercaseHTTPHandler) http.Handle("/count", countHTTPHandler) log.Fatal(http.ListenAndServe(":8080", nil)) } func decodeUppercaseHTTPRequest(_ context.Context, r *http.Request) (interface{}, error) { var request uppercaseRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { return nil, err } return request, nil } func decodeCountHTTPRequest(_ context.Context, r *http.Request) (interface{}, error) { var request countRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { return nil, err } return request, nil } func decodeUppercaseResponse(_ context.Context, msg *nats.Msg) (interface{}, error) { var response uppercaseResponse if err := json.Unmarshal(msg.Data, &response); err != nil { return nil, err } return response, nil } func decodeCountResponse(_ context.Context, msg *nats.Msg) (interface{}, error) { var response countResponse if err := json.Unmarshal(msg.Data, &response); err != nil { return nil, err } return response, nil } func decodeUppercaseRequest(_ context.Context, msg *nats.Msg) (interface{}, error) { var request uppercaseRequest if err := json.Unmarshal(msg.Data, &request); err != nil { return nil, err } return request, nil } func decodeCountRequest(_ context.Context, msg *nats.Msg) (interface{}, error) { var request countRequest if err := json.Unmarshal(msg.Data, &request); err != nil { return nil, err } return request, nil } golang-github-go-kit-kit-0.10.0/go.mod000066400000000000000000000051561362256312400174150ustar00rootroot00000000000000module github.com/go-kit/kit go 1.13 require ( github.com/VividCortex/gohistogram v1.0.0 github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 github.com/apache/thrift v0.13.0 github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a github.com/aws/aws-lambda-go v1.13.3 github.com/aws/aws-sdk-go v1.27.0 github.com/aws/aws-sdk-go-v2 v0.18.0 github.com/casbin/casbin/v2 v2.1.2 github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec // indirect github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect github.com/davecgh/go-spew v1.1.1 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/edsrzf/mmap-go v1.0.0 // indirect github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db // indirect github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8 // indirect github.com/go-logfmt/logfmt v0.5.0 github.com/go-stack/stack v1.8.0 github.com/golang/protobuf v1.3.2 github.com/gorilla/mux v1.7.3 github.com/hashicorp/consul/api v1.3.0 github.com/hashicorp/go-version v1.2.0 // indirect github.com/hudl/fargo v1.3.0 github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d github.com/lightstep/lightstep-tracer-go v0.18.1 github.com/nats-io/nats-server/v2 v2.1.2 github.com/nats-io/nats.go v1.9.1 github.com/oklog/oklog v0.3.2 github.com/oklog/run v1.0.0 // indirect github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect github.com/opentracing/basictracer-go v1.0.0 // indirect github.com/opentracing/opentracing-go v1.1.0 github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5 github.com/openzipkin/zipkin-go v0.2.2 github.com/pact-foundation/pact-go v1.0.4 github.com/pborman/uuid v1.2.0 github.com/performancecopilot/speed v3.0.0+incompatible github.com/pkg/errors v0.8.1 github.com/prometheus/client_golang v1.3.0 github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da github.com/sirupsen/logrus v1.4.2 github.com/smartystreets/goconvey v1.6.4 // indirect github.com/sony/gobreaker v0.4.1 github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 go.opencensus.io v0.22.2 go.uber.org/zap v1.13.0 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e golang.org/x/time v0.0.0-20191024005414-555d28b269f0 golang.org/x/tools v0.0.0-20200103221440-774c71fcf114 google.golang.org/grpc v1.26.0 gopkg.in/gcfg.v1 v1.2.3 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0 ) golang-github-go-kit-kit-0.10.0/go.sum000066400000000000000000001352651362256312400174470ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= 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= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0 h1:5hryIiq9gtn+MiLVn0wP37kb/uTeRZgN08WoCsAhIhI= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a h1:pv34s756C4pEXnjgPfGYgdhg/ZdajGhyOvzx8k+23nw= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3 h1:SuCy7H3NLyp+1Mrfp+m80jcbi9KYWAs9/BXwppwRDzY= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0 h1:0xphMHGMLBrPMfxR2AmVjZKcMEESEgWF8Kru94BNByk= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0 h1:qZ+woO4SamnH/eEbjM2IDLhRNwIwND/RQyVlBLp3Jqg= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/casbin/casbin/v2 v2.1.2 h1:bTwon/ECRx9dwBy2ewRVr5OiqjeXSGiTUY74sDPQi/g= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec h1:EdRZT3IeKQmfCSrgo8SZ8V3MEnskuJP0wCYNpe+aiXo= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf h1:CAKfRE2YtTUIjjh1bkBtyYFaUT/WmOqsJjgtihT0vMI= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db h1:gb2Z18BhTPJPpLQWj4T+rfKHYCHxRHCtRxhKKjRidVw= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8 h1:a9ENSRDFBUPkJ5lCgVZh26+ZbGyoVJG7yb5SSzF5H54= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c h1:Lh2aW+HnU2Nbe1gqD9SOJLJxW1jBMmQOktN2acDyJk8= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.3.0 h1:HXNYlRkkM/t+Y/Yhxtwcy02dlYwIaoxzvxPnS+cqy78= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0 h1:UOxjlb4xVNF93jak1mzzoBatyFju9nrkxpVwIp/QqxQ= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0 h1:0U6+BtN6LhaYuTnIJq4Wyq5cpn6O2kWrxAtcqBmYY6w= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d h1:/WZQPMZNsjZ7IlCpsLGdQBINg5bxKQ1K1sh6awxLtkA= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743 h1:143Bb8f8DuGWck/xpNUOckBVYfFbBTnLevfRZ1aVVqo= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1 h1:vi1F1IQ8N7hNWytK9DpJsUfQhGuNSc19z330K6vl4zk= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/nats-server/v2 v2.1.2 h1:i2Ly0B+1+rzNZHHWtD4ZwKi+OU5l+uQo1iDHZ2PmiIc= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= github.com/nats-io/nats.go v1.9.1 h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3 h1:6JrEfig+HzTH85yxzhSVbjHRJv9cn0p6n3IngIcM5/k= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/oklog/oklog v0.3.2 h1:wVfs8F+in6nTBMkA7CbRw+zZMIB7nNM825cM1wuzoTk= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5 h1:ZCnq+JUrvXcDVhX/xRolRBZifmabN1HcS1wrPSvxhrU= github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2 h1:nY8Hti+WKaP0cRsSeQ026wU03QsM762XBeCXBb9NAWI= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/pact-foundation/pact-go v1.0.4 h1:OYkFijGHoZAYbOIb1LWXrwKQbMMRUv1oQ89blD2Mh2Q= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/performancecopilot/speed v3.0.0+incompatible h1:2WnRzIquHa5QxaJKShDkLM+sc0JPuwhXzK8OYOyt3Vg= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0 h1:miYCvYqFXtl/J9FIy8eNpBfYthAEFg+Ys0XyUVEcDsc= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0 h1:ElTg5tNp4DqfV7UQjDqv2+RJlNzsDtvNAWccbItceIE= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da h1:p3Vo3i64TCLY7gIfzeQaUJ+kppEO5WQG3cL8iE8tGHU= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1 h1:oMnRNZXX5j85zso6xCPRNPtmAycat+WcoKbklScLDgQ= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a h1:AhmOdSHeswKHBjhsLs/7+1voOxT+LLrSk/Nxvk35fug= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f h1:68K/z8GLUxV76xGSqwTWw2gyk/jwn79LUL43rES2g8o= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114 h1:DnSr2mCsxyCE6ZgIkmcWUQY2R5cH/6wL7eIxEmQOMSE= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3 h1:m8OOJ4ccYHnx2f4gQwpno8nAX5OGOh7RLaaz0pj3Ogs= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0 h1:ucqkfpjg9WzSUubAO62csmucvxl4/JeW3F4I4909XkM= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= golang-github-go-kit-kit-0.10.0/lint000077500000000000000000000011141362256312400171710ustar00rootroot00000000000000#!/usr/bin/env bash set -o errexit set -o nounset set -o pipefail if [ ! $(command -v gometalinter) ] then go get github.com/alecthomas/gometalinter gometalinter --update --install fi time gometalinter \ --exclude='error return value not checked.*(Close|Log|Print).*\(errcheck\)$' \ --exclude='.*_test\.go:.*error return value not checked.*\(errcheck\)$' \ --exclude='/thrift/' \ --exclude='/pb/' \ --exclude='no args in Log call \(vet\)' \ --disable=dupl \ --disable=aligncheck \ --disable=gotype \ --cyclo-over=20 \ --tests \ --concurrency=2 \ --deadline=300s \ ./... golang-github-go-kit-kit-0.10.0/log/000077500000000000000000000000001362256312400170615ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/log/README.md000066400000000000000000000113341362256312400203420ustar00rootroot00000000000000# package log `package log` provides a minimal interface for structured logging in services. It may be wrapped to encode conventions, enforce type-safety, provide leveled logging, and so on. It can be used for both typical application log events, and log-structured data streams. ## Structured logging Structured logging is, basically, conceding to the reality that logs are _data_, and warrant some level of schematic rigor. Using a stricter, key/value-oriented message format for our logs, containing contextual and semantic information, makes it much easier to get insight into the operational activity of the systems we build. Consequently, `package log` is of the strong belief that "[the benefits of structured logging outweigh the minimal effort involved](https://www.thoughtworks.com/radar/techniques/structured-logging)". Migrating from unstructured to structured logging is probably a lot easier than you'd expect. ```go // Unstructured log.Printf("HTTP server listening on %s", addr) // Structured logger.Log("transport", "HTTP", "addr", addr, "msg", "listening") ``` ## Usage ### Typical application logging ```go w := log.NewSyncWriter(os.Stderr) logger := log.NewLogfmtLogger(w) logger.Log("question", "what is the meaning of life?", "answer", 42) // Output: // question="what is the meaning of life?" answer=42 ``` ### Contextual Loggers ```go func main() { var logger log.Logger logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) logger = log.With(logger, "instance_id", 123) logger.Log("msg", "starting") NewWorker(log.With(logger, "component", "worker")).Run() NewSlacker(log.With(logger, "component", "slacker")).Run() } // Output: // instance_id=123 msg=starting // instance_id=123 component=worker msg=running // instance_id=123 component=slacker msg=running ``` ### Interact with stdlib logger Redirect stdlib logger to Go kit logger. ```go import ( "os" stdlog "log" kitlog "github.com/go-kit/kit/log" ) func main() { logger := kitlog.NewJSONLogger(kitlog.NewSyncWriter(os.Stdout)) stdlog.SetOutput(kitlog.NewStdlibAdapter(logger)) stdlog.Print("I sure like pie") } // Output: // {"msg":"I sure like pie","ts":"2016/01/01 12:34:56"} ``` Or, if, for legacy reasons, you need to pipe all of your logging through the stdlib log package, you can redirect Go kit logger to the stdlib logger. ```go logger := kitlog.NewLogfmtLogger(kitlog.StdlibWriter{}) logger.Log("legacy", true, "msg", "at least it's something") // Output: // 2016/01/01 12:34:56 legacy=true msg="at least it's something" ``` ### Timestamps and callers ```go var logger log.Logger logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller) logger.Log("msg", "hello") // Output: // ts=2016-01-01T12:34:56Z caller=main.go:15 msg=hello ``` ## Levels Log levels are supported via the [level package](https://godoc.org/github.com/go-kit/kit/log/level). ## Supported output formats - [Logfmt](https://brandur.org/logfmt) ([see also](https://blog.codeship.com/logfmt-a-log-format-thats-easy-to-read-and-write)) - JSON ## Enhancements `package log` is centered on the one-method Logger interface. ```go type Logger interface { Log(keyvals ...interface{}) error } ``` This interface, and its supporting code like is the product of much iteration and evaluation. For more details on the evolution of the Logger interface, see [The Hunt for a Logger Interface](http://go-talks.appspot.com/github.com/ChrisHines/talks/structured-logging/structured-logging.slide#1), a talk by [Chris Hines](https://github.com/ChrisHines). Also, please see [#63](https://github.com/go-kit/kit/issues/63), [#76](https://github.com/go-kit/kit/pull/76), [#131](https://github.com/go-kit/kit/issues/131), [#157](https://github.com/go-kit/kit/pull/157), [#164](https://github.com/go-kit/kit/issues/164), and [#252](https://github.com/go-kit/kit/pull/252) to review historical conversations about package log and the Logger interface. Value-add packages and suggestions, like improvements to [the leveled logger](https://godoc.org/github.com/go-kit/kit/log/level), are of course welcome. Good proposals should - Be composable with [contextual loggers](https://godoc.org/github.com/go-kit/kit/log#With), - Not break the behavior of [log.Caller](https://godoc.org/github.com/go-kit/kit/log#Caller) in any wrapped contextual loggers, and - Be friendly to packages that accept only an unadorned log.Logger. ## Benchmarks & comparisons There are a few Go logging benchmarks and comparisons that include Go kit's package log. - [imkira/go-loggers-bench](https://github.com/imkira/go-loggers-bench) includes kit/log - [uber-common/zap](https://github.com/uber-common/zap), a zero-alloc logging library, includes a comparison with kit/log golang-github-go-kit-kit-0.10.0/log/benchmark_test.go000066400000000000000000000006771362256312400224130ustar00rootroot00000000000000package log_test import ( "testing" "github.com/go-kit/kit/log" ) func benchmarkRunner(b *testing.B, logger log.Logger, f func(log.Logger)) { lc := log.With(logger, "common_key", "common_value") b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { f(lc) } } var ( baseMessage = func(logger log.Logger) { logger.Log("foo_key", "foo_value") } withMessage = func(logger log.Logger) { log.With(logger, "a", "b").Log("c", "d") } ) golang-github-go-kit-kit-0.10.0/log/concurrency_test.go000066400000000000000000000012211362256312400227750ustar00rootroot00000000000000package log_test import ( "math" "testing" "github.com/go-kit/kit/log" ) // These test are designed to be run with the race detector. func testConcurrency(t *testing.T, logger log.Logger, total int) { n := int(math.Sqrt(float64(total))) share := total / n errC := make(chan error, n) for i := 0; i < n; i++ { go func() { errC <- spam(logger, share) }() } for i := 0; i < n; i++ { err := <-errC if err != nil { t.Fatalf("concurrent logging error: %v", err) } } } func spam(logger log.Logger, count int) error { for i := 0; i < count; i++ { err := logger.Log("key", i) if err != nil { return err } } return nil } golang-github-go-kit-kit-0.10.0/log/deprecated_levels/000077500000000000000000000000001362256312400225335ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/log/deprecated_levels/levels.go000066400000000000000000000075671362256312400243730ustar00rootroot00000000000000package levels import "github.com/go-kit/kit/log" // Levels provides a leveled logging wrapper around a logger. It has five // levels: debug, info, warning (warn), error, and critical (crit). If you // want a different set of levels, you can create your own levels type very // easily, and you can elide the configuration. type Levels struct { logger log.Logger levelKey string // We have a choice between storing level values in string fields or // making a separate context for each level. When using string fields the // Log method must combine the base context, the level data, and the // logged keyvals; but the With method only requires updating one context. // If we instead keep a separate context for each level the Log method // must only append the new keyvals; but the With method would have to // update all five contexts. // Roughly speaking, storing multiple contexts breaks even if the ratio of // Log/With calls is more than the number of levels. We have chosen to // make the With method cheap and the Log method a bit more costly because // we do not expect most applications to Log more than five times for each // call to With. debugValue string infoValue string warnValue string errorValue string critValue string } // New creates a new leveled logger, wrapping the passed logger. func New(logger log.Logger, options ...Option) Levels { l := Levels{ logger: logger, levelKey: "level", debugValue: "debug", infoValue: "info", warnValue: "warn", errorValue: "error", critValue: "crit", } for _, option := range options { option(&l) } return l } // With returns a new leveled logger that includes keyvals in all log events. func (l Levels) With(keyvals ...interface{}) Levels { return Levels{ logger: log.With(l.logger, keyvals...), levelKey: l.levelKey, debugValue: l.debugValue, infoValue: l.infoValue, warnValue: l.warnValue, errorValue: l.errorValue, critValue: l.critValue, } } // Debug returns a debug level logger. func (l Levels) Debug() log.Logger { return log.WithPrefix(l.logger, l.levelKey, l.debugValue) } // Info returns an info level logger. func (l Levels) Info() log.Logger { return log.WithPrefix(l.logger, l.levelKey, l.infoValue) } // Warn returns a warning level logger. func (l Levels) Warn() log.Logger { return log.WithPrefix(l.logger, l.levelKey, l.warnValue) } // Error returns an error level logger. func (l Levels) Error() log.Logger { return log.WithPrefix(l.logger, l.levelKey, l.errorValue) } // Crit returns a critical level logger. func (l Levels) Crit() log.Logger { return log.WithPrefix(l.logger, l.levelKey, l.critValue) } // Option sets a parameter for leveled loggers. type Option func(*Levels) // Key sets the key for the field used to indicate log level. By default, // the key is "level". func Key(key string) Option { return func(l *Levels) { l.levelKey = key } } // DebugValue sets the value for the field used to indicate the debug log // level. By default, the value is "debug". func DebugValue(value string) Option { return func(l *Levels) { l.debugValue = value } } // InfoValue sets the value for the field used to indicate the info log level. // By default, the value is "info". func InfoValue(value string) Option { return func(l *Levels) { l.infoValue = value } } // WarnValue sets the value for the field used to indicate the warning log // level. By default, the value is "warn". func WarnValue(value string) Option { return func(l *Levels) { l.warnValue = value } } // ErrorValue sets the value for the field used to indicate the error log // level. By default, the value is "error". func ErrorValue(value string) Option { return func(l *Levels) { l.errorValue = value } } // CritValue sets the value for the field used to indicate the critical log // level. By default, the value is "crit". func CritValue(value string) Option { return func(l *Levels) { l.critValue = value } } golang-github-go-kit-kit-0.10.0/log/deprecated_levels/levels_test.go000066400000000000000000000032771362256312400254240ustar00rootroot00000000000000package levels_test import ( "bytes" "os" "testing" "github.com/go-kit/kit/log" levels "github.com/go-kit/kit/log/deprecated_levels" ) func TestDefaultLevels(t *testing.T) { buf := bytes.Buffer{} logger := levels.New(log.NewLogfmtLogger(&buf)) logger.Debug().Log("msg", "résumé") // of course you'd want to do this if want, have := "level=debug msg=résumé\n", buf.String(); want != have { t.Errorf("want %#v, have %#v", want, have) } buf.Reset() logger.Info().Log("msg", "Åhus") if want, have := "level=info msg=Åhus\n", buf.String(); want != have { t.Errorf("want %#v, have %#v", want, have) } buf.Reset() logger.Error().Log("msg", "© violation") if want, have := "level=error msg=\"© violation\"\n", buf.String(); want != have { t.Errorf("want %#v, have %#v", want, have) } buf.Reset() logger.Crit().Log("msg", " ") if want, have := "level=crit msg=\"\\t\"\n", buf.String(); want != have { t.Errorf("want %#v, have %#v", want, have) } } func TestModifiedLevels(t *testing.T) { buf := bytes.Buffer{} logger := levels.New( log.NewJSONLogger(&buf), levels.Key("l"), levels.DebugValue("dbg"), levels.InfoValue("nfo"), levels.WarnValue("wrn"), levels.ErrorValue("err"), levels.CritValue("crt"), ) logger.With("easter_island", "176°").Debug().Log("msg", "moai") if want, have := `{"easter_island":"176°","l":"dbg","msg":"moai"}`+"\n", buf.String(); want != have { t.Errorf("want %#v, have %#v", want, have) } } func ExampleLevels() { logger := levels.New(log.NewLogfmtLogger(os.Stdout)) logger.Debug().Log("msg", "hello") logger.With("context", "foo").Warn().Log("err", "error") // Output: // level=debug msg=hello // level=warn context=foo err=error } golang-github-go-kit-kit-0.10.0/log/doc.go000066400000000000000000000123351362256312400201610ustar00rootroot00000000000000// Package log provides a structured logger. // // Structured logging produces logs easily consumed later by humans or // machines. Humans might be interested in debugging errors, or tracing // specific requests. Machines might be interested in counting interesting // events, or aggregating information for off-line processing. In both cases, // it is important that the log messages are structured and actionable. // Package log is designed to encourage both of these best practices. // // Basic Usage // // The fundamental interface is Logger. Loggers create log events from // key/value data. The Logger interface has a single method, Log, which // accepts a sequence of alternating key/value pairs, which this package names // keyvals. // // type Logger interface { // Log(keyvals ...interface{}) error // } // // Here is an example of a function using a Logger to create log events. // // func RunTask(task Task, logger log.Logger) string { // logger.Log("taskID", task.ID, "event", "starting task") // ... // logger.Log("taskID", task.ID, "event", "task complete") // } // // The keys in the above example are "taskID" and "event". The values are // task.ID, "starting task", and "task complete". Every key is followed // immediately by its value. // // Keys are usually plain strings. Values may be any type that has a sensible // encoding in the chosen log format. With structured logging it is a good // idea to log simple values without formatting them. This practice allows // the chosen logger to encode values in the most appropriate way. // // Contextual Loggers // // A contextual logger stores keyvals that it includes in all log events. // Building appropriate contextual loggers reduces repetition and aids // consistency in the resulting log output. With and WithPrefix add context to // a logger. We can use With to improve the RunTask example. // // func RunTask(task Task, logger log.Logger) string { // logger = log.With(logger, "taskID", task.ID) // logger.Log("event", "starting task") // ... // taskHelper(task.Cmd, logger) // ... // logger.Log("event", "task complete") // } // // The improved version emits the same log events as the original for the // first and last calls to Log. Passing the contextual logger to taskHelper // enables each log event created by taskHelper to include the task.ID even // though taskHelper does not have access to that value. Using contextual // loggers this way simplifies producing log output that enables tracing the // life cycle of individual tasks. (See the Contextual example for the full // code of the above snippet.) // // Dynamic Contextual Values // // A Valuer function stored in a contextual logger generates a new value each // time an event is logged. The Valuer example demonstrates how this feature // works. // // Valuers provide the basis for consistently logging timestamps and source // code location. The log package defines several valuers for that purpose. // See Timestamp, DefaultTimestamp, DefaultTimestampUTC, Caller, and // DefaultCaller. A common logger initialization sequence that ensures all log // entries contain a timestamp and source location looks like this: // // logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout)) // logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller) // // Concurrent Safety // // Applications with multiple goroutines want each log event written to the // same logger to remain separate from other log events. Package log provides // two simple solutions for concurrent safe logging. // // NewSyncWriter wraps an io.Writer and serializes each call to its Write // method. Using a SyncWriter has the benefit that the smallest practical // portion of the logging logic is performed within a mutex, but it requires // the formatting Logger to make only one call to Write per log event. // // NewSyncLogger wraps any Logger and serializes each call to its Log method. // Using a SyncLogger has the benefit that it guarantees each log event is // handled atomically within the wrapped logger, but it typically serializes // both the formatting and output logic. Use a SyncLogger if the formatting // logger may perform multiple writes per log event. // // Error Handling // // This package relies on the practice of wrapping or decorating loggers with // other loggers to provide composable pieces of functionality. It also means // that Logger.Log must return an error because some // implementations—especially those that output log data to an io.Writer—may // encounter errors that cannot be handled locally. This in turn means that // Loggers that wrap other loggers should return errors from the wrapped // logger up the stack. // // Fortunately, the decorator pattern also provides a way to avoid the // necessity to check for errors every time an application calls Logger.Log. // An application required to panic whenever its Logger encounters // an error could initialize its logger as follows. // // fmtlogger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout)) // logger := log.LoggerFunc(func(keyvals ...interface{}) error { // if err := fmtlogger.Log(keyvals...); err != nil { // panic(err) // } // return nil // }) package log golang-github-go-kit-kit-0.10.0/log/example_test.go000066400000000000000000000053371362256312400221120ustar00rootroot00000000000000package log_test import ( "math/rand" "os" "sync" "time" "github.com/go-kit/kit/log" ) func Example_basic() { logger := log.NewLogfmtLogger(os.Stdout) type Task struct { ID int } RunTask := func(task Task, logger log.Logger) { logger.Log("taskID", task.ID, "event", "starting task") logger.Log("taskID", task.ID, "event", "task complete") } RunTask(Task{ID: 1}, logger) // Output: // taskID=1 event="starting task" // taskID=1 event="task complete" } func Example_contextual() { logger := log.NewLogfmtLogger(os.Stdout) type Task struct { ID int Cmd string } taskHelper := func(cmd string, logger log.Logger) { // execute(cmd) logger.Log("cmd", cmd, "dur", 42*time.Millisecond) } RunTask := func(task Task, logger log.Logger) { logger = log.With(logger, "taskID", task.ID) logger.Log("event", "starting task") taskHelper(task.Cmd, logger) logger.Log("event", "task complete") } RunTask(Task{ID: 1, Cmd: "echo Hello, world!"}, logger) // Output: // taskID=1 event="starting task" // taskID=1 cmd="echo Hello, world!" dur=42ms // taskID=1 event="task complete" } func Example_valuer() { logger := log.NewLogfmtLogger(os.Stdout) count := 0 counter := func() interface{} { count++ return count } logger = log.With(logger, "count", log.Valuer(counter)) logger.Log("call", "first") logger.Log("call", "second") // Output: // count=1 call=first // count=2 call=second } func Example_debugInfo() { logger := log.NewLogfmtLogger(os.Stdout) // make time predictable for this test baseTime := time.Date(2015, time.February, 3, 10, 0, 0, 0, time.UTC) mockTime := func() time.Time { baseTime = baseTime.Add(time.Second) return baseTime } logger = log.With(logger, "time", log.Timestamp(mockTime), "caller", log.DefaultCaller) logger.Log("call", "first") logger.Log("call", "second") // ... logger.Log("call", "third") // Output: // time=2015-02-03T10:00:01Z caller=example_test.go:93 call=first // time=2015-02-03T10:00:02Z caller=example_test.go:94 call=second // time=2015-02-03T10:00:03Z caller=example_test.go:98 call=third } func Example_syncWriter() { w := log.NewSyncWriter(os.Stdout) logger := log.NewLogfmtLogger(w) type Task struct { ID int } var wg sync.WaitGroup RunTask := func(task Task, logger log.Logger) { logger.Log("taskID", task.ID, "event", "starting task") time.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond) logger.Log("taskID", task.ID, "event", "task complete") wg.Done() } wg.Add(2) go RunTask(Task{ID: 1}, logger) go RunTask(Task{ID: 2}, logger) wg.Wait() // Unordered output: // taskID=1 event="starting task" // taskID=2 event="starting task" // taskID=1 event="task complete" // taskID=2 event="task complete" } golang-github-go-kit-kit-0.10.0/log/json_logger.go000066400000000000000000000037201362256312400217220ustar00rootroot00000000000000package log import ( "encoding" "encoding/json" "fmt" "io" "reflect" ) type jsonLogger struct { io.Writer } // NewJSONLogger returns a Logger that encodes keyvals to the Writer as a // single JSON object. Each log event produces no more than one call to // w.Write. The passed Writer must be safe for concurrent use by multiple // goroutines if the returned Logger will be used concurrently. func NewJSONLogger(w io.Writer) Logger { return &jsonLogger{w} } func (l *jsonLogger) Log(keyvals ...interface{}) error { n := (len(keyvals) + 1) / 2 // +1 to handle case when len is odd m := make(map[string]interface{}, n) for i := 0; i < len(keyvals); i += 2 { k := keyvals[i] var v interface{} = ErrMissingValue if i+1 < len(keyvals) { v = keyvals[i+1] } merge(m, k, v) } enc := json.NewEncoder(l.Writer) enc.SetEscapeHTML(false) return enc.Encode(m) } func merge(dst map[string]interface{}, k, v interface{}) { var key string switch x := k.(type) { case string: key = x case fmt.Stringer: key = safeString(x) default: key = fmt.Sprint(x) } // We want json.Marshaler and encoding.TextMarshaller to take priority over // err.Error() and v.String(). But json.Marshall (called later) does that by // default so we force a no-op if it's one of those 2 case. switch x := v.(type) { case json.Marshaler: case encoding.TextMarshaler: case error: v = safeError(x) case fmt.Stringer: v = safeString(x) } dst[key] = v } func safeString(str fmt.Stringer) (s string) { defer func() { if panicVal := recover(); panicVal != nil { if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() { s = "NULL" } else { panic(panicVal) } } }() s = str.String() return } func safeError(err error) (s interface{}) { defer func() { if panicVal := recover(); panicVal != nil { if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() { s = nil } else { panic(panicVal) } } }() s = err.Error() return } golang-github-go-kit-kit-0.10.0/log/json_logger_test.go000066400000000000000000000074141362256312400227650ustar00rootroot00000000000000package log_test import ( "bytes" "errors" "io/ioutil" "testing" "github.com/go-kit/kit/log" ) func TestJSONLoggerCaller(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} logger := log.NewJSONLogger(buf) logger = log.With(logger, "caller", log.DefaultCaller) if err := logger.Log(); err != nil { t.Fatal(err) } if want, have := `{"caller":"json_logger_test.go:18"}`+"\n", buf.String(); want != have { t.Errorf("\nwant %#v\nhave %#v", want, have) } } func TestJSONLogger(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} logger := log.NewJSONLogger(buf) if err := logger.Log("err", errors.New("err"), "m", map[string]int{"0": 0}, "a", []int{1, 2, 3}); err != nil { t.Fatal(err) } if want, have := `{"a":[1,2,3],"err":"err","m":{"0":0}}`+"\n", buf.String(); want != have { t.Errorf("\nwant %#v\nhave %#v", want, have) } } func TestJSONLoggerMissingValue(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} logger := log.NewJSONLogger(buf) if err := logger.Log("k"); err != nil { t.Fatal(err) } if want, have := `{"k":"(MISSING)"}`+"\n", buf.String(); want != have { t.Errorf("\nwant %#v\nhave %#v", want, have) } } func TestJSONLoggerNilStringerKey(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} logger := log.NewJSONLogger(buf) if err := logger.Log((*stringer)(nil), "v"); err != nil { t.Fatal(err) } if want, have := `{"NULL":"v"}`+"\n", buf.String(); want != have { t.Errorf("\nwant %#v\nhave %#v", want, have) } } func TestJSONLoggerNilErrorValue(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} logger := log.NewJSONLogger(buf) if err := logger.Log("err", (*stringError)(nil)); err != nil { t.Fatal(err) } if want, have := `{"err":null}`+"\n", buf.String(); want != have { t.Errorf("\nwant %#v\nhave %#v", want, have) } } func TestJSONLoggerNoHTMLEscape(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} logger := log.NewJSONLogger(buf) if err := logger.Log("k", "<&>"); err != nil { t.Fatal(err) } if want, have := `{"k":"<&>"}`+"\n", buf.String(); want != have { t.Errorf("\nwant %#v\nhave%#v", want, have) } } // aller implements json.Marshaler, encoding.TextMarshaler, and fmt.Stringer. type aller struct{} func (aller) MarshalJSON() ([]byte, error) { return []byte("\"json\""), nil } func (aller) MarshalText() ([]byte, error) { return []byte("text"), nil } func (aller) String() string { return "string" } func (aller) Error() string { return "error" } // textstringer implements encoding.TextMarshaler and fmt.Stringer. type textstringer struct{} func (textstringer) MarshalText() ([]byte, error) { return []byte("text"), nil } func (textstringer) String() string { return "string" } func TestJSONLoggerStringValue(t *testing.T) { t.Parallel() tests := []struct { v interface{} expected string }{ { v: aller{}, expected: `{"v":"json"}`, }, { v: textstringer{}, expected: `{"v":"text"}`, }, { v: stringer("string"), expected: `{"v":"string"}`, }, } for _, test := range tests { buf := &bytes.Buffer{} logger := log.NewJSONLogger(buf) if err := logger.Log("v", test.v); err != nil { t.Fatal(err) } if want, have := test.expected+"\n", buf.String(); want != have { t.Errorf("\nwant %#v\nhave %#v", want, have) } } } type stringer string func (s stringer) String() string { return string(s) } type stringError string func (s stringError) Error() string { return string(s) } func BenchmarkJSONLoggerSimple(b *testing.B) { benchmarkRunner(b, log.NewJSONLogger(ioutil.Discard), baseMessage) } func BenchmarkJSONLoggerContextual(b *testing.B) { benchmarkRunner(b, log.NewJSONLogger(ioutil.Discard), withMessage) } func TestJSONLoggerConcurrency(t *testing.T) { t.Parallel() testConcurrency(t, log.NewJSONLogger(ioutil.Discard), 10000) } golang-github-go-kit-kit-0.10.0/log/level/000077500000000000000000000000001362256312400201705ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/log/level/benchmark_test.go000066400000000000000000000032151362256312400235110ustar00rootroot00000000000000package level_test import ( "io/ioutil" "testing" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" ) func Benchmark(b *testing.B) { contexts := []struct { name string context func(log.Logger) log.Logger }{ {"NoContext", func(l log.Logger) log.Logger { return l }}, {"TimeContext", func(l log.Logger) log.Logger { return log.With(l, "time", log.DefaultTimestampUTC) }}, {"CallerContext", func(l log.Logger) log.Logger { return log.With(l, "caller", log.DefaultCaller) }}, {"TimeCallerReqIDContext", func(l log.Logger) log.Logger { return log.With(l, "time", log.DefaultTimestampUTC, "caller", log.DefaultCaller, "reqID", 29) }}, } loggers := []struct { name string logger log.Logger }{ {"Nop", log.NewNopLogger()}, {"Logfmt", log.NewLogfmtLogger(ioutil.Discard)}, {"JSON", log.NewJSONLogger(ioutil.Discard)}, } filters := []struct { name string filter func(log.Logger) log.Logger }{ {"Baseline", func(l log.Logger) log.Logger { return l }}, {"DisallowedLevel", func(l log.Logger) log.Logger { return level.NewFilter(l, level.AllowInfo()) }}, {"AllowedLevel", func(l log.Logger) log.Logger { return level.NewFilter(l, level.AllowAll()) }}, } for _, c := range contexts { b.Run(c.name, func(b *testing.B) { for _, f := range filters { b.Run(f.name, func(b *testing.B) { for _, l := range loggers { b.Run(l.name, func(b *testing.B) { logger := c.context(f.filter(l.logger)) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { level.Debug(logger).Log("foo", "bar") } }) } }) } }) } } golang-github-go-kit-kit-0.10.0/log/level/doc.go000066400000000000000000000016501362256312400212660ustar00rootroot00000000000000// Package level implements leveled logging on top of Go kit's log package. To // use the level package, create a logger as per normal in your func main, and // wrap it with level.NewFilter. // // var logger log.Logger // logger = log.NewLogfmtLogger(os.Stderr) // logger = level.NewFilter(logger, level.AllowInfo()) // <-- // logger = log.With(logger, "ts", log.DefaultTimestampUTC) // // Then, at the callsites, use one of the level.Debug, Info, Warn, or Error // helper methods to emit leveled log events. // // logger.Log("foo", "bar") // as normal, no level // level.Debug(logger).Log("request_id", reqID, "trace_data", trace.Get()) // if value > 100 { // level.Error(logger).Log("value", value) // } // // NewFilter allows precise control over what happens when a log event is // emitted without a level key, or if a squelched level is used. Check the // Option functions for details. package level golang-github-go-kit-kit-0.10.0/log/level/example_test.go000066400000000000000000000023401362256312400232100ustar00rootroot00000000000000package level_test import ( "errors" "os" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" ) func Example_basic() { logger := log.NewLogfmtLogger(os.Stdout) level.Debug(logger).Log("msg", "this message is at the debug level") level.Info(logger).Log("msg", "this message is at the info level") level.Warn(logger).Log("msg", "this message is at the warn level") level.Error(logger).Log("msg", "this message is at the error level") // Output: // level=debug msg="this message is at the debug level" // level=info msg="this message is at the info level" // level=warn msg="this message is at the warn level" // level=error msg="this message is at the error level" } func Example_filtered() { // Set up logger with level filter. logger := log.NewLogfmtLogger(os.Stdout) logger = level.NewFilter(logger, level.AllowInfo()) logger = log.With(logger, "caller", log.DefaultCaller) // Use level helpers to log at different levels. level.Error(logger).Log("err", errors.New("bad data")) level.Info(logger).Log("event", "data saved") level.Debug(logger).Log("next item", 17) // filtered // Output: // level=error caller=example_test.go:32 err="bad data" // level=info caller=example_test.go:33 event="data saved" } golang-github-go-kit-kit-0.10.0/log/level/level.go000066400000000000000000000134351362256312400216340ustar00rootroot00000000000000package level import "github.com/go-kit/kit/log" // Error returns a logger that includes a Key/ErrorValue pair. func Error(logger log.Logger) log.Logger { return log.WithPrefix(logger, Key(), ErrorValue()) } // Warn returns a logger that includes a Key/WarnValue pair. func Warn(logger log.Logger) log.Logger { return log.WithPrefix(logger, Key(), WarnValue()) } // Info returns a logger that includes a Key/InfoValue pair. func Info(logger log.Logger) log.Logger { return log.WithPrefix(logger, Key(), InfoValue()) } // Debug returns a logger that includes a Key/DebugValue pair. func Debug(logger log.Logger) log.Logger { return log.WithPrefix(logger, Key(), DebugValue()) } // NewFilter wraps next and implements level filtering. See the commentary on // the Option functions for a detailed description of how to configure levels. // If no options are provided, all leveled log events created with Debug, // Info, Warn or Error helper methods are squelched and non-leveled log // events are passed to next unmodified. func NewFilter(next log.Logger, options ...Option) log.Logger { l := &logger{ next: next, } for _, option := range options { option(l) } return l } type logger struct { next log.Logger allowed level squelchNoLevel bool errNotAllowed error errNoLevel error } func (l *logger) Log(keyvals ...interface{}) error { var hasLevel, levelAllowed bool for i := 1; i < len(keyvals); i += 2 { if v, ok := keyvals[i].(*levelValue); ok { hasLevel = true levelAllowed = l.allowed&v.level != 0 break } } if !hasLevel && l.squelchNoLevel { return l.errNoLevel } if hasLevel && !levelAllowed { return l.errNotAllowed } return l.next.Log(keyvals...) } // Option sets a parameter for the leveled logger. type Option func(*logger) // AllowAll is an alias for AllowDebug. func AllowAll() Option { return AllowDebug() } // AllowDebug allows error, warn, info and debug level log events to pass. func AllowDebug() Option { return allowed(levelError | levelWarn | levelInfo | levelDebug) } // AllowInfo allows error, warn and info level log events to pass. func AllowInfo() Option { return allowed(levelError | levelWarn | levelInfo) } // AllowWarn allows error and warn level log events to pass. func AllowWarn() Option { return allowed(levelError | levelWarn) } // AllowError allows only error level log events to pass. func AllowError() Option { return allowed(levelError) } // AllowNone allows no leveled log events to pass. func AllowNone() Option { return allowed(0) } func allowed(allowed level) Option { return func(l *logger) { l.allowed = allowed } } // ErrNotAllowed sets the error to return from Log when it squelches a log // event disallowed by the configured Allow[Level] option. By default, // ErrNotAllowed is nil; in this case the log event is squelched with no // error. func ErrNotAllowed(err error) Option { return func(l *logger) { l.errNotAllowed = err } } // SquelchNoLevel instructs Log to squelch log events with no level, so that // they don't proceed through to the wrapped logger. If SquelchNoLevel is set // to true and a log event is squelched in this way, the error value // configured with ErrNoLevel is returned to the caller. func SquelchNoLevel(squelch bool) Option { return func(l *logger) { l.squelchNoLevel = squelch } } // ErrNoLevel sets the error to return from Log when it squelches a log event // with no level. By default, ErrNoLevel is nil; in this case the log event is // squelched with no error. func ErrNoLevel(err error) Option { return func(l *logger) { l.errNoLevel = err } } // NewInjector wraps next and returns a logger that adds a Key/level pair to // the beginning of log events that don't already contain a level. In effect, // this gives a default level to logs without a level. func NewInjector(next log.Logger, level Value) log.Logger { return &injector{ next: next, level: level, } } type injector struct { next log.Logger level interface{} } func (l *injector) Log(keyvals ...interface{}) error { for i := 1; i < len(keyvals); i += 2 { if _, ok := keyvals[i].(*levelValue); ok { return l.next.Log(keyvals...) } } kvs := make([]interface{}, len(keyvals)+2) kvs[0], kvs[1] = key, l.level copy(kvs[2:], keyvals) return l.next.Log(kvs...) } // Value is the interface that each of the canonical level values implement. // It contains unexported methods that prevent types from other packages from // implementing it and guaranteeing that NewFilter can distinguish the levels // defined in this package from all other values. type Value interface { String() string levelVal() } // Key returns the unique key added to log events by the loggers in this // package. func Key() interface{} { return key } // ErrorValue returns the unique value added to log events by Error. func ErrorValue() Value { return errorValue } // WarnValue returns the unique value added to log events by Warn. func WarnValue() Value { return warnValue } // InfoValue returns the unique value added to log events by Info. func InfoValue() Value { return infoValue } // DebugValue returns the unique value added to log events by Warn. func DebugValue() Value { return debugValue } var ( // key is of type interface{} so that it allocates once during package // initialization and avoids allocating every time the value is added to a // []interface{} later. key interface{} = "level" errorValue = &levelValue{level: levelError, name: "error"} warnValue = &levelValue{level: levelWarn, name: "warn"} infoValue = &levelValue{level: levelInfo, name: "info"} debugValue = &levelValue{level: levelDebug, name: "debug"} ) type level byte const ( levelDebug level = 1 << iota levelInfo levelWarn levelError ) type levelValue struct { name string level } func (v *levelValue) String() string { return v.name } func (v *levelValue) levelVal() {} golang-github-go-kit-kit-0.10.0/log/level/level_test.go000066400000000000000000000140401362256312400226640ustar00rootroot00000000000000package level_test import ( "bytes" "errors" "io" "strings" "testing" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" ) func TestVariousLevels(t *testing.T) { testCases := []struct { name string allowed level.Option want string }{ { "AllowAll", level.AllowAll(), strings.Join([]string{ `{"level":"debug","this is":"debug log"}`, `{"level":"info","this is":"info log"}`, `{"level":"warn","this is":"warn log"}`, `{"level":"error","this is":"error log"}`, }, "\n"), }, { "AllowDebug", level.AllowDebug(), strings.Join([]string{ `{"level":"debug","this is":"debug log"}`, `{"level":"info","this is":"info log"}`, `{"level":"warn","this is":"warn log"}`, `{"level":"error","this is":"error log"}`, }, "\n"), }, { "AllowInfo", level.AllowInfo(), strings.Join([]string{ `{"level":"info","this is":"info log"}`, `{"level":"warn","this is":"warn log"}`, `{"level":"error","this is":"error log"}`, }, "\n"), }, { "AllowWarn", level.AllowWarn(), strings.Join([]string{ `{"level":"warn","this is":"warn log"}`, `{"level":"error","this is":"error log"}`, }, "\n"), }, { "AllowError", level.AllowError(), strings.Join([]string{ `{"level":"error","this is":"error log"}`, }, "\n"), }, { "AllowNone", level.AllowNone(), ``, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { var buf bytes.Buffer logger := level.NewFilter(log.NewJSONLogger(&buf), tc.allowed) level.Debug(logger).Log("this is", "debug log") level.Info(logger).Log("this is", "info log") level.Warn(logger).Log("this is", "warn log") level.Error(logger).Log("this is", "error log") if want, have := tc.want, strings.TrimSpace(buf.String()); want != have { t.Errorf("\nwant:\n%s\nhave:\n%s", want, have) } }) } } func TestErrNotAllowed(t *testing.T) { myError := errors.New("squelched!") opts := []level.Option{ level.AllowWarn(), level.ErrNotAllowed(myError), } logger := level.NewFilter(log.NewNopLogger(), opts...) if want, have := myError, level.Info(logger).Log("foo", "bar"); want != have { t.Errorf("want %#+v, have %#+v", want, have) } if want, have := error(nil), level.Warn(logger).Log("foo", "bar"); want != have { t.Errorf("want %#+v, have %#+v", want, have) } } func TestErrNoLevel(t *testing.T) { myError := errors.New("no level specified") var buf bytes.Buffer opts := []level.Option{ level.SquelchNoLevel(true), level.ErrNoLevel(myError), } logger := level.NewFilter(log.NewJSONLogger(&buf), opts...) if want, have := myError, logger.Log("foo", "bar"); want != have { t.Errorf("want %v, have %v", want, have) } if want, have := ``, strings.TrimSpace(buf.String()); want != have { t.Errorf("\nwant '%s'\nhave '%s'", want, have) } } func TestAllowNoLevel(t *testing.T) { var buf bytes.Buffer opts := []level.Option{ level.SquelchNoLevel(false), level.ErrNoLevel(errors.New("I should never be returned!")), } logger := level.NewFilter(log.NewJSONLogger(&buf), opts...) if want, have := error(nil), logger.Log("foo", "bar"); want != have { t.Errorf("want %v, have %v", want, have) } if want, have := `{"foo":"bar"}`, strings.TrimSpace(buf.String()); want != have { t.Errorf("\nwant '%s'\nhave '%s'", want, have) } } func TestLevelContext(t *testing.T) { var buf bytes.Buffer // Wrapping the level logger with a context allows users to use // log.DefaultCaller as per normal. var logger log.Logger logger = log.NewLogfmtLogger(&buf) logger = level.NewFilter(logger, level.AllowAll()) logger = log.With(logger, "caller", log.DefaultCaller) level.Info(logger).Log("foo", "bar") if want, have := `level=info caller=level_test.go:149 foo=bar`, strings.TrimSpace(buf.String()); want != have { t.Errorf("\nwant '%s'\nhave '%s'", want, have) } } func TestContextLevel(t *testing.T) { var buf bytes.Buffer // Wrapping a context with the level logger still works, but requires users // to specify a higher callstack depth value. var logger log.Logger logger = log.NewLogfmtLogger(&buf) logger = log.With(logger, "caller", log.Caller(5)) logger = level.NewFilter(logger, level.AllowAll()) level.Info(logger).Log("foo", "bar") if want, have := `caller=level_test.go:165 level=info foo=bar`, strings.TrimSpace(buf.String()); want != have { t.Errorf("\nwant '%s'\nhave '%s'", want, have) } } func TestLevelFormatting(t *testing.T) { testCases := []struct { name string format func(io.Writer) log.Logger output string }{ { name: "logfmt", format: log.NewLogfmtLogger, output: `level=info foo=bar`, }, { name: "JSON", format: log.NewJSONLogger, output: `{"foo":"bar","level":"info"}`, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { var buf bytes.Buffer logger := tc.format(&buf) level.Info(logger).Log("foo", "bar") if want, have := tc.output, strings.TrimSpace(buf.String()); want != have { t.Errorf("\nwant: '%s'\nhave '%s'", want, have) } }) } } func TestInjector(t *testing.T) { var ( output []interface{} logger log.Logger ) logger = log.LoggerFunc(func(keyvals ...interface{}) error { output = keyvals return nil }) logger = level.NewInjector(logger, level.InfoValue()) logger.Log("foo", "bar") if got, want := len(output), 4; got != want { t.Errorf("missing level not injected: got len==%d, want len==%d", got, want) } if got, want := output[0], level.Key(); got != want { t.Errorf("wrong level key: got %#v, want %#v", got, want) } if got, want := output[1], level.InfoValue(); got != want { t.Errorf("wrong level value: got %#v, want %#v", got, want) } level.Error(logger).Log("foo", "bar") if got, want := len(output), 4; got != want { t.Errorf("leveled record modified: got len==%d, want len==%d", got, want) } if got, want := output[0], level.Key(); got != want { t.Errorf("wrong level key: got %#v, want %#v", got, want) } if got, want := output[1], level.ErrorValue(); got != want { t.Errorf("wrong level value: got %#v, want %#v", got, want) } } golang-github-go-kit-kit-0.10.0/log/log.go000066400000000000000000000115451362256312400201770ustar00rootroot00000000000000package log import "errors" // Logger is the fundamental interface for all log operations. Log creates a // log event from keyvals, a variadic sequence of alternating keys and values. // Implementations must be safe for concurrent use by multiple goroutines. In // particular, any implementation of Logger that appends to keyvals or // modifies or retains any of its elements must make a copy first. type Logger interface { Log(keyvals ...interface{}) error } // ErrMissingValue is appended to keyvals slices with odd length to substitute // the missing value. var ErrMissingValue = errors.New("(MISSING)") // With returns a new contextual logger with keyvals prepended to those passed // to calls to Log. If logger is also a contextual logger created by With or // WithPrefix, keyvals is appended to the existing context. // // The returned Logger replaces all value elements (odd indexes) containing a // Valuer with their generated value for each call to its Log method. func With(logger Logger, keyvals ...interface{}) Logger { if len(keyvals) == 0 { return logger } l := newContext(logger) kvs := append(l.keyvals, keyvals...) if len(kvs)%2 != 0 { kvs = append(kvs, ErrMissingValue) } return &context{ logger: l.logger, // Limiting the capacity of the stored keyvals ensures that a new // backing array is created if the slice must grow in Log or With. // Using the extra capacity without copying risks a data race that // would violate the Logger interface contract. keyvals: kvs[:len(kvs):len(kvs)], hasValuer: l.hasValuer || containsValuer(keyvals), } } // WithPrefix returns a new contextual logger with keyvals prepended to those // passed to calls to Log. If logger is also a contextual logger created by // With or WithPrefix, keyvals is prepended to the existing context. // // The returned Logger replaces all value elements (odd indexes) containing a // Valuer with their generated value for each call to its Log method. func WithPrefix(logger Logger, keyvals ...interface{}) Logger { if len(keyvals) == 0 { return logger } l := newContext(logger) // Limiting the capacity of the stored keyvals ensures that a new // backing array is created if the slice must grow in Log or With. // Using the extra capacity without copying risks a data race that // would violate the Logger interface contract. n := len(l.keyvals) + len(keyvals) if len(keyvals)%2 != 0 { n++ } kvs := make([]interface{}, 0, n) kvs = append(kvs, keyvals...) if len(kvs)%2 != 0 { kvs = append(kvs, ErrMissingValue) } kvs = append(kvs, l.keyvals...) return &context{ logger: l.logger, keyvals: kvs, hasValuer: l.hasValuer || containsValuer(keyvals), } } // context is the Logger implementation returned by With and WithPrefix. It // wraps a Logger and holds keyvals that it includes in all log events. Its // Log method calls bindValues to generate values for each Valuer in the // context keyvals. // // A context must always have the same number of stack frames between calls to // its Log method and the eventual binding of Valuers to their value. This // requirement comes from the functional requirement to allow a context to // resolve application call site information for a Caller stored in the // context. To do this we must be able to predict the number of logging // functions on the stack when bindValues is called. // // Two implementation details provide the needed stack depth consistency. // // 1. newContext avoids introducing an additional layer when asked to // wrap another context. // 2. With and WithPrefix avoid introducing an additional layer by // returning a newly constructed context with a merged keyvals rather // than simply wrapping the existing context. type context struct { logger Logger keyvals []interface{} hasValuer bool } func newContext(logger Logger) *context { if c, ok := logger.(*context); ok { return c } return &context{logger: logger} } // Log replaces all value elements (odd indexes) containing a Valuer in the // stored context with their generated value, appends keyvals, and passes the // result to the wrapped Logger. func (l *context) Log(keyvals ...interface{}) error { kvs := append(l.keyvals, keyvals...) if len(kvs)%2 != 0 { kvs = append(kvs, ErrMissingValue) } if l.hasValuer { // If no keyvals were appended above then we must copy l.keyvals so // that future log events will reevaluate the stored Valuers. if len(keyvals) == 0 { kvs = append([]interface{}{}, l.keyvals...) } bindValues(kvs[:len(l.keyvals)]) } return l.logger.Log(kvs...) } // LoggerFunc is an adapter to allow use of ordinary functions as Loggers. If // f is a function with the appropriate signature, LoggerFunc(f) is a Logger // object that calls f. type LoggerFunc func(...interface{}) error // Log implements Logger by calling f(keyvals...). func (f LoggerFunc) Log(keyvals ...interface{}) error { return f(keyvals...) } golang-github-go-kit-kit-0.10.0/log/log_test.go000066400000000000000000000110711362256312400212300ustar00rootroot00000000000000package log_test import ( "bytes" "fmt" "sync" "testing" "github.com/go-kit/kit/log" "github.com/go-stack/stack" ) func TestContext(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} logger := log.NewLogfmtLogger(buf) kvs := []interface{}{"a", 123} lc := log.With(logger, kvs...) kvs[1] = 0 // With should copy its key values lc = log.With(lc, "b", "c") // With should stack if err := lc.Log("msg", "message"); err != nil { t.Fatal(err) } if want, have := "a=123 b=c msg=message\n", buf.String(); want != have { t.Errorf("\nwant: %shave: %s", want, have) } buf.Reset() lc = log.WithPrefix(lc, "p", "first") if err := lc.Log("msg", "message"); err != nil { t.Fatal(err) } if want, have := "p=first a=123 b=c msg=message\n", buf.String(); want != have { t.Errorf("\nwant: %shave: %s", want, have) } } func TestContextMissingValue(t *testing.T) { t.Parallel() var output []interface{} logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error { output = keyvals return nil })) log.WithPrefix(log.With(logger, "k1"), "k0").Log("k2") if want, have := 6, len(output); want != have { t.Errorf("want len(output) == %v, have %v", want, have) } for i := 1; i < 6; i += 2 { if want, have := log.ErrMissingValue, output[i]; want != have { t.Errorf("want output[%d] == %#v, have %#v", i, want, have) } } } // Test that context.Log has a consistent function stack depth when binding // Valuers, regardless of how many times With has been called. func TestContextStackDepth(t *testing.T) { t.Parallel() fn := fmt.Sprintf("%n", stack.Caller(0)) var output []interface{} logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error { output = keyvals return nil })) stackValuer := log.Valuer(func() interface{} { for i, c := range stack.Trace() { if fmt.Sprintf("%n", c) == fn { return i } } t.Fatal("Test function not found in stack trace.") return nil }) logger = log.With(logger, "stack", stackValuer) // Call through interface to get baseline. logger.Log("k", "v") want := output[1].(int) for len(output) < 10 { logger.Log("k", "v") if have := output[1]; have != want { t.Errorf("%d Withs: have %v, want %v", len(output)/2-1, have, want) } wrapped := log.With(logger) wrapped.Log("k", "v") if have := output[1]; have != want { t.Errorf("%d Withs: have %v, want %v", len(output)/2-1, have, want) } logger = log.With(logger, "k", "v") } } // Test that With returns a Logger safe for concurrent use. This test // validates that the stored logging context does not get corrupted when // multiple clients concurrently log additional keyvals. // // This test must be run with go test -cpu 2 (or more) to achieve its goal. func TestWithConcurrent(t *testing.T) { // Create some buckets to count how many events each goroutine logs. const goroutines = 8 counts := [goroutines]int{} // This logger extracts a goroutine id from the last value field and // increments the referenced bucket. logger := log.LoggerFunc(func(kv ...interface{}) error { goroutine := kv[len(kv)-1].(int) counts[goroutine]++ return nil }) // With must be careful about handling slices that can grow without // copying the underlying array, so give it a challenge. l := log.With(logger, make([]interface{}, 0, 2)...) // Start logging concurrently. Each goroutine logs its id so the logger // can bucket the event counts. var wg sync.WaitGroup wg.Add(goroutines) const n = 10000 for i := 0; i < goroutines; i++ { go func(idx int) { defer wg.Done() for j := 0; j < n; j++ { l.Log("goroutineIdx", idx) } }(i) } wg.Wait() for bucket, have := range counts { if want := n; want != have { t.Errorf("bucket %d: want %d, have %d", bucket, want, have) // note Errorf } } } func BenchmarkDiscard(b *testing.B) { logger := log.NewNopLogger() b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { logger.Log("k", "v") } } func BenchmarkOneWith(b *testing.B) { logger := log.NewNopLogger() lc := log.With(logger, "k", "v") b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { lc.Log("k", "v") } } func BenchmarkTwoWith(b *testing.B) { logger := log.NewNopLogger() lc := log.With(logger, "k", "v") for i := 1; i < 2; i++ { lc = log.With(lc, "k", "v") } b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { lc.Log("k", "v") } } func BenchmarkTenWith(b *testing.B) { logger := log.NewNopLogger() lc := log.With(logger, "k", "v") for i := 1; i < 10; i++ { lc = log.With(lc, "k", "v") } b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { lc.Log("k", "v") } } golang-github-go-kit-kit-0.10.0/log/logfmt_logger.go000066400000000000000000000025411362256312400222410ustar00rootroot00000000000000package log import ( "bytes" "io" "sync" "github.com/go-logfmt/logfmt" ) type logfmtEncoder struct { *logfmt.Encoder buf bytes.Buffer } func (l *logfmtEncoder) Reset() { l.Encoder.Reset() l.buf.Reset() } var logfmtEncoderPool = sync.Pool{ New: func() interface{} { var enc logfmtEncoder enc.Encoder = logfmt.NewEncoder(&enc.buf) return &enc }, } type logfmtLogger struct { w io.Writer } // NewLogfmtLogger returns a logger that encodes keyvals to the Writer in // logfmt format. Each log event produces no more than one call to w.Write. // The passed Writer must be safe for concurrent use by multiple goroutines if // the returned Logger will be used concurrently. func NewLogfmtLogger(w io.Writer) Logger { return &logfmtLogger{w} } func (l logfmtLogger) Log(keyvals ...interface{}) error { enc := logfmtEncoderPool.Get().(*logfmtEncoder) enc.Reset() defer logfmtEncoderPool.Put(enc) if err := enc.EncodeKeyvals(keyvals...); err != nil { return err } // Add newline to the end of the buffer if err := enc.EndRecord(); err != nil { return err } // The Logger interface requires implementations to be safe for concurrent // use by multiple goroutines. For this implementation that means making // only one call to l.w.Write() for each call to Log. if _, err := l.w.Write(enc.buf.Bytes()); err != nil { return err } return nil } golang-github-go-kit-kit-0.10.0/log/logfmt_logger_test.go000066400000000000000000000026071362256312400233030ustar00rootroot00000000000000package log_test import ( "bytes" "errors" "io/ioutil" "testing" "github.com/go-kit/kit/log" "github.com/go-logfmt/logfmt" ) func TestLogfmtLogger(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} logger := log.NewLogfmtLogger(buf) if err := logger.Log("hello", "world"); err != nil { t.Fatal(err) } if want, have := "hello=world\n", buf.String(); want != have { t.Errorf("want %#v, have %#v", want, have) } buf.Reset() if err := logger.Log("a", 1, "err", errors.New("error")); err != nil { t.Fatal(err) } if want, have := "a=1 err=error\n", buf.String(); want != have { t.Errorf("want %#v, have %#v", want, have) } buf.Reset() if err := logger.Log("std_map", map[int]int{1: 2}, "my_map", mymap{0: 0}); err != nil { t.Fatal(err) } if want, have := "std_map=\""+logfmt.ErrUnsupportedValueType.Error()+"\" my_map=special_behavior\n", buf.String(); want != have { t.Errorf("want %#v, have %#v", want, have) } } func BenchmarkLogfmtLoggerSimple(b *testing.B) { benchmarkRunner(b, log.NewLogfmtLogger(ioutil.Discard), baseMessage) } func BenchmarkLogfmtLoggerContextual(b *testing.B) { benchmarkRunner(b, log.NewLogfmtLogger(ioutil.Discard), withMessage) } func TestLogfmtLoggerConcurrency(t *testing.T) { t.Parallel() testConcurrency(t, log.NewLogfmtLogger(ioutil.Discard), 10000) } type mymap map[int]int func (m mymap) String() string { return "special_behavior" } golang-github-go-kit-kit-0.10.0/log/logrus/000077500000000000000000000000001362256312400203745ustar00rootroot00000000000000golang-github-go-kit-kit-0.10.0/log/logrus/logrus_logger.go000066400000000000000000000014071362256312400235770ustar00rootroot00000000000000// Package logrus provides an adapter to the // go-kit log.Logger interface. package logrus import ( "errors" "fmt" "github.com/go-kit/kit/log" "github.com/sirupsen/logrus" ) type logrusLogger struct { logrus.FieldLogger } var errMissingValue = errors.New("(MISSING)") // NewLogrusLogger returns a go-kit log.Logger that sends log events to a Logrus logger. func NewLogrusLogger(logger logrus.FieldLogger) log.Logger { return &logrusLogger{logger} } func (l logrusLogger) Log(keyvals ...interface{}) error { fields := logrus.Fields{} for i := 0; i < len(keyvals); i += 2 { if i+1 < len(keyvals) { fields[fmt.Sprint(keyvals[i])] = keyvals[i+1] } else { fields[fmt.Sprint(keyvals[i])] = errMissingValue } } l.WithFields(fields).Info() return nil } golang-github-go-kit-kit-0.10.0/log/logrus/logrus_logger_test.go000066400000000000000000000027311362256312400246370ustar00rootroot00000000000000package logrus_test import ( "bytes" "errors" "strings" "testing" log "github.com/go-kit/kit/log/logrus" "github.com/sirupsen/logrus" ) func TestLogrusLogger(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} logrusLogger := logrus.New() logrusLogger.Out = buf logrusLogger.Formatter = &logrus.TextFormatter{TimestampFormat: "02-01-2006 15:04:05", FullTimestamp: true} logger := log.NewLogrusLogger(logrusLogger) if err := logger.Log("hello", "world"); err != nil { t.Fatal(err) } if want, have := "hello=world\n", strings.Split(buf.String(), " ")[3]; want != have { t.Errorf("want %#v, have %#v", want, have) } buf.Reset() if err := logger.Log("a", 1, "err", errors.New("error")); err != nil { t.Fatal(err) } if want, have := "a=1 err=error", strings.TrimSpace(strings.SplitAfterN(buf.String(), " ", 4)[3]); want != have { t.Errorf("want %#v, have %#v", want, have) } buf.Reset() if err := logger.Log("a", 1, "b"); err != nil { t.Fatal(err) } if want, have := "a=1 b=\"(MISSING)\"", strings.TrimSpace(strings.SplitAfterN(buf.String(), " ", 4)[3]); want != have { t.Errorf("want %#v, have %#v", want, have) } buf.Reset() if err := logger.Log("my_map", mymap{0: 0}); err != nil { t.Fatal(err) } if want, have := "my_map=special_behavior", strings.TrimSpace(strings.Split(buf.String(), " ")[3]); want != have { t.Errorf("want %#v, have %#v", want, have) } } type mymap map[int]int func (m mymap) String() string { return "special_behavior" } golang-github-go-kit-kit-0.10.0/log/nop_logger.go000066400000000000000000000003161362256312400215430ustar00rootroot00000000000000package log type nopLogger struct{} // NewNopLogger returns a logger that doesn't do anything. func NewNopLogger() Logger { return nopLogger{} } func (nopLogger) Log(...interface{}) error { return nil } golang-github-go-kit-kit-0.10.0/log/nop_logger_test.go000066400000000000000000000007721362256312400226100ustar00rootroot00000000000000package log_test import ( "testing" "github.com/go-kit/kit/log" ) func TestNopLogger(t *testing.T) { t.Parallel() logger := log.NewNopLogger() if err := logger.Log("abc", 123); err != nil { t.Error(err) } if err := log.With(logger, "def", "ghi").Log(); err != nil { t.Error(err) } } func BenchmarkNopLoggerSimple(b *testing.B) { benchmarkRunner(b, log.NewNopLogger(), baseMessage) } func BenchmarkNopLoggerContextual(b *testing.B) { benchmarkRunner(b, log.NewNopLogger(), withMessage) } golang-github-go-kit-kit-0.10.0/log/stdlib.go000066400000000000000000000062571362256312400207030ustar00rootroot00000000000000package log import ( "io" "log" "regexp" "strings" ) // StdlibWriter implements io.Writer by invoking the stdlib log.Print. It's // designed to be passed to a Go kit logger as the writer, for cases where // it's necessary to redirect all Go kit log output to the stdlib logger. // // If you have any choice in the matter, you shouldn't use this. Prefer to // redirect the stdlib log to the Go kit logger via NewStdlibAdapter. type StdlibWriter struct{} // Write implements io.Writer. func (w StdlibWriter) Write(p []byte) (int, error) { log.Print(strings.TrimSpace(string(p))) return len(p), nil } // StdlibAdapter wraps a Logger and allows it to be passed to the stdlib // logger's SetOutput. It will extract date/timestamps, filenames, and // messages, and place them under relevant keys. type StdlibAdapter struct { Logger timestampKey string fileKey string messageKey string } // StdlibAdapterOption sets a parameter for the StdlibAdapter. type StdlibAdapterOption func(*StdlibAdapter) // TimestampKey sets the key for the timestamp field. By default, it's "ts". func TimestampKey(key string) StdlibAdapterOption { return func(a *StdlibAdapter) { a.timestampKey = key } } // FileKey sets the key for the file and line field. By default, it's "caller". func FileKey(key string) StdlibAdapterOption { return func(a *StdlibAdapter) { a.fileKey = key } } // MessageKey sets the key for the actual log message. By default, it's "msg". func MessageKey(key string) StdlibAdapterOption { return func(a *StdlibAdapter) { a.messageKey = key } } // NewStdlibAdapter returns a new StdlibAdapter wrapper around the passed // logger. It's designed to be passed to log.SetOutput. func NewStdlibAdapter(logger Logger, options ...StdlibAdapterOption) io.Writer { a := StdlibAdapter{ Logger: logger, timestampKey: "ts", fileKey: "caller", messageKey: "msg", } for _, option := range options { option(&a) } return a } func (a StdlibAdapter) Write(p []byte) (int, error) { result := subexps(p) keyvals := []interface{}{} var timestamp string if date, ok := result["date"]; ok && date != "" { timestamp = date } if time, ok := result["time"]; ok && time != "" { if timestamp != "" { timestamp += " " } timestamp += time } if timestamp != "" { keyvals = append(keyvals, a.timestampKey, timestamp) } if file, ok := result["file"]; ok && file != "" { keyvals = append(keyvals, a.fileKey, file) } if msg, ok := result["msg"]; ok { keyvals = append(keyvals, a.messageKey, msg) } if err := a.Logger.Log(keyvals...); err != nil { return 0, err } return len(p), nil } const ( logRegexpDate = `(?P[0-9]{4}/[0-9]{2}/[0-9]{2})?[ ]?` logRegexpTime = `(?P