Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/extensions/tracers/xray/tracer.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <string>
4
#include <utility>
5
#include <vector>
6
7
#include "envoy/common/time.h"
8
#include "envoy/tracing/tracer.h"
9
10
#include "source/common/common/empty_string.h"
11
#include "source/common/common/hex.h"
12
#include "source/common/common/random_generator.h"
13
#include "source/common/http/codes.h"
14
#include "source/common/protobuf/utility.h"
15
#include "source/common/tracing/common_values.h"
16
#include "source/common/tracing/trace_context_impl.h"
17
#include "source/extensions/tracers/xray/daemon_broker.h"
18
#include "source/extensions/tracers/xray/sampling_strategy.h"
19
#include "source/extensions/tracers/xray/xray_configuration.h"
20
21
#include "absl/container/flat_hash_map.h"
22
#include "absl/strings/string_view.h"
23
24
namespace Envoy {
25
namespace Extensions {
26
namespace Tracers {
27
namespace XRay {
28
29
constexpr absl::string_view SpanClientIp = "client_ip";
30
constexpr absl::string_view SpanXForwardedFor = "x_forwarded_for";
31
constexpr absl::string_view Subsegment = "subsegment";
32
33
const Tracing::TraceContextHandler& xRayTraceHeader();
34
const Tracing::TraceContextHandler& xForwardedForHeader();
35
36
class Span : public Tracing::Span, Logger::Loggable<Logger::Id::config> {
37
public:
38
  /**
39
   * Creates a new Span.
40
   *
41
   * @param time_source A time source to get the span end time
42
   * @param random random generator for generating unique child span ids
43
   * @param broker Facilitates communication with the X-Ray daemon.
44
   */
45
  Span(TimeSource& time_source, Random::RandomGenerator& random, DaemonBroker& broker)
46
      : time_source_(time_source), random_(random), broker_(broker),
47
0
        id_(Hex::uint64ToHex(random_.random())) {}
48
49
  /**
50
   * Sets the Span's trace ID.
51
   */
52
0
  void setTraceId(absl::string_view trace_id) { trace_id_ = std::string(trace_id); };
53
54
  /**
55
   * Gets the Span's trace ID.
56
   */
57
0
  const std::string& traceId() const { return trace_id_; }
58
59
  /**
60
   * Completes the current span, serialize it and send it to the X-Ray daemon.
61
   */
62
  void finishSpan() override;
63
64
  /**
65
   * Sets the current operation name on the Span.
66
   * This information will be included in the X-Ray span's metadata.
67
   */
68
0
  void setOperation(absl::string_view operation) override {
69
0
    operation_name_ = std::string(operation);
70
0
  }
71
72
  /**
73
   * Sets the current direction on the Span.
74
   * This information will be included in the X-Ray span's annotation.
75
   */
76
0
  void setDirection(absl::string_view direction) { direction_ = std::string(direction); }
77
78
  /**
79
   * Sets the name of the Span.
80
   */
81
0
  void setName(absl::string_view name) { name_ = std::string(name); }
82
83
  /**
84
   * Sets the origin of the Span.
85
   */
86
0
  void setOrigin(absl::string_view origin) { origin_ = std::string(origin); }
87
88
  /**
89
   * Gets the origin of the Span.
90
   */
91
0
  const std::string& origin() { return origin_; }
92
93
  /**
94
   * Adds a key-value pair to either the Span's annotations or metadata.
95
   * An allowlist of keys are added to the annotations, everything else is added to the metadata.
96
   */
97
  void setTag(absl::string_view name, absl::string_view value) override;
98
99
  /**
100
   * Sets the ID of the parent segment. This is different from the Trace ID.
101
   * The parent ID is used if the request originated from an instrumented application.
102
   * For more information see:
103
   * https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader
104
   */
105
0
  void setParentId(absl::string_view parent_segment_id) {
106
0
    parent_segment_id_ = std::string(parent_segment_id);
107
0
  }
108
109
  /**
110
   * Sets the type of the Span. In X-Ray, an independent subsegment has a type of "subsegment".
111
   * https://docs.aws.amazon.com/xray/latest/devguide/xray-api-segmentdocuments.html#api-segmentdocuments-subsegments
112
   */
113
0
  void setType(absl::string_view type) { type_ = std::string(type); }
114
115
  /**
116
   * Sets the aws metadata field of the Span.
117
   */
118
0
  void setAwsMetadata(const absl::flat_hash_map<std::string, ProtobufWkt::Value>& aws_metadata) {
119
0
    aws_metadata_ = aws_metadata;
120
0
  }
121
122
  /*
123
   * Adds to the http request annotation field of the Span.
124
   */
125
0
  void addToHttpRequestAnnotations(absl::string_view key, const ProtobufWkt::Value& value) {
126
0
    http_request_annotations_.emplace(std::string(key), value);
127
0
  }
128
129
  /*
130
   * Check if key is set in http request annotation field of a Span.
131
   */
132
0
  bool hasKeyInHttpRequestAnnotations(absl::string_view key) {
133
0
    return http_request_annotations_.find(key) != http_request_annotations_.end();
134
0
  }
135
136
  /*
137
   * Adds to the http response annotation field of the Span.
138
   */
139
0
  void addToHttpResponseAnnotations(absl::string_view key, const ProtobufWkt::Value& value) {
140
0
    http_response_annotations_.emplace(std::string(key), value);
141
0
  }
142
143
  /**
144
   * Sets the recording start time of the traced operation/request.
145
   */
146
0
  void setStartTime(Envoy::SystemTime start_time) { start_time_ = start_time; }
147
148
  /**
149
   * Marks the span as either "sampled" or "not-sampled".
150
   * By default, Spans are "sampled".
151
   * This is handy in cases where the sampling decision has already been determined either by Envoy
152
   * or by a downstream service.
153
   */
154
0
  void setSampled(bool sampled) override { sampled_ = sampled; };
155
156
  /**
157
   * Sets the server error as true for the traced operation/request.
158
   */
159
0
  void setServerError() { server_error_ = true; };
160
161
  /**
162
   * Sets the http response status code for the traced operation/request.
163
   */
164
0
  void setResponseStatusCode(uint64_t status_code) { response_status_code_ = status_code; };
165
166
  /**
167
   * Adds X-Ray trace header to the set of outgoing headers.
168
   */
169
  void injectContext(Tracing::TraceContext& trace_context,
170
                     const Tracing::UpstreamContext&) override;
171
172
  /**
173
   * Gets the start time of this Span.
174
   */
175
0
  Envoy::SystemTime startTime() const { return start_time_; }
176
177
  /**
178
   * Gets this Span's ID.
179
   */
180
0
  const std::string& id() const { return id_; }
181
182
  /**
183
   * Gets this Span's parent ID.
184
   */
185
0
  const std::string& parentId() const { return parent_segment_id_; }
186
187
  /**
188
   * Gets this Span's direction.
189
   */
190
0
  const std::string& direction() const { return direction_; }
191
192
  /**
193
   * Gets this Span's type.
194
   */
195
0
  const std::string& type() const { return type_; }
196
197
  /**
198
   * Gets this Span's name.
199
   */
200
0
  const std::string& name() const { return name_; }
201
202
  /**
203
   * Determines whether this span is sampled.
204
   */
205
0
  bool sampled() const { return sampled_; }
206
207
  /**
208
   * Determines if a server error occurred (response status code was 5XX Server Error).
209
   */
210
0
  bool serverError() const { return server_error_; }
211
212
  /**
213
   * Determines if a client error occurred (response status code was 4XX Client Error).
214
   */
215
0
  bool clientError() const { return Http::CodeUtility::is4xx(response_status_code_); }
216
217
  /**
218
   * Determines if a request was throttled (response status code was 429 Too Many Requests).
219
   */
220
0
  bool isThrottled() const {
221
0
    return Http::Code::TooManyRequests == static_cast<Http::Code>(response_status_code_);
222
0
  }
223
224
  /**
225
   * Not used by X-Ray because the Spans are "logged" (serialized) to the X-Ray daemon.
226
   */
227
0
  void log(Envoy::SystemTime, const std::string&) override {}
228
229
  // X-Ray doesn't support baggage, so noop these OpenTracing functions.
230
0
  void setBaggage(absl::string_view, absl::string_view) override {}
231
0
  std::string getBaggage(absl::string_view) override { return EMPTY_STRING; }
232
233
0
  std::string getTraceId() const override { return trace_id_; };
234
235
  // TODO(#34412): This method is unimplemented for X-Ray.
236
0
  std::string getSpanId() const override { return EMPTY_STRING; };
237
238
  /**
239
   * Creates a child span.
240
   * In X-Ray terms this creates a sub-segment and sets its parent ID to the current span's ID.
241
   * @param operation_name The span of the child span.
242
   * @param start_time The time at which this child span started.
243
   */
244
  Tracing::SpanPtr spawnChild(const Tracing::Config&, const std::string& operation_name,
245
                              Envoy::SystemTime start_time) override;
246
247
private:
248
  Envoy::TimeSource& time_source_;
249
  Random::RandomGenerator& random_;
250
  DaemonBroker& broker_;
251
  Envoy::SystemTime start_time_;
252
  std::string operation_name_;
253
  std::string direction_;
254
  std::string id_;
255
  std::string trace_id_;
256
  std::string parent_segment_id_;
257
  std::string name_;
258
  std::string origin_;
259
  std::string type_;
260
  absl::flat_hash_map<std::string, ProtobufWkt::Value> aws_metadata_;
261
  absl::flat_hash_map<std::string, ProtobufWkt::Value> http_request_annotations_;
262
  absl::flat_hash_map<std::string, ProtobufWkt::Value> http_response_annotations_;
263
  absl::flat_hash_map<std::string, std::string> custom_annotations_;
264
  bool server_error_{false};
265
  uint64_t response_status_code_{0};
266
  bool sampled_{true};
267
};
268
269
using SpanPtr = std::unique_ptr<Span>;
270
271
class Tracer {
272
public:
273
  Tracer(absl::string_view segment_name, absl::string_view origin,
274
         const absl::flat_hash_map<std::string, ProtobufWkt::Value>& aws_metadata,
275
         DaemonBrokerPtr daemon_broker, TimeSource& time_source, Random::RandomGenerator& random)
276
      : segment_name_(segment_name), origin_(origin), aws_metadata_(aws_metadata),
277
0
        daemon_broker_(std::move(daemon_broker)), time_source_(time_source), random_(random) {}
278
  /**
279
   * Starts a tracing span for X-Ray
280
   */
281
  Tracing::SpanPtr startSpan(const Tracing::Config&, const std::string& operation_name,
282
                             Envoy::SystemTime start_time,
283
                             const absl::optional<XRayHeader>& xray_header,
284
                             const absl::optional<absl::string_view> client_ip);
285
  /**
286
   * Creates a Span that is marked as not-sampled.
287
   * This is useful when the sampling decision is done in Envoy's X-Ray and we want to avoid
288
   * overruling that decision in the upstream service in case that service itself uses X-Ray for
289
   * tracing. Also at the same time if X-Ray header is set then preserve its value.
290
   */
291
  XRay::SpanPtr createNonSampledSpan(const absl::optional<XRayHeader>& xray_header) const;
292
293
private:
294
  const std::string segment_name_;
295
  const std::string origin_;
296
  const absl::flat_hash_map<std::string, ProtobufWkt::Value> aws_metadata_;
297
  const DaemonBrokerPtr daemon_broker_;
298
  Envoy::TimeSource& time_source_;
299
  Random::RandomGenerator& random_;
300
};
301
302
using TracerPtr = std::unique_ptr<Tracer>;
303
304
} // namespace XRay
305
} // namespace Tracers
306
} // namespace Extensions
307
} // namespace Envoy