summaryrefslogtreecommitdiffstats
path: root/include/opentracing/tracer.h
blob: a4a125aa5682b5a49a11b5ff47d1c43c5253fa45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#ifndef OPENTRACING_TRACER_H
#define OPENTRACING_TRACER_H

#include <opentracing/propagation.h>
#include <opentracing/span.h>
#include <opentracing/string_view.h>
#include <opentracing/symbols.h>
#include <opentracing/util.h>
#include <opentracing/version.h>
#include <chrono>
#include <initializer_list>
#include <iosfwd>
#include <memory>
#include <utility>
#include <vector>

namespace opentracing {
BEGIN_OPENTRACING_ABI_NAMESPACE
// StartSpanOptions allows Tracer.StartSpan() callers a mechanism to override
// the start timestamp, specify Span References, and make a single Tag or
// multiple Tags available at Span start time.
//
// StartSpan() callers should look at the StartSpanOption interface and
// implementations available in this library.
struct StartSpanOptions {
  // start_system_timestamp and start_steady_timestamp override the Span's start
  // time, or implicitly become std::chrono::system_clock::now() and
  // std::chrono::steady_clock::now() if both are equal to the epoch (default
  // behavior).
  //
  // If one of the timestamps is set but not the other, the set timestamp is
  // used to estimate the corresponding timestamp of the other.
  SystemTime start_system_timestamp;
  SteadyTime start_steady_timestamp;

  // Zero or more causal references to other Spans (via their SpanContext).
  // If empty, start a "root" Span (i.e., start a new trace).
  //
  // Any nullptrs provided will be ignored.
  std::vector<std::pair<SpanReferenceType, const SpanContext*>> references;

  // Zero or more tags to apply to the newly created span.
  std::vector<std::pair<std::string, Value>> tags;
};

// StartSpanOption instances (zero or more) may be passed to Tracer.StartSpan.
class StartSpanOption {
 public:
  StartSpanOption(const StartSpanOption&) = delete;

  virtual ~StartSpanOption() = default;

  virtual void Apply(StartSpanOptions& options) const noexcept = 0;

 protected:
  StartSpanOption() = default;
};

// Tracer is a simple, thin interface for Span creation and SpanContext
// propagation.
class OPENTRACING_API Tracer {
 public:
  virtual ~Tracer() = default;

  // Create, start, and return a new Span with the given `operationName` and
  // incorporate the given StartSpanOption `option_list`.
  //
  // A Span with no SpanReference options (e.g., opentracing::ChildOf() or
  // opentracing::FollowsFrom()) becomes the root of its own trace.
  //
  // Examples:
  //
  //     opentracing::Tracer& tracer = ...
  //
  //     // The root-span case:
  //     auto span = tracer.StartSpan("GetFeed")
  //
  //     // The vanilla child span case:
  //     auto span = tracer.StartSpan(
  //         "GetFeed",
  //         {opentracing::ChildOf(&parentSpan.context())})
  //
  //     // All the bells and whistles:
  //     auto span = tracer.StartSpan(
  //         "GetFeed",
  //         {opentracing::ChildOf(&parentSpan.context()),
  //         opentracing::Tag{"user_agent", loggedReq.UserAgent},
  //         opentracing::StartTimestamp(loggedReq.timestamp())})
  //
  // If StartSpan is called after Close, it leaves the Tracer in a valid
  // state, but its behavior is unspecified.
  std::unique_ptr<Span> StartSpan(
      string_view operation_name,
      std::initializer_list<option_wrapper<StartSpanOption>> option_list = {})
      const noexcept {
    StartSpanOptions options;
    for (const auto& option : option_list) option.get().Apply(options);
    return StartSpanWithOptions(operation_name, options);
  }

  virtual std::unique_ptr<Span> StartSpanWithOptions(
      string_view operation_name, const StartSpanOptions& options) const
      noexcept = 0;

  // Inject() takes the `sc` SpanContext instance and injects it for propagation
  // within `carrier`.
  //
  // OpenTracing defines a common set of `carrier` interfaces.
  //
  // Throws only if `writer` does.
  //
  // If `writer` is an `std::ostream`, then Inject() propagates `sc` as a blob
  // of binary data.
  virtual expected<void> Inject(const SpanContext& sc,
                                std::ostream& writer) const = 0;

  virtual expected<void> Inject(const SpanContext& sc,
                                const TextMapWriter& writer) const = 0;

  virtual expected<void> Inject(const SpanContext& sc,
                                const HTTPHeadersWriter& writer) const = 0;

  virtual expected<void> Inject(const SpanContext& sc,
                                const CustomCarrierWriter& writer) const {
    return writer.Inject(*this, sc);
  }

  // Extract() returns a SpanContext instance given `carrier`.
  //
  // OpenTracing defines a common set of `carrier` interfaces.
  //
  // Returns a `SpanContext` that is `non-null` on success or nullptr if no span
  // is found; otherwise an std::error_code.
  //
  // Throws only if `reader` does.
  virtual expected<std::unique_ptr<SpanContext>> Extract(
      std::istream& reader) const = 0;

