Line data Source code
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 Upstream::HostDescriptionConstSharedPtr&) 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 : // TODO: This method is unimplemented for X-Ray. 234 0 : std::string getTraceIdAsHex() const override { return EMPTY_STRING; }; 235 : 236 : /** 237 : * Creates a child span. 238 : * In X-Ray terms this creates a sub-segment and sets its parent ID to the current span's ID. 239 : * @param operation_name The span of the child span. 240 : * @param start_time The time at which this child span started. 241 : */ 242 : Tracing::SpanPtr spawnChild(const Tracing::Config&, const std::string& operation_name, 243 : Envoy::SystemTime start_time) override; 244 : 245 : private: 246 : Envoy::TimeSource& time_source_; 247 : Random::RandomGenerator& random_; 248 : DaemonBroker& broker_; 249 : Envoy::SystemTime start_time_; 250 : std::string operation_name_; 251 : std::string direction_; 252 : std::string id_; 253 : std::string trace_id_; 254 : std::string parent_segment_id_; 255 : std::string name_; 256 : std::string origin_; 257 : std::string type_; 258 : absl::flat_hash_map<std::string, ProtobufWkt::Value> aws_metadata_; 259 : absl::flat_hash_map<std::string, ProtobufWkt::Value> http_request_annotations_; 260 : absl::flat_hash_map<std::string, ProtobufWkt::Value> http_response_annotations_; 261 : absl::flat_hash_map<std::string, std::string> custom_annotations_; 262 : bool server_error_{false}; 263 : uint64_t response_status_code_{0}; 264 : bool sampled_{true}; 265 : }; 266 : 267 : using SpanPtr = std::unique_ptr<Span>; 268 : 269 : class Tracer { 270 : public: 271 : Tracer(absl::string_view segment_name, absl::string_view origin, 272 : const absl::flat_hash_map<std::string, ProtobufWkt::Value>& aws_metadata, 273 : DaemonBrokerPtr daemon_broker, TimeSource& time_source, Random::RandomGenerator& random) 274 : : segment_name_(segment_name), origin_(origin), aws_metadata_(aws_metadata), 275 0 : daemon_broker_(std::move(daemon_broker)), time_source_(time_source), random_(random) {} 276 : /** 277 : * Starts a tracing span for X-Ray 278 : */ 279 : Tracing::SpanPtr startSpan(const Tracing::Config&, const std::string& operation_name, 280 : Envoy::SystemTime start_time, 281 : const absl::optional<XRayHeader>& xray_header, 282 : const absl::optional<absl::string_view> client_ip); 283 : /** 284 : * Creates a Span that is marked as not-sampled. 285 : * This is useful when the sampling decision is done in Envoy's X-Ray and we want to avoid 286 : * overruling that decision in the upstream service in case that service itself uses X-Ray for 287 : * tracing. Also at the same time if X-Ray header is set then preserve its value. 288 : */ 289 : XRay::SpanPtr createNonSampledSpan(const absl::optional<XRayHeader>& xray_header) const; 290 : 291 : private: 292 : const std::string segment_name_; 293 : const std::string origin_; 294 : const absl::flat_hash_map<std::string, ProtobufWkt::Value> aws_metadata_; 295 : const DaemonBrokerPtr daemon_broker_; 296 : Envoy::TimeSource& time_source_; 297 : Random::RandomGenerator& random_; 298 : }; 299 : 300 : using TracerPtr = std::unique_ptr<Tracer>; 301 : 302 : } // namespace XRay 303 : } // namespace Tracers 304 : } // namespace Extensions 305 : } // namespace Envoy