1// Unless explicitly stated otherwise all files in this repository are licensed 2// under the Apache License Version 2.0. 3// This product includes software developed at Datadog (https://www.datadoghq.com/). 4// Copyright 2016 Datadog, Inc. 5 6// Package restful provides functions to trace the emicklei/go-restful package (https://github.com/emicklei/go-restful). 7package restful 8 9import ( 10 "math" 11 "strconv" 12 13 "gopkg.in/DataDog/dd-trace-go.v1/ddtrace" 14 "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext" 15 "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" 16 "gopkg.in/DataDog/dd-trace-go.v1/internal/log" 17 18 "github.com/emicklei/go-restful" 19) 20 21// FilterFunc returns a restful.FilterFunction which will automatically trace incoming request. 22func FilterFunc(configOpts ...Option) restful.FilterFunction { 23 cfg := newConfig() 24 for _, opt := range configOpts { 25 opt(cfg) 26 } 27 log.Debug("contrib/emicklei/go-restful: Creating tracing filter: %#v", cfg) 28 return func(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { 29 opts := []ddtrace.StartSpanOption{ 30 tracer.ServiceName(cfg.serviceName), 31 tracer.ResourceName(req.SelectedRoutePath()), 32 tracer.SpanType(ext.SpanTypeWeb), 33 tracer.Tag(ext.HTTPMethod, req.Request.Method), 34 tracer.Tag(ext.HTTPURL, req.Request.URL.Path), 35 } 36 if !math.IsNaN(cfg.analyticsRate) { 37 opts = append(opts, tracer.Tag(ext.EventSampleRate, cfg.analyticsRate)) 38 } 39 if spanctx, err := tracer.Extract(tracer.HTTPHeadersCarrier(req.Request.Header)); err == nil { 40 opts = append(opts, tracer.ChildOf(spanctx)) 41 } 42 span, ctx := tracer.StartSpanFromContext(req.Request.Context(), "http.request", opts...) 43 defer span.Finish() 44 45 // pass the span through the request context 46 req.Request = req.Request.WithContext(ctx) 47 48 chain.ProcessFilter(req, resp) 49 50 span.SetTag(ext.HTTPCode, strconv.Itoa(resp.StatusCode())) 51 span.SetTag(ext.Error, resp.Error()) 52 } 53} 54 55// Filter is deprecated. Please use FilterFunc. 56func Filter(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { 57 opts := []ddtrace.StartSpanOption{ 58 tracer.ResourceName(req.SelectedRoutePath()), 59 tracer.SpanType(ext.SpanTypeWeb), 60 tracer.Tag(ext.HTTPMethod, req.Request.Method), 61 tracer.Tag(ext.HTTPURL, req.Request.URL.Path), 62 } 63 if spanctx, err := tracer.Extract(tracer.HTTPHeadersCarrier(req.Request.Header)); err == nil { 64 opts = append(opts, tracer.ChildOf(spanctx)) 65 } 66 span, ctx := tracer.StartSpanFromContext(req.Request.Context(), "http.request", opts...) 67 defer span.Finish() 68 69 // pass the span through the request context 70 req.Request = req.Request.WithContext(ctx) 71 72 chain.ProcessFilter(req, resp) 73 74 span.SetTag(ext.HTTPCode, strconv.Itoa(resp.StatusCode())) 75 span.SetTag(ext.Error, resp.Error()) 76} 77