diff --git a/README.md b/README.md index 6a329c7..6d25e50 100644 --- a/README.md +++ b/README.md @@ -12,24 +12,24 @@ ## Goals - Operate in a heterogeneous SOA — expect to interact with mostly non-gokit services -- RPC as the messaging pattern +- RPC as the primary messaging pattern - Pluggable serialization and transport — not just JSON over HTTP - Zipkin-compatible request tracing ## Non-goals -- Supporting messaging patterns other than RPC — pub/sub, CQRS, etc. +- Supporting messaging patterns other than RPC (in the initial release) — pub/sub, CQRS, etc. - Having opinions on deployment, orchestration, process supervision, etc. -- Having opinions on configuration passing, i.e. flags, env vars, files, etc. +- Having opinions on configuration passing — flags, env vars, files, etc. ## Component status -- API stability — adopted -- `package metrics` — [implemented](https://github.com/go-kit/kit/tree/master/metrics) -- `package server` — [implemented](https://github.com/go-kit/kit/tree/master/server) -- `package transport` — [implemented](https://github.com/go-kit/kit/tree/master/transport) -- `package log` — [implemented](https://github.com/go-kit/kit/tree/master/log) -- `package tracing` — [prototyping](Https://github.com/go-kit/kit/tree/master/tracing) +- [API stability](https://github.com/go-kit/kit/blob/master/rfc/rfc007-api-stability.md) — **adopted** +- [`package metrics`](https://github.com/go-kit/kit/tree/master/metrics) — **implemented** +- [`package server`](https://github.com/go-kit/kit/tree/master/server) — **implemented** +- [`package transport`](https://github.com/go-kit/kit/tree/master/transport) — **implemented** +- [`package log`](https://github.com/go-kit/kit/tree/master/log) — **implemented** +- [`package tracing`](https://github.com/go-kit/kit/tree/master/tracing) — prototyping - `package client` — pending - Service discovery — pending @@ -102,7 +102,7 @@ - [Gorilla](http://www.gorillatoolkit.org) - [Martini](https://github.com/go-martini/martini) - [Negroni](https://github.com/codegangsta/negroni) -- [Revel](https://revel.github.io/) +- [Revel](https://revel.github.io/) (considered harmful) ## Additional reading diff --git a/addsvc/README.md b/addsvc/README.md new file mode 100644 index 0000000..605058d --- /dev/null +++ b/addsvc/README.md @@ -0,0 +1,17 @@ +# addsvc + +addsvc is an example service, used to illustrate the mechanics of gokit. +It exposes simple functionality on a variety of transports and endpoints. + +## Server + +To build and run addsvc, + +``` +$ go install +$ addsvc +``` + +## Client + +TODO diff --git a/log/README.md b/log/README.md new file mode 100644 index 0000000..57d22c9 --- /dev/null +++ b/log/README.md @@ -0,0 +1,54 @@ +# package log + +`package log` provides a minimal interface for structured logging in services. +It may be wrapped to encode conventions, enforce type-safety, etc. +It can be used for both typical application log events, and log-structured data streams. + +## Rationale + +TODO + +## Usage + +Typical application logging. + +```go +import "github.com/go-kit/kit/log" + +func main() { + logger := log.NewPrefixLogger(os.Stderr) + logger.Log("question", "what is the meaning of life?", "answer", 42) +} +``` + +Contextual logging. + +```go +func handle(logger log.Logger, req *Request) { + logger = log.With(logger, "txid", req.TransactionID, "query", req.Query) + logger.Log() + + answer, err := process(logger, req.Query) + if err != nil { + logger.Log("err", err) + return + } + + logger.Log("answer", answer) +} +``` + +Redirect stdlib log to gokit logger. + +```go +import ( + "os" + stdlog "log" + kitlog "github.com/go-kit/kit/log" +) + +func main() { + logger := kitlog.NewJSONLogger(os.Stdout) + stdlog.SetOutput(kitlog.NewStdlibAdapter(logger)) +} +``` diff --git a/log/stdlib.go b/log/stdlib.go index 9a6d130..2f8f532 100644 --- a/log/stdlib.go +++ b/log/stdlib.go @@ -9,7 +9,10 @@ // StdlibWriter implements io.Writer by invoking the stdlib log.Print. It's // designed to be passed to a gokit logger as the writer, for cases where it's -// desirable to pipe all log output to the same, canonical destination. +// necessary to redirect all gokit 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 gokit logger via NewStdlibAdapter. type StdlibWriter struct{} // Write implements io.Writer. diff --git a/metrics/README.md b/metrics/README.md new file mode 100644 index 0000000..7f2ebf4 --- /dev/null +++ b/metrics/README.md @@ -0,0 +1,54 @@ +# package metrics + +`package metrics` provides a set of uniform interfaces for service instrumentation. +It has **[counters][]**, **[gauges][]**, and **[histograms][]**, + and provides adapters to popular metrics packages, like **[expvar][]**, **[statsd][]**, and **[Prometheus][]**. + +[counters]: http://prometheus.io/docs/concepts/metric_types/#counter +[gauges]: http://prometheus.io/docs/concepts/metric_types/#gauge +[histograms]: http://prometheus.io/docs/concepts/metric_types/#histogram +[expvar]: https://golang.org/pkg/expvar +[statsd]: https://github.com/etsy/statsd +[Prometheus]: http://prometheus.io + +## Rationale + +TODO + +## Usage + +A simple counter, exported via expvar. + +```go +import "github.com/go-kit/kit/metrics/expvar" + +func main() { + myCount := expvar.NewCounter("my_count") + myCount.Add(1) +} +``` + +A histogram for request duration, exported via a Prometheus summary with +dynamically-computed quantiles. + +```go +import ( + stdprometheus "github.com/prometheus/client_golang/prometheus" + + "github.com/go-kit/kit/metrics" + "github.com/go-kit/kit/metrics/prometheus" + "github.com/go-kit/kit/metrics/statsd" +) + +var requestDuration = prometheus.NewSummary(stdprometheus.SummaryOpts{ + Namespace: "myservice", + Subsystem: "api", + Name: "request_duration_nanoseconds_count", + Help: "Total time spent serving requests.", +}, []string{}) + +func handleRequest() { + defer func(begin time.Time) { requestDuration.Observe(time.Since(begin)) }(time.Now()) + // handle request +} +``` diff --git a/server/README.md b/server/README.md new file mode 100644 index 0000000..cdbdb69 --- /dev/null +++ b/server/README.md @@ -0,0 +1,13 @@ +# package server + +`package server` is a very small package that collects interfaces used by services. +Most server-side functionality is actually implemented by surrounding packages. + +# Rationale + +TODO + +# Usage + +As currently defined, you shouldn't need to use `package server` directly. +Other gokit components integrate on `package server` interfaces. diff --git a/tracing/README.md b/tracing/README.md new file mode 100644 index 0000000..f277844 --- /dev/null +++ b/tracing/README.md @@ -0,0 +1,40 @@ +# package tracing + +`package tracing` provides [Dapper-style][dapper] request tracing to services. +An implementation exists for [Zipkin][]; [Appdash][] support is planned. + +[dapper]: http://research.google.com/pubs/pub36356.html +[Zipkin]: https://blog.twitter.com/2012/distributed-systems-tracing-with-zipkin +[Appdash]: https://sourcegraph.com/blog/117580140734 + +## Rationale + +TODO + +## Usage + +Wrap a [server.Endpoint][] so that it emits traces to a Zipkin collector. + +[server.Endpoint]: http://godoc.org/github.com/go-kit/kit/server#Endpoint + +```go +func main() { + var ( + myHost = "instance01.addsvc.internal.net" + myMethod = "ADD" + scribeHost = "scribe.internal.net" + timeout = 50 * time.Millisecond + batchSize = 100 + batchInterval = 3 * time.Second + ) + + spanFunc := zipkin.NewSpanFunc(myHost, myMethod) + collector, _ := zipkin.NewScribeCollector(scribeHost, timeout, batchSize, batchInterval) + + var e server.Endpoint + e = makeEndpoint() // for your service + e = zipkin.AnnotateEndpoint(spanFunc, collector) + + serve(e) +} +``` diff --git a/transport/README.md b/transport/README.md new file mode 100644 index 0000000..1751db8 --- /dev/null +++ b/transport/README.md @@ -0,0 +1,50 @@ +# package transport + +`package transport` defines interfaces for service transports and codecs. +It also provides implementations for transports and codecs that aren't already well-defined by other packages. +The most common use case for `package transport` is probably to bind a gokit [server.Endpoint][] with a stdlib [http.Handler][], via gokit's [http.Binding][]. +Refer to the [addsvc][] example service to see how to make e.g. [Thrift][] or [gRPC][] transport bindings. + +[server.Endpoint]: https://godoc.org/github.com/go-kit/kit/server/#Endpoint +[http.Handler]: https://golang.org/pkg/net/http/#Handler +[http.Binding]: https://godoc.org/github.com/go-kit/kit/transport/http/#Binding +[addsvc]: https://github.com/go-kit/kit/blob/319c1c7129a146b541bbbaf18e2502bf32c603c5/addsvc/main.go +[Thrift]: https://github.com/go-kit/kit/blob/319c1c7129a146b541bbbaf18e2502bf32c603c5/addsvc/main.go#L142-192 +[gRPC]: https://github.com/go-kit/kit/blob/319c1c7129a146b541bbbaf18e2502bf32c603c5/addsvc/main.go#L102-119 + +## Rationale + +TODO + +## Usage + +Bind a gokit [server.Endpoint][] with a stdlib [http.Handler][]. + +```go +import ( + "net/http" + "reflect" + + "golang.org/x/net/context" + + jsoncodec "github.com/go-kit/kit/transport/codec/json" + httptransport "github.com/go-kit/kit/transport/http" +) + +type request struct{} + +func main() { + var ( + ctx = context.Background() + requestType = reflect.TypeOf(request{}) + codec = jsoncodec.New() + e = makeEndpoint() + before = []httptransport.BeforeFunc{} + after = []httptransport.AfterFunc{} + ) + handler := httptransport.NewBinding(ctx, requestType, codec, e, before, after) + mux := http.NewServeMux() + mux.Handle("/path", handler) + http.ListenAndServe(":8080", mux) +} +```