tracer.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. // Package opentracer is in "Maintenance" mode and limited support is offered. Please consider
  6. // using OpenTelemetry or ddtrace/tracer directly. For additional details, please see our Support
  7. // Policy: https://github.com/DataDog/dd-trace-go#support-policy
  8. //
  9. // Package opentracer provides a wrapper on top of the Datadog tracer that can be used with Opentracing.
  10. // It also provides a set of opentracing.StartSpanOption that are specific to Datadog's APM product.
  11. // To use it, simply call "New".
  12. //
  13. // Note that there are currently some small incompatibilities between the Opentracing spec and the Datadog
  14. // APM product, which we are in the process of addressing on the long term. When using Datadog, the
  15. // Opentracing operation name is what is called resource in Datadog's terms and the Opentracing "component"
  16. // tag is Datadog's operation name. Meaning that in order to define (in Opentracing terms) a span that
  17. // has the operation name "/user/profile" and the component "http.request", one would do:
  18. // opentracing.StartSpan("http.request", opentracer.ResourceName("/user/profile"))
  19. //
  20. // Some libraries and frameworks are supported out-of-the-box by using our integrations. You can see a list
  21. // of supported integrations here: https://godoc.org/gopkg.in/DataDog/dd-trace-go.v1/contrib. They are fully
  22. // compatible with the Opentracing implementation.
  23. package opentracer
  24. import (
  25. "context"
  26. "gopkg.in/DataDog/dd-trace-go.v1/ddtrace"
  27. "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/internal"
  28. "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
  29. opentracing "github.com/opentracing/opentracing-go"
  30. )
  31. // New creates, instantiates and returns an Opentracing compatible version of the
  32. // Datadog tracer using the provided set of options.
  33. func New(opts ...tracer.StartOption) opentracing.Tracer {
  34. tracer.Start(opts...)
  35. return &opentracer{internal.GetGlobalTracer()}
  36. }
  37. var _ opentracing.Tracer = (*opentracer)(nil)
  38. // opentracer implements opentracing.Tracer on top of ddtrace.Tracer.
  39. type opentracer struct{ ddtrace.Tracer }
  40. // StartSpan implements opentracing.Tracer.
  41. func (t *opentracer) StartSpan(operationName string, options ...opentracing.StartSpanOption) opentracing.Span {
  42. var sso opentracing.StartSpanOptions
  43. for _, o := range options {
  44. o.Apply(&sso)
  45. }
  46. opts := []ddtrace.StartSpanOption{tracer.StartTime(sso.StartTime)}
  47. for _, ref := range sso.References {
  48. if v, ok := ref.ReferencedContext.(ddtrace.SpanContext); ok {
  49. // opentracing.ChildOfRef and opentracing.FollowsFromRef will both be represented as
  50. // children because Datadog APM does not have a concept of FollowsFrom references.
  51. opts = append(opts, tracer.ChildOf(v))
  52. break // can only have one parent
  53. }
  54. }
  55. for k, v := range sso.Tags {
  56. opts = append(opts, tracer.Tag(k, v))
  57. }
  58. return &span{
  59. Span: t.Tracer.StartSpan(operationName, opts...),
  60. opentracer: t,
  61. }
  62. }
  63. // Inject implements opentracing.Tracer.
  64. func (t *opentracer) Inject(ctx opentracing.SpanContext, format interface{}, carrier interface{}) error {
  65. sctx, ok := ctx.(ddtrace.SpanContext)
  66. if !ok {
  67. return opentracing.ErrUnsupportedFormat
  68. }
  69. switch format {
  70. case opentracing.TextMap, opentracing.HTTPHeaders:
  71. return translateError(t.Tracer.Inject(sctx, carrier))
  72. default:
  73. return opentracing.ErrUnsupportedFormat
  74. }
  75. }
  76. // Extract implements opentracing.Tracer.
  77. func (t *opentracer) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) {
  78. switch format {
  79. case opentracing.TextMap, opentracing.HTTPHeaders:
  80. sctx, err := t.Tracer.Extract(carrier)
  81. return sctx, translateError(err)
  82. default:
  83. return nil, opentracing.ErrUnsupportedFormat
  84. }
  85. }
  86. var _ opentracing.TracerContextWithSpanExtension = (*opentracer)(nil)
  87. // ContextWithSpan implements opentracing.TracerContextWithSpanExtension.
  88. func (t *opentracer) ContextWithSpanHook(ctx context.Context, openSpan opentracing.Span) context.Context {
  89. ddSpan, ok := openSpan.(*span)
  90. if !ok {
  91. return ctx
  92. }
  93. return tracer.ContextWithSpan(ctx, ddSpan.Span)
  94. }
  95. func translateError(err error) error {
  96. switch err {
  97. case tracer.ErrSpanContextNotFound:
  98. return opentracing.ErrSpanContextNotFound
  99. case tracer.ErrInvalidCarrier:
  100. return opentracing.ErrInvalidCarrier
  101. case tracer.ErrInvalidSpanContext:
  102. return opentracing.ErrInvalidSpanContext
  103. case tracer.ErrSpanContextCorrupted:
  104. return opentracing.ErrSpanContextCorrupted
  105. default:
  106. return err
  107. }
  108. }