tracer.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package sdk
  4. import (
  5. "context"
  6. "math"
  7. "time"
  8. "go.opentelemetry.io/otel/trace"
  9. "go.opentelemetry.io/otel/trace/noop"
  10. "go.opentelemetry.io/auto/sdk/internal/telemetry"
  11. )
  12. type tracer struct {
  13. noop.Tracer
  14. name, schemaURL, version string
  15. }
  16. var _ trace.Tracer = tracer{}
  17. func (t tracer) Start(
  18. ctx context.Context,
  19. name string,
  20. opts ...trace.SpanStartOption,
  21. ) (context.Context, trace.Span) {
  22. var psc, sc trace.SpanContext
  23. sampled := true
  24. span := new(span)
  25. // Ask eBPF for sampling decision and span context info.
  26. t.start(ctx, span, &psc, &sampled, &sc)
  27. span.sampled.Store(sampled)
  28. span.spanContext = sc
  29. ctx = trace.ContextWithSpan(ctx, span)
  30. if sampled {
  31. // Only build traces if sampled.
  32. cfg := trace.NewSpanStartConfig(opts...)
  33. span.traces, span.span = t.traces(name, cfg, span.spanContext, psc)
  34. }
  35. return ctx, span
  36. }
  37. // Expected to be implemented in eBPF.
  38. //
  39. //go:noinline
  40. func (t *tracer) start(
  41. ctx context.Context,
  42. spanPtr *span,
  43. psc *trace.SpanContext,
  44. sampled *bool,
  45. sc *trace.SpanContext,
  46. ) {
  47. start(ctx, spanPtr, psc, sampled, sc)
  48. }
  49. // start is used for testing.
  50. var start = func(context.Context, *span, *trace.SpanContext, *bool, *trace.SpanContext) {}
  51. var intToUint32Bound = min(math.MaxInt, math.MaxUint32)
  52. func (t tracer) traces(
  53. name string,
  54. cfg trace.SpanConfig,
  55. sc, psc trace.SpanContext,
  56. ) (*telemetry.Traces, *telemetry.Span) {
  57. span := &telemetry.Span{
  58. TraceID: telemetry.TraceID(sc.TraceID()),
  59. SpanID: telemetry.SpanID(sc.SpanID()),
  60. Flags: uint32(sc.TraceFlags()),
  61. TraceState: sc.TraceState().String(),
  62. ParentSpanID: telemetry.SpanID(psc.SpanID()),
  63. Name: name,
  64. Kind: spanKind(cfg.SpanKind()),
  65. }
  66. span.Attrs, span.DroppedAttrs = convCappedAttrs(maxSpan.Attrs, cfg.Attributes())
  67. links := cfg.Links()
  68. if limit := maxSpan.Links; limit == 0 {
  69. n := len(links)
  70. if n > 0 {
  71. bounded := max(min(n, intToUint32Bound), 0)
  72. span.DroppedLinks = uint32(bounded) //nolint:gosec // Bounds checked.
  73. }
  74. } else {
  75. if limit > 0 {
  76. n := max(len(links)-limit, 0)
  77. bounded := min(n, intToUint32Bound)
  78. span.DroppedLinks = uint32(bounded) //nolint:gosec // Bounds checked.
  79. links = links[n:]
  80. }
  81. span.Links = convLinks(links)
  82. }
  83. if t := cfg.Timestamp(); !t.IsZero() {
  84. span.StartTime = cfg.Timestamp()
  85. } else {
  86. span.StartTime = time.Now()
  87. }
  88. return &telemetry.Traces{
  89. ResourceSpans: []*telemetry.ResourceSpans{
  90. {
  91. ScopeSpans: []*telemetry.ScopeSpans{
  92. {
  93. Scope: &telemetry.Scope{
  94. Name: t.name,
  95. Version: t.version,
  96. },
  97. Spans: []*telemetry.Span{span},
  98. SchemaURL: t.schemaURL,
  99. },
  100. },
  101. },
  102. },
  103. }, span
  104. }
  105. func spanKind(kind trace.SpanKind) telemetry.SpanKind {
  106. switch kind {
  107. case trace.SpanKindInternal:
  108. return telemetry.SpanKindInternal
  109. case trace.SpanKindServer:
  110. return telemetry.SpanKindServer
  111. case trace.SpanKindClient:
  112. return telemetry.SpanKindClient
  113. case trace.SpanKindProducer:
  114. return telemetry.SpanKindProducer
  115. case trace.SpanKindConsumer:
  116. return telemetry.SpanKindConsumer
  117. }
  118. return telemetry.SpanKind(0) // undefined.
  119. }