Coverage Report

Created: 2023-11-12 09:30

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