Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/extensions/tracers/zipkin/tracer.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/extensions/tracers/zipkin/tracer.h"
2
3
#include <chrono>
4
5
#include "source/common/common/utility.h"
6
#include "source/common/tracing/http_tracer_impl.h"
7
#include "source/extensions/tracers/zipkin/util.h"
8
#include "source/extensions/tracers/zipkin/zipkin_core_constants.h"
9
10
namespace Envoy {
11
namespace Extensions {
12
namespace Tracers {
13
namespace Zipkin {
14
15
/**
16
 * @param spawn_child_span whether the Envoy will spawn a child span for the request. This
17
 * means that the Envoy will be treated as an independent hop in the trace chain.
18
 * See
19
 * https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/observability/tracing#different-modes-of-envoy
20
 * for more details.
21
 * @param upstream whether the span is span for an upstream request.
22
 * @param direction the direction of the traffic that the span is for. Egress means
23
 * the span is for an outgoing request, and Ingress means the span is for an incoming request.
24
 */
25
0
Annotation getAnnotation(bool spawn_child_span, bool upstream, Tracing::OperationName direction) {
26
0
  Annotation annotation;
27
0
  if (spawn_child_span) {
28
    // Spawn child span is set to true and Envoy should be treated as an independent hop in the
29
    // trace chain. Determine the span type based on the request type.
30
31
    // Create server span for downstream request and client span for upstream request.
32
0
    annotation.setValue(upstream ? CLIENT_SEND : SERVER_RECV);
33
0
  } else {
34
    // Spawn child span is set to false and Envoy should not be treated as an independent hop in the
35
    // trace chain. Determine the span type based on the traffic direction.
36
37
    // Create server span for inbound sidecar and client span for outbound sidecar.
38
0
    annotation.setValue(direction == Tracing::OperationName::Egress ? CLIENT_SEND : SERVER_RECV);
39
0
  }
40
41
0
  return annotation;
42
0
}
43
44
SpanPtr Tracer::startSpan(const Tracing::Config& config, const std::string& span_name,
45
0
                          SystemTime timestamp) {
46
  // Build the endpoint
47
0
  Endpoint ep(service_name_, address_);
48
49
  // Build the CS annotation.
50
  // No previous context then this must be span created for downstream request for now.
51
0
  Annotation cs = getAnnotation(split_spans_for_request_ || config.spawnUpstreamSpan(), false,
52
0
                                config.operationName());
53
0
  cs.setEndpoint(std::move(ep));
54
55
  // Create an all-new span, with no parent id
56
0
  SpanPtr span_ptr = std::make_unique<Span>(time_source_);
57
0
  span_ptr->setName(span_name);
58
0
  uint64_t random_number = random_generator_.random();
59
0
  span_ptr->setId(random_number);
60
0
  span_ptr->setTraceId(random_number);
61
0
  if (trace_id_128bit_) {
62
0
    span_ptr->setTraceIdHigh(random_generator_.random());
63
0
  }
64
0
  int64_t start_time_micro = std::chrono::duration_cast<std::chrono::microseconds>(
65
0
                                 time_source_.monotonicTime().time_since_epoch())
66
0
                                 .count();
67
0
  span_ptr->setStartTime(start_time_micro);
68
69
  // Set the timestamp globally for the span and also for the CS annotation
70
0
  uint64_t timestamp_micro =
71
0
      std::chrono::duration_cast<std::chrono::microseconds>(timestamp.time_since_epoch()).count();
72
0
  cs.setTimestamp(timestamp_micro);
73
0
  span_ptr->setTimestamp(timestamp_micro);
74
75
  // Add CS annotation to the span
76
0
  span_ptr->addAnnotation(std::move(cs));
77
78
0
  span_ptr->setTracer(this);
79
80
0
  return span_ptr;
81
0
}
82
83
SpanPtr Tracer::startSpan(const Tracing::Config& config, const std::string& span_name,
84
0
                          SystemTime timestamp, const SpanContext& previous_context) {
85
0
  SpanPtr span_ptr = std::make_unique<Span>(time_source_);
86
  // If the previous context is inner context then this span is span for upstream request.
87
0
  Annotation annotation = getAnnotation(split_spans_for_request_ || config.spawnUpstreamSpan(),
88
0
                                        previous_context.innerContext(), config.operationName());
89
0
  uint64_t timestamp_micro;
90
91
0
  timestamp_micro =
92
0
      std::chrono::duration_cast<std::chrono::microseconds>(timestamp.time_since_epoch()).count();
93
94
0
  span_ptr->setName(span_name);
95
96
  // Set the span's id and parent id
97
0
  if (annotation.value() == CLIENT_SEND || !shared_span_context_) {
98
    // We need to create a new span that is a child of the previous span; no shared context
99
100
    // Create a new span id
101
0
    uint64_t random_number = random_generator_.random();
102
0
    span_ptr->setId(random_number);
103
104
    // Set the parent id to the id of the previous span
105
0
    span_ptr->setParentId(previous_context.id());
106
107
    // Set the timestamp globally for the span
108
0
    span_ptr->setTimestamp(timestamp_micro);
109
0
  } else if (annotation.value() == SERVER_RECV) {
110
    // We need to create a new span that will share context with the previous span
111
112
    // Initialize the shared context for the new span
113
0
    span_ptr->setId(previous_context.id());
114
0
    if (previous_context.parentId()) {
115
0
      span_ptr->setParentId(previous_context.parentId());
116
0
    }
117
0
  } else {
118
0
    return span_ptr; // return an empty span
119
0
  }
120
121
  // Build the endpoint
122
0
  Endpoint ep(service_name_, address_);
123
124
  // Add the newly-created annotation to the span
125
0
  annotation.setEndpoint(std::move(ep));
126
0
  annotation.setTimestamp(timestamp_micro);
127
0
  span_ptr->addAnnotation(std::move(annotation));
128
129
  // Keep the same trace id
130
0
  span_ptr->setTraceId(previous_context.traceId());
131
0
  if (previous_context.is128BitTraceId()) {
132
0
    span_ptr->setTraceIdHigh(previous_context.traceIdHigh());
133
0
  }
134
135
  // Keep the same sampled flag
136
0
  span_ptr->setSampled(previous_context.sampled());
137
138
0
  int64_t start_time_micro = std::chrono::duration_cast<std::chrono::microseconds>(
139
0
                                 time_source_.monotonicTime().time_since_epoch())
140
0
                                 .count();
141
0
  span_ptr->setStartTime(start_time_micro);
142
143
0
  span_ptr->setTracer(this);
144
145
0
  return span_ptr;
146
0
}
147
148
0
void Tracer::reportSpan(Span&& span) {
149
0
  if (reporter_ && span.sampled()) {
150
0
    reporter_->reportSpan(std::move(span));
151
0
  }
152
0
}
153
154
0
void Tracer::setReporter(ReporterPtr reporter) { reporter_ = std::move(reporter); }
155
156
} // namespace Zipkin
157
} // namespace Tracers
158
} // namespace Extensions
159
} // namespace Envoy