Codebase list golang-github-go-kit-kit / f9d8373b-9935-4125-b2b2-694ccabcf82b/v0.10.0 tracing / opencensus / http.go
f9d8373b-9935-4125-b2b2-694ccabcf82b/v0.10.0

Tree @f9d8373b-9935-4125-b2b2-694ccabcf82b/v0.10.0 (Download .tar.gz)

http.go @f9d8373b-9935-4125-b2b2-694ccabcf82b/v0.10.0

4431eb8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4ce0cba
4431eb8
 
 
 
 
4ce0cba
 
 
 
4431eb8
 
 
 
4ce0cba
 
4431eb8
 
 
 
 
19a2639
492fed7
4431eb8
492fed7
 
4431eb8
 
 
 
 
 
 
 
 
4ce0cba
 
4431eb8
 
19a2639
4431eb8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4ce0cba
4431eb8
 
 
 
 
4ce0cba
 
 
 
4431eb8
 
 
 
 
 
 
 
 
4ce0cba
 
4431eb8
 
 
 
4ce0cba
 
4431eb8
 
 
 
 
4ce0cba
4431eb8
 
 
 
 
 
4ce0cba
4431eb8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
package opencensus

import (
	"context"
	"net/http"

	"go.opencensus.io/plugin/ochttp"
	"go.opencensus.io/plugin/ochttp/propagation/b3"
	"go.opencensus.io/trace"

	kithttp "github.com/go-kit/kit/transport/http"
)

// HTTPClientTrace enables OpenCensus tracing of a Go kit HTTP transport client.
func HTTPClientTrace(options ...TracerOption) kithttp.ClientOption {
	cfg := TracerOptions{}

	for _, option := range options {
		option(&cfg)
	}

	if !cfg.Public && cfg.HTTPPropagate == nil {
		cfg.HTTPPropagate = &b3.HTTPFormat{}
	}

	clientBefore := kithttp.ClientBefore(
		func(ctx context.Context, req *http.Request) context.Context {
			var name string

			if cfg.Name != "" {
				name = cfg.Name
			} else {
				// OpenCensus states Path being default naming for a client span
				name = req.Method + " " + req.URL.Path
			}

			ctx, span := trace.StartSpan(
				ctx,
				name,
				trace.WithSampler(cfg.Sampler),
				trace.WithSpanKind(trace.SpanKindClient),
			)

			span.AddAttributes(
				trace.StringAttribute(ochttp.HostAttribute, req.URL.Host),
				trace.StringAttribute(ochttp.MethodAttribute, req.Method),
				trace.StringAttribute(ochttp.PathAttribute, req.URL.Path),
				trace.StringAttribute(ochttp.UserAgentAttribute, req.UserAgent()),
			)

			if !cfg.Public {
				cfg.HTTPPropagate.SpanContextToRequest(span.SpanContext(), req)
			}

			return ctx
		},
	)

	clientAfter := kithttp.ClientAfter(
		func(ctx context.Context, res *http.Response) context.Context {
			if span := trace.FromContext(ctx); span != nil {
				span.SetStatus(ochttp.TraceStatus(res.StatusCode, http.StatusText(res.StatusCode)))
				span.AddAttributes(
					trace.Int64Attribute(ochttp.StatusCodeAttribute, int64(res.StatusCode)),
				)
			}
			return ctx
		},
	)

	clientFinalizer := kithttp.ClientFinalizer(
		func(ctx context.Context, err error) {
			if span := trace.FromContext(ctx); span != nil {
				if err != nil {
					span.SetStatus(trace.Status{
						Code:    trace.StatusCodeUnknown,
						Message: err.Error(),
					})
				}
				span.End()
			}
		},
	)

	return func(c *kithttp.Client) {
		clientBefore(c)
		clientAfter(c)
		clientFinalizer(c)
	}
}

// HTTPServerTrace enables OpenCensus tracing of a Go kit HTTP transport server.
func HTTPServerTrace(options ...TracerOption) kithttp.ServerOption {
	cfg := TracerOptions{}

	for _, option := range options {
		option(&cfg)
	}

	if !cfg.Public && cfg.HTTPPropagate == nil {
		cfg.HTTPPropagate = &b3.HTTPFormat{}
	}

	serverBefore := kithttp.ServerBefore(
		func(ctx context.Context, req *http.Request) context.Context {
			var (
				spanContext trace.SpanContext
				span        *trace.Span
				name        string
				ok          bool
			)

			if cfg.Name != "" {
				name = cfg.Name
			} else {
				name = req.Method + " " + req.URL.Path
			}

			spanContext, ok = cfg.HTTPPropagate.SpanContextFromRequest(req)
			if ok && !cfg.Public {
				ctx, span = trace.StartSpanWithRemoteParent(
					ctx,
					name,
					spanContext,
					trace.WithSpanKind(trace.SpanKindServer),
					trace.WithSampler(cfg.Sampler),
				)
			} else {
				ctx, span = trace.StartSpan(
					ctx,
					name,
					trace.WithSpanKind(trace.SpanKindServer),
					trace.WithSampler(cfg.Sampler),
				)
				if ok {
					span.AddLink(trace.Link{
						TraceID:    spanContext.TraceID,
						SpanID:     spanContext.SpanID,
						Type:       trace.LinkTypeChild,
						Attributes: nil,
					})
				}
			}

			span.AddAttributes(
				trace.StringAttribute(ochttp.MethodAttribute, req.Method),
				trace.StringAttribute(ochttp.PathAttribute, req.URL.Path),
			)

			return ctx
		},
	)

	serverFinalizer := kithttp.ServerFinalizer(
		func(ctx context.Context, code int, r *http.Request) {
			if span := trace.FromContext(ctx); span != nil {
				span.SetStatus(ochttp.TraceStatus(code, http.StatusText(code)))

				if rs, ok := ctx.Value(kithttp.ContextKeyResponseSize).(int64); ok {
					span.AddAttributes(
						trace.Int64Attribute("http.response_size", rs),
					)
				}

				span.End()
			}
		},
	)

	return func(s *kithttp.Server) {
		serverBefore(s)
		serverFinalizer(s)
	}
}