Moved to google.golang.org/genproto/googleapis/api/annotations

Fixes #52
This commit is contained in:
Valerio Gheri
2017-03-31 18:01:58 +02:00
parent 024c5a4e4e
commit c40779224f
2037 changed files with 831329 additions and 1854 deletions

View 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

View 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)
}
}
}

View 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)
}
}

View 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
}

View 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)
}
}

View 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)
}
}

View 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)
}
}