1
#pragma once
2

            
3
#include <memory>
4

            
5
#include "envoy/common/random_generator.h"
6
#include "envoy/config/trace/v3/zipkin.pb.h"
7
#include "envoy/local_info/local_info.h"
8
#include "envoy/runtime/runtime.h"
9
#include "envoy/thread_local/thread_local.h"
10
#include "envoy/tracing/trace_driver.h"
11
#include "envoy/upstream/cluster_manager.h"
12

            
13
#include "source/common/http/async_client_utility.h"
14
#include "source/common/upstream/cluster_update_tracker.h"
15
#include "source/extensions/tracers/zipkin/span_buffer.h"
16
#include "source/extensions/tracers/zipkin/tracer.h"
17
#include "source/extensions/tracers/zipkin/tracer_interface.h"
18
#include "source/extensions/tracers/zipkin/zipkin_core_constants.h"
19

            
20
namespace Envoy {
21
namespace Extensions {
22
namespace Tracers {
23
namespace Zipkin {
24

            
25
#define ZIPKIN_TRACER_STATS(COUNTER)                                                               \
26
43
  COUNTER(spans_sent)                                                                              \
27
43
  COUNTER(timer_flushed)                                                                           \
28
43
  COUNTER(reports_skipped_no_cluster)                                                              \
29
43
  COUNTER(reports_sent)                                                                            \
30
43
  COUNTER(reports_dropped)                                                                         \
31
43
  COUNTER(reports_failed)
32

            
33
struct ZipkinTracerStats {
34
  ZIPKIN_TRACER_STATS(GENERATE_COUNTER_STRUCT)
35
};
36

            
37
using ZipkinTracerStatsSharedPtr = std::shared_ptr<ZipkinTracerStats>;
38

            
39
/**
40
 * Information about the Zipkin collector.
41
 */
42
struct CollectorInfo {
43
  std::string cluster_; // The cluster to use to reach the collector.
44

            
45
  // The Zipkin collector endpoint/path to receive the collected trace data.
46
  // For legacy configuration: from collector_endpoint field.
47
  // For HttpService configuration: from http_service_.http_uri().uri().
48
  std::string endpoint_;
49

            
50
  // The hostname to use when sending spans to the collector.
51
  // For legacy configuration: from collector_hostname field or cluster name.
52
  // For HttpService configuration: cluster name.
53
  std::string hostname_;
54

            
55
  // The version of the collector. This is related to endpoint's supported payload specification and
56
  // transport.
57
  envoy::config::trace::v3::ZipkinConfig::CollectorEndpointVersion version_{
58
      envoy::config::trace::v3::ZipkinConfig::HTTP_JSON};
59

            
60
  bool shared_span_context_{DEFAULT_SHARED_SPAN_CONTEXT};
61

            
62
  // Additional custom headers to include in requests to the Zipkin collector.
63
  // Only available when using HttpService configuration via request_headers_to_add.
64
  // Legacy configuration does not support custom headers.
65
  std::vector<std::pair<Http::LowerCaseString, std::string>> request_headers_;
66
};
67

            
68
using CollectorInfoConstSharedPtr = std::shared_ptr<const CollectorInfo>;
69

            
70
/**
71
 * Class for a Zipkin-specific Driver.
72
 */
73
class Driver : public Tracing::Driver {
74
public:
75
  /**
76
   * Thread-local store containing ZipkinDriver and Zipkin::Tracer objects.
77
   */
78
  struct TlsTracer : ThreadLocal::ThreadLocalObject {
79
43
    TlsTracer(TracerPtr tracer) : tracer_(std::move(tracer)) {}
80
    TracerPtr tracer_;
81
  };
82

            
83
  /**
84
   * Constructor. It adds itself and a newly-created Zipkin::Tracer object to a thread-local store.
85
   * Also, it associates the given random-number generator to the Zipkin::Tracer object it creates.
86
   */
87
  Driver(const envoy::config::trace::v3::ZipkinConfig& zipkin_config,
88
         Server::Configuration::ServerFactoryContext& context);
89

            
90
  /**
91
   * This function is inherited from the abstract Driver class.
92
   *
93
   * It starts a new Zipkin span. Depending on the request headers, it can create a root span,
94
   * a child span, or a shared-context span.
95
   *
96
   * The third parameter (operation_name) does not actually make sense for Zipkin.
97
   * Thus, this implementation of the virtual function startSpan() ignores the operation name
98
   * ("ingress" or "egress") passed by the caller.
99
   */
100
  Tracing::SpanPtr startSpan(const Tracing::Config& config, Tracing::TraceContext& trace_context,
101
                             const StreamInfo::StreamInfo& stream_info,
102
                             const std::string& operation_name,
103
                             Tracing::Decision tracing_decision) override;
104

            
105
47
  bool w3cFallbackEnabled() const {
106
47
    return trace_context_option_ ==
107
47
           envoy::config::trace::v3::ZipkinConfig::USE_B3_WITH_W3C_PROPAGATION;
108
47
  }
109
3
  TraceContextOption traceContextOption() const { return trace_context_option_; }
110

            
111
3
  const std::string& hostnameForTest() { return collector_->hostname_; }
112

            
113
private:
114
  std::shared_ptr<CollectorInfo> collector_;
115
  ThreadLocal::SlotPtr tls_;
116
  TraceContextOption trace_context_option_;
117
};
118

            
119
/**
120
 * This class derives from the abstract Zipkin::Reporter.
121
 * It buffers spans and relies on Http::AsyncClient to send spans to
122
 * Zipkin using JSON over HTTP.
123
 *
124
 * Two runtime parameters control the span buffering/flushing behavior, namely:
125
 * tracing.zipkin.min_flush_spans and tracing.zipkin.flush_interval_ms.
126
 *
127
 * Up to `tracing.zipkin.min_flush_spans` will be buffered. Spans are flushed (sent to Zipkin)
128
 * either when the buffer is full, or when a timer, set to `tracing.zipkin.flush_interval_ms`,
129
 * expires, whichever happens first.
130
 *
131
 * The default values for the runtime parameters are 5 spans and 5000ms.
132
 */
133
class ReporterImpl : Logger::Loggable<Logger::Id::tracing>,
134
                     public Reporter,
135
                     public Http::AsyncClient::Callbacks {
136
public:
137
  /**
138
   * Constructor.
139
   *
140
   * @param dispatcher Controls the timer used to flush buffered spans.
141
   * @param cm Reference to the cluster manager. This is used to get a handle
142
   * to the cluster that contains the Zipkin collector.
143
   * @param runtime Reference to the runtime. This is used to get the values
144
   * of the runtime parameters that control the span-buffering/flushing behavior.
145
   * @param tracer_stats Reference to the structure used to record Zipkin-related stats.
146
   * @param collector holds the endpoint version and path information.
147
   * when making HTTP POST requests carrying spans. This value comes from the
148
   * Zipkin-related tracing configuration.
149
   */
150
  ReporterImpl(Event::Dispatcher& dispatcher, Upstream::ClusterManager& cm,
151
               Runtime::Loader& runtime, ZipkinTracerStatsSharedPtr tracer_stats,
152
               CollectorInfoConstSharedPtr collector);
153

            
154
  /**
155
   * Implementation of Zipkin::Reporter::reportSpan().
156
   *
157
   * Buffers the given span and calls flushSpans() if the buffer is full.
158
   *
159
   * @param span The span to be buffered.
160
   */
161
  void reportSpan(Span&& span) override;
162

            
163
  // Http::AsyncClient::Callbacks.
164
  // The callbacks below record Zipkin-span-related stats.
165
  void onSuccess(const Http::AsyncClient::Request&, Http::ResponseMessagePtr&&) override;
166
  void onFailure(const Http::AsyncClient::Request&, Http::AsyncClient::FailureReason) override;
167
  void onBeforeFinalizeUpstreamSpan(Tracing::Span&, const Http::ResponseHeaderMap*) override {}
168

            
169
private:
170
  /**
171
   * Enables the span-flushing timer.
172
   */
173
  void enableTimer();
174

            
175
  /**
176
   * Removes all spans from the span buffer and sends them to Zipkin using Http::AsyncClient.
177
   */
178
  void flushSpans();
179

            
180
  Runtime::Loader& runtime_;
181
  ZipkinTracerStatsSharedPtr tracer_stats_;
182
  CollectorInfoConstSharedPtr collector_;
183

            
184
  Event::TimerPtr flush_timer_;
185
  SpanBufferPtr span_buffer_;
186
  Upstream::ClusterUpdateTracker collector_cluster_;
187
  // Track active HTTP requests to be able to cancel them on destruction.
188
  Http::AsyncClientRequestTracker active_requests_;
189
};
190
} // namespace Zipkin
191
} // namespace Tracers
192
} // namespace Extensions
193
} // namespace Envoy