Moved to google.golang.org/genproto/googleapis/api/annotations
Fixes #52
This commit is contained in:
60
vendor/github.com/go-kit/kit/tracing/README.md
generated
vendored
Normal file
60
vendor/github.com/go-kit/kit/tracing/README.md
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
# package tracing
|
||||
|
||||
`package tracing` provides [Dapper][]-style request tracing to services.
|
||||
|
||||
## Rationale
|
||||
|
||||
Request tracing is a fundamental building block for large distributed
|
||||
applications. It's instrumental in understanding request flows, identifying
|
||||
hot spots, and diagnosing errors. All microservice infrastructures will
|
||||
benefit from request tracing; sufficiently large infrastructures will require
|
||||
it.
|
||||
|
||||
## OpenTracing
|
||||
|
||||
Go kit builds on top of the [OpenTracing] API and uses the [opentracing-go]
|
||||
package to provide tracing middlewares for its servers and clients. Currently
|
||||
`kit/transport/http` and `kit/transport/grpc` transports are supported.
|
||||
|
||||
Since [OpenTracing] is an upcoming standard API, Go kit should support a
|
||||
multitude of tracing backends. If a Tracer implementation in Go for your
|
||||
back-end exists, it should work out of the box. The following tracing back-ends
|
||||
are known to work with Go kit through the OpenTracing interface and are
|
||||
highlighted in the [addsvc] example.
|
||||
|
||||
|
||||
### LightStep
|
||||
|
||||
[LightStep] support is available through their standard Go package
|
||||
[lightstep-tracer-go].
|
||||
|
||||
### AppDash
|
||||
|
||||
[Appdash] support is available straight from their system repository in the
|
||||
[appdash/opentracing] directory.
|
||||
|
||||
### Zipkin
|
||||
|
||||
[Zipkin] support is now available from the [zipkin-go-opentracing] package which
|
||||
can be found at the [Open Zipkin GitHub] page. This means our old custom
|
||||
`tracing/zipkin` package is now deprecated. In the `kit/tracing/zipkin`
|
||||
directory you can still find the `docker-compose` script to bootstrap a Zipkin
|
||||
development environment and a [README] detailing how to transition from the
|
||||
old package to the new.
|
||||
|
||||
[Dapper]: http://research.google.com/pubs/pub36356.html
|
||||
[addsvc]:https://github.com/go-kit/kit/tree/master/examples/addsvc
|
||||
[README]: https://github.com/go-kit/kit/blob/master/tracing/zipkin/README.md
|
||||
|
||||
[OpenTracing]: http://opentracing.io
|
||||
[opentracing-go]: https://github.com/opentracing/opentracing-go
|
||||
|
||||
[Zipkin]: http://zipkin.io/
|
||||
[Open Zipkin GitHub]: https://github.com/openzipkin
|
||||
[zipkin-go-opentracing]: https://github.com/openzipkin/zipkin-go-opentracing
|
||||
|
||||
[Appdash]: https://github.com/sourcegraph/appdash
|
||||
[appdash/opentracing]: https://github.com/sourcegraph/appdash/tree/master/opentracing
|
||||
|
||||
[LightStep]: http://lightstep.com/
|
||||
[lightstep-tracer-go]: https://github.com/lightstep/lightstep-tracer-go
|
8
vendor/github.com/go-kit/kit/tracing/doc.go
generated
vendored
Normal file
8
vendor/github.com/go-kit/kit/tracing/doc.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Package tracing provides helpers and bindings for distributed tracing.
|
||||
//
|
||||
// As your infrastructure grows, it becomes important to be able to trace a
|
||||
// request, as it travels through multiple services and back to the user.
|
||||
// Package tracing provides endpoints and transport helpers and middlewares to
|
||||
// capture and emit request-scoped information. We use the excellent OpenTracing
|
||||
// project to bind to concrete tracing systems.
|
||||
package tracing
|
4
vendor/github.com/go-kit/kit/tracing/opentracing/doc.go
generated
vendored
Normal file
4
vendor/github.com/go-kit/kit/tracing/opentracing/doc.go
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
// Package opentracing provides Go kit integration to the OpenTracing project.
|
||||
// OpenTracing implements a general purpose interface that microservices can
|
||||
// program against, and which adapts to all major distributed tracing systems.
|
||||
package opentracing
|
55
vendor/github.com/go-kit/kit/tracing/opentracing/endpoint.go
generated
vendored
Normal file
55
vendor/github.com/go-kit/kit/tracing/opentracing/endpoint.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
package opentracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
otext "github.com/opentracing/opentracing-go/ext"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
// TraceServer returns a Middleware that wraps the `next` Endpoint in an
|
||||
// OpenTracing Span called `operationName`.
|
||||
//
|
||||
// If `ctx` already has a Span, it is re-used and the operation name is
|
||||
// overwritten. If `ctx` does not yet have a Span, one is created here.
|
||||
func TraceServer(tracer opentracing.Tracer, operationName string) endpoint.Middleware {
|
||||
return func(next endpoint.Endpoint) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
serverSpan := opentracing.SpanFromContext(ctx)
|
||||
if serverSpan == nil {
|
||||
// All we can do is create a new root span.
|
||||
serverSpan = tracer.StartSpan(operationName)
|
||||
} else {
|
||||
serverSpan.SetOperationName(operationName)
|
||||
}
|
||||
defer serverSpan.Finish()
|
||||
otext.SpanKindRPCServer.Set(serverSpan)
|
||||
ctx = opentracing.ContextWithSpan(ctx, serverSpan)
|
||||
return next(ctx, request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TraceClient returns a Middleware that wraps the `next` Endpoint in an
|
||||
// OpenTracing Span called `operationName`.
|
||||
func TraceClient(tracer opentracing.Tracer, operationName string) endpoint.Middleware {
|
||||
return func(next endpoint.Endpoint) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
var clientSpan opentracing.Span
|
||||
if parentSpan := opentracing.SpanFromContext(ctx); parentSpan != nil {
|
||||
clientSpan = tracer.StartSpan(
|
||||
operationName,
|
||||
opentracing.ChildOf(parentSpan.Context()),
|
||||
)
|
||||
} else {
|
||||
clientSpan = tracer.StartSpan(operationName)
|
||||
}
|
||||
defer clientSpan.Finish()
|
||||
otext.SpanKindRPCClient.Set(clientSpan)
|
||||
ctx = opentracing.ContextWithSpan(ctx, clientSpan)
|
||||
return next(ctx, request)
|
||||
}
|
||||
}
|
||||
}
|
117
vendor/github.com/go-kit/kit/tracing/opentracing/endpoint_test.go
generated
vendored
Normal file
117
vendor/github.com/go-kit/kit/tracing/opentracing/endpoint_test.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
package opentracing_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/mocktracer"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
kitot "github.com/go-kit/kit/tracing/opentracing"
|
||||
)
|
||||
|
||||
func TestTraceServer(t *testing.T) {
|
||||
tracer := mocktracer.New()
|
||||
|
||||
// Initialize the ctx with a nameless Span.
|
||||
contextSpan := tracer.StartSpan("").(*mocktracer.MockSpan)
|
||||
ctx := opentracing.ContextWithSpan(context.Background(), contextSpan)
|
||||
|
||||
tracedEndpoint := kitot.TraceServer(tracer, "testOp")(endpoint.Nop)
|
||||
if _, err := tracedEndpoint(ctx, struct{}{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finishedSpans := tracer.FinishedSpans()
|
||||
if want, have := 1, len(finishedSpans); want != have {
|
||||
t.Fatalf("Want %v span(s), found %v", want, have)
|
||||
}
|
||||
|
||||
// Test that the op name is updated
|
||||
endpointSpan := finishedSpans[0]
|
||||
if want, have := "testOp", endpointSpan.OperationName; want != have {
|
||||
t.Fatalf("Want %q, have %q", want, have)
|
||||
}
|
||||
contextContext := contextSpan.Context().(mocktracer.MockSpanContext)
|
||||
endpointContext := endpointSpan.Context().(mocktracer.MockSpanContext)
|
||||
// ...and that the ID is unmodified.
|
||||
if want, have := contextContext.SpanID, endpointContext.SpanID; want != have {
|
||||
t.Errorf("Want SpanID %q, have %q", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTraceServerNoContextSpan(t *testing.T) {
|
||||
tracer := mocktracer.New()
|
||||
|
||||
// Empty/background context.
|
||||
tracedEndpoint := kitot.TraceServer(tracer, "testOp")(endpoint.Nop)
|
||||
if _, err := tracedEndpoint(context.Background(), struct{}{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// tracedEndpoint created a new Span.
|
||||
finishedSpans := tracer.FinishedSpans()
|
||||
if want, have := 1, len(finishedSpans); want != have {
|
||||
t.Fatalf("Want %v span(s), found %v", want, have)
|
||||
}
|
||||
|
||||
endpointSpan := finishedSpans[0]
|
||||
if want, have := "testOp", endpointSpan.OperationName; want != have {
|
||||
t.Fatalf("Want %q, have %q", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTraceClient(t *testing.T) {
|
||||
tracer := mocktracer.New()
|
||||
|
||||
// Initialize the ctx with a parent Span.
|
||||
parentSpan := tracer.StartSpan("parent").(*mocktracer.MockSpan)
|
||||
defer parentSpan.Finish()
|
||||
ctx := opentracing.ContextWithSpan(context.Background(), parentSpan)
|
||||
|
||||
tracedEndpoint := kitot.TraceClient(tracer, "testOp")(endpoint.Nop)
|
||||
if _, err := tracedEndpoint(ctx, struct{}{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// tracedEndpoint created a new Span.
|
||||
finishedSpans := tracer.FinishedSpans()
|
||||
if want, have := 1, len(finishedSpans); want != have {
|
||||
t.Fatalf("Want %v span(s), found %v", want, have)
|
||||
}
|
||||
|
||||
endpointSpan := finishedSpans[0]
|
||||
if want, have := "testOp", endpointSpan.OperationName; want != have {
|
||||
t.Fatalf("Want %q, have %q", want, have)
|
||||
}
|
||||
|
||||
parentContext := parentSpan.Context().(mocktracer.MockSpanContext)
|
||||
endpointContext := parentSpan.Context().(mocktracer.MockSpanContext)
|
||||
|
||||
// ... and that the parent ID is set appropriately.
|
||||
if want, have := parentContext.SpanID, endpointContext.SpanID; want != have {
|
||||
t.Errorf("Want ParentID %q, have %q", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTraceClientNoContextSpan(t *testing.T) {
|
||||
tracer := mocktracer.New()
|
||||
|
||||
// Empty/background context.
|
||||
tracedEndpoint := kitot.TraceClient(tracer, "testOp")(endpoint.Nop)
|
||||
if _, err := tracedEndpoint(context.Background(), struct{}{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// tracedEndpoint created a new Span.
|
||||
finishedSpans := tracer.FinishedSpans()
|
||||
if want, have := 1, len(finishedSpans); want != have {
|
||||
t.Fatalf("Want %v span(s), found %v", want, have)
|
||||
}
|
||||
|
||||
endpointSpan := finishedSpans[0]
|
||||
if want, have := "testOp", endpointSpan.OperationName; want != have {
|
||||
t.Fatalf("Want %q, have %q", want, have)
|
||||
}
|
||||
}
|
70
vendor/github.com/go-kit/kit/tracing/opentracing/grpc.go
generated
vendored
Normal file
70
vendor/github.com/go-kit/kit/tracing/opentracing/grpc.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
package opentracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
)
|
||||
|
||||
// ToGRPCRequest returns a grpc RequestFunc that injects an OpenTracing Span
|
||||
// found in `ctx` into the grpc Metadata. If no such Span can be found, the
|
||||
// RequestFunc is a noop.
|
||||
func ToGRPCRequest(tracer opentracing.Tracer, logger log.Logger) func(ctx context.Context, md *metadata.MD) context.Context {
|
||||
return func(ctx context.Context, md *metadata.MD) context.Context {
|
||||
if span := opentracing.SpanFromContext(ctx); span != nil {
|
||||
// There's nothing we can do with an error here.
|
||||
if err := tracer.Inject(span.Context(), opentracing.TextMap, metadataReaderWriter{md}); err != nil {
|
||||
logger.Log("err", err)
|
||||
}
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
}
|
||||
|
||||
// FromGRPCRequest returns a grpc RequestFunc that tries to join with an
|
||||
// OpenTracing trace found in `req` and starts a new Span called
|
||||
// `operationName` accordingly. If no trace could be found in `req`, the Span
|
||||
// will be a trace root. The Span is incorporated in the returned Context and
|
||||
// can be retrieved with opentracing.SpanFromContext(ctx).
|
||||
func FromGRPCRequest(tracer opentracing.Tracer, operationName string, logger log.Logger) func(ctx context.Context, md metadata.MD) context.Context {
|
||||
return func(ctx context.Context, md metadata.MD) context.Context {
|
||||
var span opentracing.Span
|
||||
wireContext, err := tracer.Extract(opentracing.TextMap, metadataReaderWriter{&md})
|
||||
if err != nil && err != opentracing.ErrSpanContextNotFound {
|
||||
logger.Log("err", err)
|
||||
}
|
||||
span = tracer.StartSpan(operationName, ext.RPCServerOption(wireContext))
|
||||
return opentracing.ContextWithSpan(ctx, span)
|
||||
}
|
||||
}
|
||||
|
||||
// A type that conforms to opentracing.TextMapReader and
|
||||
// opentracing.TextMapWriter.
|
||||
type metadataReaderWriter struct {
|
||||
*metadata.MD
|
||||
}
|
||||
|
||||
func (w metadataReaderWriter) Set(key, val string) {
|
||||
key = strings.ToLower(key)
|
||||
if strings.HasSuffix(key, "-bin") {
|
||||
val = string(base64.StdEncoding.EncodeToString([]byte(val)))
|
||||
}
|
||||
(*w.MD)[key] = append((*w.MD)[key], val)
|
||||
}
|
||||
|
||||
func (w metadataReaderWriter) ForeachKey(handler func(key, val string) error) error {
|
||||
for k, vals := range *w.MD {
|
||||
for _, v := range vals {
|
||||
if err := handler(k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
64
vendor/github.com/go-kit/kit/tracing/opentracing/grpc_test.go
generated
vendored
Normal file
64
vendor/github.com/go-kit/kit/tracing/opentracing/grpc_test.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
package opentracing_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/mocktracer"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
kitot "github.com/go-kit/kit/tracing/opentracing"
|
||||
)
|
||||
|
||||
func TestTraceGRPCRequestRoundtrip(t *testing.T) {
|
||||
logger := log.NewNopLogger()
|
||||
tracer := mocktracer.New()
|
||||
|
||||
// Initialize the ctx with a Span to inject.
|
||||
beforeSpan := tracer.StartSpan("to_inject").(*mocktracer.MockSpan)
|
||||
defer beforeSpan.Finish()
|
||||
beforeSpan.SetBaggageItem("baggage", "check")
|
||||
beforeCtx := opentracing.ContextWithSpan(context.Background(), beforeSpan)
|
||||
|
||||
toGRPCFunc := kitot.ToGRPCRequest(tracer, logger)
|
||||
md := metadata.Pairs()
|
||||
// Call the RequestFunc.
|
||||
afterCtx := toGRPCFunc(beforeCtx, &md)
|
||||
|
||||
// The Span should not have changed.
|
||||
afterSpan := opentracing.SpanFromContext(afterCtx)
|
||||
if beforeSpan != afterSpan {
|
||||
t.Error("Should not swap in a new span")
|
||||
}
|
||||
|
||||
// No spans should have finished yet.
|
||||
finishedSpans := tracer.FinishedSpans()
|
||||
if want, have := 0, len(finishedSpans); want != have {
|
||||
t.Errorf("Want %v span(s), found %v", want, have)
|
||||
}
|
||||
|
||||
// Use FromGRPCRequest to verify that we can join with the trace given MD.
|
||||
fromGRPCFunc := kitot.FromGRPCRequest(tracer, "joined", logger)
|
||||
joinCtx := fromGRPCFunc(afterCtx, md)
|
||||
joinedSpan := opentracing.SpanFromContext(joinCtx).(*mocktracer.MockSpan)
|
||||
|
||||
joinedContext := joinedSpan.Context().(mocktracer.MockSpanContext)
|
||||
beforeContext := beforeSpan.Context().(mocktracer.MockSpanContext)
|
||||
|
||||
if joinedContext.SpanID == beforeContext.SpanID {
|
||||
t.Error("SpanID should have changed", joinedContext.SpanID, beforeContext.SpanID)
|
||||
}
|
||||
|
||||
// Check that the parent/child relationship is as expected for the joined span.
|
||||
if want, have := beforeContext.SpanID, joinedSpan.ParentID; want != have {
|
||||
t.Errorf("Want ParentID %q, have %q", want, have)
|
||||
}
|
||||
if want, have := "joined", joinedSpan.OperationName; want != have {
|
||||
t.Errorf("Want %q, have %q", want, have)
|
||||
}
|
||||
if want, have := "check", joinedSpan.BaggageItem("baggage"); want != have {
|
||||
t.Errorf("Want %q, have %q", want, have)
|
||||
}
|
||||
}
|
71
vendor/github.com/go-kit/kit/tracing/opentracing/http.go
generated
vendored
Normal file
71
vendor/github.com/go-kit/kit/tracing/opentracing/http.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
package opentracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
kithttp "github.com/go-kit/kit/transport/http"
|
||||
)
|
||||
|
||||
// ToHTTPRequest returns an http RequestFunc that injects an OpenTracing Span
|
||||
// found in `ctx` into the http headers. If no such Span can be found, the
|
||||
// RequestFunc is a noop.
|
||||
func ToHTTPRequest(tracer opentracing.Tracer, logger log.Logger) kithttp.RequestFunc {
|
||||
return func(ctx context.Context, req *http.Request) context.Context {
|
||||
// Try to find a Span in the Context.
|
||||
if span := opentracing.SpanFromContext(ctx); span != nil {
|
||||
// Add standard OpenTracing tags.
|
||||
ext.HTTPMethod.Set(span, req.Method)
|
||||
ext.HTTPUrl.Set(span, req.URL.String())
|
||||
host, portString, err := net.SplitHostPort(req.URL.Host)
|
||||
if err == nil {
|
||||
ext.PeerHostname.Set(span, host)
|
||||
if port, err := strconv.Atoi(portString); err != nil {
|
||||
ext.PeerPort.Set(span, uint16(port))
|
||||
}
|
||||
} else {
|
||||
ext.PeerHostname.Set(span, req.URL.Host)
|
||||
}
|
||||
|
||||
// There's nothing we can do with any errors here.
|
||||
if err = tracer.Inject(
|
||||
span.Context(),
|
||||
opentracing.TextMap,
|
||||
opentracing.HTTPHeadersCarrier(req.Header),
|
||||
); err != nil {
|
||||
logger.Log("err", err)
|
||||
}
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
}
|
||||
|
||||
// FromHTTPRequest returns an http RequestFunc that tries to join with an
|
||||
// OpenTracing trace found in `req` and starts a new Span called
|
||||
// `operationName` accordingly. If no trace could be found in `req`, the Span
|
||||
// will be a trace root. The Span is incorporated in the returned Context and
|
||||
// can be retrieved with opentracing.SpanFromContext(ctx).
|
||||
func FromHTTPRequest(tracer opentracing.Tracer, operationName string, logger log.Logger) kithttp.RequestFunc {
|
||||
return func(ctx context.Context, req *http.Request) context.Context {
|
||||
// Try to join to a trace propagated in `req`.
|
||||
var span opentracing.Span
|
||||
wireContext, err := tracer.Extract(
|
||||
opentracing.TextMap,
|
||||
opentracing.HTTPHeadersCarrier(req.Header),
|
||||
)
|
||||
if err != nil && err != opentracing.ErrSpanContextNotFound {
|
||||
logger.Log("err", err)
|
||||
}
|
||||
|
||||
span = tracer.StartSpan(operationName, ext.RPCServerOption(wireContext))
|
||||
ext.HTTPMethod.Set(span, req.Method)
|
||||
ext.HTTPUrl.Set(span, req.URL.String())
|
||||
return opentracing.ContextWithSpan(ctx, span)
|
||||
}
|
||||
}
|
109
vendor/github.com/go-kit/kit/tracing/opentracing/http_test.go
generated
vendored
Normal file
109
vendor/github.com/go-kit/kit/tracing/opentracing/http_test.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
package opentracing_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"github.com/opentracing/opentracing-go/mocktracer"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
kitot "github.com/go-kit/kit/tracing/opentracing"
|
||||
)
|
||||
|
||||
func TestTraceHTTPRequestRoundtrip(t *testing.T) {
|
||||
logger := log.NewNopLogger()
|
||||
tracer := mocktracer.New()
|
||||
|
||||
// Initialize the ctx with a Span to inject.
|
||||
beforeSpan := tracer.StartSpan("to_inject").(*mocktracer.MockSpan)
|
||||
defer beforeSpan.Finish()
|
||||
beforeSpan.SetBaggageItem("baggage", "check")
|
||||
beforeCtx := opentracing.ContextWithSpan(context.Background(), beforeSpan)
|
||||
|
||||
toHTTPFunc := kitot.ToHTTPRequest(tracer, logger)
|
||||
req, _ := http.NewRequest("GET", "http://test.biz/path", nil)
|
||||
// Call the RequestFunc.
|
||||
afterCtx := toHTTPFunc(beforeCtx, req)
|
||||
|
||||
// The Span should not have changed.
|
||||
afterSpan := opentracing.SpanFromContext(afterCtx)
|
||||
if beforeSpan != afterSpan {
|
||||
t.Error("Should not swap in a new span")
|
||||
}
|
||||
|
||||
// No spans should have finished yet.
|
||||
finishedSpans := tracer.FinishedSpans()
|
||||
if want, have := 0, len(finishedSpans); want != have {
|
||||
t.Errorf("Want %v span(s), found %v", want, have)
|
||||
}
|
||||
|
||||
// Use FromHTTPRequest to verify that we can join with the trace given a req.
|
||||
fromHTTPFunc := kitot.FromHTTPRequest(tracer, "joined", logger)
|
||||
joinCtx := fromHTTPFunc(afterCtx, req)
|
||||
joinedSpan := opentracing.SpanFromContext(joinCtx).(*mocktracer.MockSpan)
|
||||
|
||||
joinedContext := joinedSpan.Context().(mocktracer.MockSpanContext)
|
||||
beforeContext := beforeSpan.Context().(mocktracer.MockSpanContext)
|
||||
|
||||
if joinedContext.SpanID == beforeContext.SpanID {
|
||||
t.Error("SpanID should have changed", joinedContext.SpanID, beforeContext.SpanID)
|
||||
}
|
||||
|
||||
// Check that the parent/child relationship is as expected for the joined span.
|
||||
if want, have := beforeContext.SpanID, joinedSpan.ParentID; want != have {
|
||||
t.Errorf("Want ParentID %q, have %q", want, have)
|
||||
}
|
||||
if want, have := "joined", joinedSpan.OperationName; want != have {
|
||||
t.Errorf("Want %q, have %q", want, have)
|
||||
}
|
||||
if want, have := "check", joinedSpan.BaggageItem("baggage"); want != have {
|
||||
t.Errorf("Want %q, have %q", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToHTTPRequestTags(t *testing.T) {
|
||||
tracer := mocktracer.New()
|
||||
span := tracer.StartSpan("to_inject").(*mocktracer.MockSpan)
|
||||
defer span.Finish()
|
||||
ctx := opentracing.ContextWithSpan(context.Background(), span)
|
||||
req, _ := http.NewRequest("GET", "http://test.biz/path", nil)
|
||||
|
||||
kitot.ToHTTPRequest(tracer, log.NewNopLogger())(ctx, req)
|
||||
|
||||
expectedTags := map[string]interface{}{
|
||||
string(ext.HTTPMethod): "GET",
|
||||
string(ext.HTTPUrl): "http://test.biz/path",
|
||||
string(ext.PeerHostname): "test.biz",
|
||||
}
|
||||
if !reflect.DeepEqual(expectedTags, span.Tags()) {
|
||||
t.Errorf("Want %q, have %q", expectedTags, span.Tags())
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromHTTPRequestTags(t *testing.T) {
|
||||
tracer := mocktracer.New()
|
||||
parentSpan := tracer.StartSpan("to_extract").(*mocktracer.MockSpan)
|
||||
defer parentSpan.Finish()
|
||||
req, _ := http.NewRequest("GET", "http://test.biz/path", nil)
|
||||
tracer.Inject(parentSpan.Context(), opentracing.TextMap, opentracing.HTTPHeadersCarrier(req.Header))
|
||||
|
||||
ctx := kitot.FromHTTPRequest(tracer, "op", log.NewNopLogger())(context.Background(), req)
|
||||
opentracing.SpanFromContext(ctx).Finish()
|
||||
|
||||
childSpan := tracer.FinishedSpans()[0]
|
||||
expectedTags := map[string]interface{}{
|
||||
string(ext.HTTPMethod): "GET",
|
||||
string(ext.HTTPUrl): "http://test.biz/path",
|
||||
string(ext.SpanKind): ext.SpanKindRPCServerEnum,
|
||||
}
|
||||
if !reflect.DeepEqual(expectedTags, childSpan.Tags()) {
|
||||
t.Errorf("Want %q, have %q", expectedTags, childSpan.Tags())
|
||||
}
|
||||
if want, have := "op", childSpan.OperationName; want != have {
|
||||
t.Errorf("Want %q, have %q", want, have)
|
||||
}
|
||||
}
|
178
vendor/github.com/go-kit/kit/tracing/zipkin/README.md
generated
vendored
Normal file
178
vendor/github.com/go-kit/kit/tracing/zipkin/README.md
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
# Zipkin
|
||||
|
||||
## Development and Testing Set-up
|
||||
|
||||
Great efforts have been made to make [Zipkin] easier to test, develop and
|
||||
experiment against. [Zipkin] can now be run from a single Docker container or by
|
||||
running its self-contained executable jar without extensive configuration. In
|
||||
its default configuration you will run Zipkin with a HTTP collector, In memory
|
||||
Span storage backend and web UI on port 9411.
|
||||
|
||||
Example:
|
||||
```
|
||||
docker run -d -p 9411:9411 openzipkin/zipkin
|
||||
```
|
||||
|
||||
[zipkin]: http://zipkin.io
|
||||
|
||||
Instrumenting your services with Zipkin distributed tracing using the default
|
||||
configuration is now possible with the latest release of [zipkin-go-opentracing]
|
||||
as it includes an HTTP transport for sending spans to the [Zipkin] HTTP
|
||||
Collector.
|
||||
|
||||
## Middleware Usage
|
||||
|
||||
Follow the [addsvc] example to check out how to wire the Zipkin Middleware. The
|
||||
changes should be relatively minor.
|
||||
|
||||
The [zipkin-go-opentracing] package has support for HTTP, Kafka and Scribe
|
||||
collectors as well as using Go Kit's [Log] package for logging.
|
||||
|
||||
### Configuring for the Zipkin HTTP Collector
|
||||
|
||||
To select the transport for the HTTP Collector, you configure the `Recorder`
|
||||
with the appropriate collector like this:
|
||||
|
||||
```go
|
||||
var (
|
||||
debugMode = false
|
||||
serviceName = "MyService"
|
||||
serviceHostPort = "localhost:8000"
|
||||
zipkinHTTPEndpoint = "localhost:9411"
|
||||
)
|
||||
collector, err = zipkin.NewHTTPCollector(zipkinHTTPEndpoint)
|
||||
if err != nil {
|
||||
// handle error
|
||||
}
|
||||
tracer, err = zipkin.NewTracer(
|
||||
zipkin.NewRecorder(collector, debugMode, serviceHostPort, serviceName),
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
### Span per Node vs. Span per RPC
|
||||
By default Zipkin V1 considers either side of an RPC to have the same identity
|
||||
and differs in that respect from many other tracing systems which consider the
|
||||
caller to be the parent and the receiver to be the child. The OpenTracing
|
||||
specification does not dictate one model over the other, but the Zipkin team is
|
||||
looking into these [single-host-spans] to potentially bring Zipkin more in-line
|
||||
with the other tracing systems.
|
||||
|
||||
[single-host-spans]: https://github.com/openzipkin/zipkin/issues/963
|
||||
|
||||
In case of a `span per node` the receiver will create a child span from the
|
||||
propagated parent span like this:
|
||||
|
||||
```
|
||||
Span per Node propagation and identities
|
||||
|
||||
CALLER: RECEIVER:
|
||||
---------------------------------
|
||||
traceId -> traceId
|
||||
spanId (new)
|
||||
spanId -> parentSpanId
|
||||
parentSpanId
|
||||
```
|
||||
|
||||
**Note:** most tracing implementations supporting the `span per node` model
|
||||
therefore do not propagate their `parentSpanID` as its not needed.
|
||||
|
||||
A typical Zipkin implementation will use the `span per RPC` model and recreate
|
||||
the span identity from the caller on the receiver's end and then annotates its
|
||||
values on top of it. Propagation will happen like this:
|
||||
|
||||
```
|
||||
Span per RPC propagation and identities
|
||||
|
||||
CALLER: RECEIVER:
|
||||
---------------------------------
|
||||
traceId -> traceId
|
||||
spanId -> spanId
|
||||
parentSpanId -> parentSpanId
|
||||
```
|
||||
|
||||
The [zipkin-go-opentracing] implementation allows you to choose which model you
|
||||
wish to use. Make sure you select the same model consistently for all your
|
||||
services that are required to communicate with each other or you will have trace
|
||||
propagation issues. If using non OpenTracing / legacy instrumentation, it's
|
||||
probably best to use the `span per RPC call` model.
|
||||
|
||||
To adhere to the more common tracing philosophy of `span per node`, the Tracer
|
||||
defaults to `span per node`. To set the `span per RPC call` mode start your
|
||||
tracer like this:
|
||||
|
||||
```go
|
||||
tracer, err = zipkin.NewTracer(
|
||||
zipkin.NewRecorder(...),
|
||||
zipkin.ClientServerSameSpan(true),
|
||||
)
|
||||
```
|
||||
|
||||
[zipkin-go-opentracing]: https://github.com/openzipkin/zipkin-go-opentracing
|
||||
[addsvc]:https://github.com/go-kit/kit/tree/master/examples/addsvc
|
||||
[Log]: https://github.com/go-kit/kit/tree/master/log
|
||||
|
||||
### Tracing Resources
|
||||
|
||||
In our legacy implementation we had the `NewChildSpan` method to allow
|
||||
annotation of resources such as databases, caches and other services that do not
|
||||
have server side tracing support. Since OpenTracing has no specific method of
|
||||
dealing with these items explicitely that is compatible with Zipkin's `SA`
|
||||
annotation, the [zipkin-go-opentracing] has implemented support using the
|
||||
OpenTracing Tags system. Here is an example of how one would be able to record
|
||||
a resource span compatible with standard OpenTracing and triggering an `SA`
|
||||
annotation in [zipkin-go-opentracing]:
|
||||
|
||||
```go
|
||||
// you need to import the ext package for the Tag helper functions
|
||||
import (
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
)
|
||||
|
||||
func (svc *Service) GetMeSomeExamples(ctx context.Context, ...) ([]Examples, error) {
|
||||
// Example of annotating a database query:
|
||||
var (
|
||||
serviceName = "MySQL"
|
||||
serviceHost = "mysql.example.com"
|
||||
servicePort = uint16(3306)
|
||||
queryLabel = "GetExamplesByParam"
|
||||
query = "select * from example where param = 'value'"
|
||||
)
|
||||
|
||||
// retrieve the parent span, if not found create a new trace
|
||||
parentSpan := opentracing.SpanFromContext(ctx)
|
||||
if parentSpan == nil {
|
||||
parentSpan = opentracing.StartSpan(queryLabel)
|
||||
defer parentSpan.Finish()
|
||||
}
|
||||
|
||||
// create a new span to record the resource interaction
|
||||
span := opentracing.StartChildSpan(parentSpan, queryLabel)
|
||||
|
||||
// span.kind "resource" triggers SA annotation
|
||||
ext.SpanKind.Set(span, "resource")
|
||||
|
||||
// this will label the span's service & hostPort (called Endpoint in Zipkin)
|
||||
ext.PeerService.Set(span, serviceName)
|
||||
ext.PeerHostname.Set(span, serviceHost)
|
||||
ext.PeerPort.Set(span, servicePort)
|
||||
|
||||
// a Tag is the equivalent of a Zipkin Binary Annotation (key:value pair)
|
||||
span.SetTag("query", query)
|
||||
|
||||
// a LogEvent is the equivalent of a Zipkin Annotation (timestamped)
|
||||
span.LogEvent("query:start")
|
||||
|
||||
// do the actual query...
|
||||
|
||||
// let's annotate the end...
|
||||
span.LogEvent("query:end")
|
||||
|
||||
// we're done with this span.
|
||||
span.Finish()
|
||||
|
||||
// do other stuff
|
||||
...
|
||||
}
|
||||
```
|
Reference in New Issue
Block a user