...

Source file src/github.com/go-kit/kit/tracing/opencensus/endpoint.go

Documentation: github.com/go-kit/kit/tracing/opencensus

     1  package opencensus
     2  
     3  import (
     4  	"context"
     5  	"strconv"
     6  
     7  	"go.opencensus.io/trace"
     8  
     9  	"github.com/go-kit/kit/endpoint"
    10  	"github.com/go-kit/kit/sd/lb"
    11  )
    12  
    13  // TraceEndpointDefaultName is the default endpoint span name to use.
    14  const TraceEndpointDefaultName = "gokit/endpoint"
    15  
    16  // TraceEndpoint returns an Endpoint middleware, tracing a Go kit endpoint.
    17  // This endpoint tracer should be used in combination with a Go kit Transport
    18  // tracing middleware, generic OpenCensus transport middleware or custom before
    19  // and after transport functions as service propagation of SpanContext is not
    20  // provided in this middleware.
    21  func TraceEndpoint(name string, options ...EndpointOption) endpoint.Middleware {
    22  	if name == "" {
    23  		name = TraceEndpointDefaultName
    24  	}
    25  
    26  	cfg := &EndpointOptions{}
    27  
    28  	for _, o := range options {
    29  		o(cfg)
    30  	}
    31  
    32  	return func(next endpoint.Endpoint) endpoint.Endpoint {
    33  		return func(ctx context.Context, request interface{}) (response interface{}, err error) {
    34  			if cfg.GetName != nil {
    35  				if newName := cfg.GetName(ctx, name); newName != "" {
    36  					name = newName
    37  				}
    38  			}
    39  
    40  			ctx, span := trace.StartSpan(ctx, name)
    41  			if len(cfg.Attributes) > 0 {
    42  				span.AddAttributes(cfg.Attributes...)
    43  			}
    44  			defer span.End()
    45  
    46  			if cfg.GetAttributes != nil {
    47  				if attrs := cfg.GetAttributes(ctx); len(attrs) > 0 {
    48  					span.AddAttributes(attrs...)
    49  				}
    50  			}
    51  
    52  			defer func() {
    53  				if err != nil {
    54  					if lberr, ok := err.(lb.RetryError); ok {
    55  						// handle errors originating from lb.Retry
    56  						attrs := make([]trace.Attribute, 0, len(lberr.RawErrors))
    57  						for idx, rawErr := range lberr.RawErrors {
    58  							attrs = append(attrs, trace.StringAttribute(
    59  								"gokit.retry.error."+strconv.Itoa(idx+1), rawErr.Error(),
    60  							))
    61  						}
    62  						span.AddAttributes(attrs...)
    63  						span.SetStatus(trace.Status{
    64  							Code:    trace.StatusCodeUnknown,
    65  							Message: lberr.Final.Error(),
    66  						})
    67  						return
    68  					}
    69  					// generic error
    70  					span.SetStatus(trace.Status{
    71  						Code:    trace.StatusCodeUnknown,
    72  						Message: err.Error(),
    73  					})
    74  					return
    75  				}
    76  
    77  				// test for business error
    78  				if res, ok := response.(endpoint.Failer); ok && res.Failed() != nil {
    79  					span.AddAttributes(
    80  						trace.StringAttribute("gokit.business.error", res.Failed().Error()),
    81  					)
    82  					if cfg.IgnoreBusinessError {
    83  						span.SetStatus(trace.Status{Code: trace.StatusCodeOK})
    84  						return
    85  					}
    86  					// treating business error as real error in span.
    87  					span.SetStatus(trace.Status{
    88  						Code:    trace.StatusCodeUnknown,
    89  						Message: res.Failed().Error(),
    90  					})
    91  					return
    92  				}
    93  
    94  				// no errors identified
    95  				span.SetStatus(trace.Status{Code: trace.StatusCodeOK})
    96  			}()
    97  			response, err = next(ctx, request)
    98  			return
    99  		}
   100  	}
   101  }
   102  

View as plain text