  virtual expected<std::unique_ptr<SpanContext>> Extract(
      const TextMapReader& reader) const = 0;

  virtual expected<std::unique_ptr<SpanContext>> Extract(
      const HTTPHeadersReader& reader) const = 0;

  virtual expected<std::unique_ptr<SpanContext>> Extract(
      const CustomCarrierReader& reader) const {
    return reader.Extract(*this);
  }

  // Close is called when a tracer is finished processing spans. It is not
  // required to be called and its effect is unspecified. For example, an
  // implementation might use this function to flush buffered spans to its
  // recording system and failing to call it could result in some spans being
  // dropped.
  virtual void Close() noexcept {}

  // GlobalTracer returns the global tracer.
  static std::shared_ptr<Tracer> Global() noexcept;

  // InitGlobalTracer sets the global tracer pointer, returns the
  // former global tracer value.
  static std::shared_ptr<Tracer> InitGlobal(
      std::shared_ptr<Tracer> tracer) noexcept;

  static bool IsGlobalTracerRegistered() noexcept;
};

// StartTimestamp is a StartSpanOption that sets an explicit start timestamp for
// the new Span.
class StartTimestamp : public StartSpanOption {
 public:
  StartTimestamp(SystemTime system_when, SteadyTime steady_when) noexcept
      : system_when_(system_when), steady_when_(steady_when) {}

  StartTimestamp(SystemTime system_when) noexcept
      : system_when_(system_when),
        steady_when_(convert_time_point<SteadyClock>(system_when_)) {}

  // Construct a timestamp using a duration from the epoch of std::time_t.
  // From the documentation on std::time_t's epoch:
  //     Although not defined, this is almost always an integral value holding
  //     the number of seconds (not counting leap seconds) since 00:00, Jan 1
  //     1970 UTC, corresponding to POSIX time
  // See http://en.cppreference.com/w/cpp/chrono/c/time_t
  template <class Rep, class Period>
  explicit StartTimestamp(
      const std::chrono::duration<Rep, Period>& time_since_epoch) noexcept
      : StartTimestamp(SystemClock::from_time_t(std::time_t(0)) +
                       std::chrono::duration_cast<SystemClock::duration>(
                           time_since_epoch)) {}

  StartTimestamp(const StartTimestamp& other) noexcept
      : StartSpanOption(),
        system_when_(other.system_when_),
        steady_when_(other.steady_when_) {}

  void Apply(StartSpanOptions& options) const noexcept override {
    options.start_system_timestamp = system_when_;
    options.start_steady_timestamp = steady_when_;
  }

 private:
  SystemTime system_when_;
  SteadyTime steady_when_;
};

// SpanReference is a StartSpanOption that pairs a SpanReferenceType and a
// referenced SpanContext. See the SpanReferenceType documentation for
// supported relationships.
//
// If the referenced SpanContext is a nullptr, it is ignored. The passed
// SpanContext is copied during Span construction and the pointer is not
// retained.
class SpanReference : public StartSpanOption {
 public:
  SpanReference(SpanReferenceType type, const SpanContext* referenced) noexcept
      : type_(type), referenced_(referenced) {}

  SpanReference(const SpanReference& other) noexcept
      : StartSpanOption(), type_(other.type_), referenced_(other.referenced_) {}

  void Apply(StartSpanOptions& options) const noexcept override {
    try {
      if (referenced_) options.references.emplace_back(type_, referenced_);
    } catch (const std::bad_alloc&) {
      // Ignore reference if memory can't be allocated for it.
    }
  }

 private:
  SpanReferenceType type_;
  const SpanContext* referenced_;
};

// ChildOf returns a StartSpanOption pointing to a dependent parent span.
//
// See ChildOfRef, SpanReference
inline SpanReference ChildOf(const SpanContext* span_context) noexcept {
  return {SpanReferenceType::ChildOfRef, span_context};
}

// FollowsFrom returns a StartSpanOption pointing to a parent Span that caused
// the child Span but does not directly depend on its result in any way.
//
// See FollowsFromRef, SpanReference
inline SpanReference FollowsFrom(const SpanContext* span_context) noexcept {
  return {SpanReferenceType::FollowsFromRef, span_context};
}

// SetTag may be passed as a StartSpanOption to add a tag to new spans,
// for example:
//
// tracer.StartSpan("opName", SetTag{"Key", value})
class SetTag : public StartSpanOption {
 public:
  SetTag(string_view key, const Value& value) noexcept
      : key_(key), value_(value) {}

  SetTag(const SetTag& other) noexcept
      : StartSpanOption(), key_(other.key_), value_(other.value_) {}

  void Apply(StartSpanOptions& options) const noexcept override {
    try {
      options.tags.emplace_back(key_, value_);
    } catch (const std::bad_alloc&) {
      // Ignore tag if memory can't be allocated for it.
    }
  }

 private:
  const string_view key_;
  const Value& value_;
};
END_OPENTRACING_ABI_NAMESPACE
}  // namespace opentracing

#endif  // OPENTRACING_TRACER_H