userver: userver/tracing/span.hpp Source File
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
span.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/tracing/span.hpp
4/// @brief @copybrief tracing::Span
5
6#include <optional>
7#include <string_view>
8
9#include <userver/logging/log.hpp>
10#include <userver/logging/log_extra.hpp>
11#include <userver/tracing/scope_time.hpp>
12#include <userver/tracing/tracer_fwd.hpp>
13#include <userver/utils/impl/internal_tag.hpp>
14#include <userver/utils/impl/source_location.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace tracing {
19
20class SpanBuilder;
21struct SpanEvent;
22
23/// @brief Measures the execution time of the current code block, links it with
24/// the parent tracing::Spans and stores that info in the log.
25///
26/// Logging of spans can be controlled at runtime via @ref USERVER_NO_LOG_SPANS.
27///
28/// See @ref scripts/docs/en/userver/logging.md for usage examples and more
29/// descriptions.
30///
31/// @warning Shall be created only as a local variable. Do not use it as a
32/// class member!
33class Span final {
34public:
35 class Impl;
36
37 /// Use implicit task-local storage for parent identification, takes TraceID and Link from the parent `Span`.
38 ///
39 /// For extremely rare cases where a new Trace ID is required, use @ref tracing::Span::MakeSpan.
40 explicit Span(
41 std::string name,
42 const utils::impl::SourceLocation& source_location = utils::impl::SourceLocation::Current()
43 );
44
45 /// Sets an arbitrary `Span` as parent. If `parent == nullptr`, then creates a root `Span`.
46 ///
47 /// Useful in extremely rare cases. Prefer the constructor above by default.
48 explicit Span(
49 std::string name,
50 const Span* parent,
51 ReferenceType reference_type = ReferenceType::kChild,
52 const utils::impl::SourceLocation& source_location = utils::impl::SourceLocation::Current()
53 );
54
55 Span(Span&& other) noexcept;
56 Span(const Span& other) = delete;
57 Span& operator=(Span&&) = delete;
58 Span& operator=(const Span&) = delete;
59 ~Span();
60
61 /// @brief Returns the Span of the current task.
62 ///
63 /// Should not be called in non-coroutine
64 /// context. Should not be called from a task with no alive Span.
65 ///
66 /// Rule of thumb: it is safe to call it from a task created by
67 /// utils::Async/utils::CriticalAsync/utils::PeriodicTask. If current task was
68 /// created with an explicit engine::impl::*Async(), you have to create a Span
69 /// beforehand.
70 static Span& CurrentSpan();
71
72 /// @brief Returns nullptr if called in non-coroutine context or from a task
73 /// with no alive Span; otherwise returns the Span of the current task.
74 static Span* CurrentSpanUnchecked();
75
76 /// Factory function for extremely rare cases of creating a Span with custom
77 /// IDs; prefer Span constructor instead.
78 ///
79 /// @return A new Span with the specified IDs.
80 /// @param name Name of a new Span.
81 /// @param trace_id New Trace ID; if empty then the Trace ID is autogenerated.
82 /// @param parent_span_id ID of the parent Span, can be empty.
83 /// @param source_location Implementation detail, do not touch.
84 static Span MakeSpan(
85 std::string name,
86 std::string_view trace_id,
87 std::string_view parent_span_id,
88 const utils::impl::SourceLocation& source_location = utils::impl::SourceLocation::Current()
89 );
90
91 /// Factory function for extremely rare cases of creating a Span with custom
92 /// IDs; prefer Span constructor instead.
93 ///
94 /// @return A new Span with the specified IDs.
95 /// @param name Name of a new Span.
96 /// @param trace_id New Trace ID; if empty then the Trace ID is autogenerated.
97 /// @param parent_span_id ID of the parent Span, can be empty.
98 /// @param link The new Link; if empty the Link is autogenerated.
99 /// @param source_location Implementation detail, do not touch.
100 static Span MakeSpan(
101 std::string name,
102 std::string_view trace_id,
103 std::string_view parent_span_id,
104 std::string_view link,
105 const utils::impl::SourceLocation& source_location = utils::impl::SourceLocation::Current()
106 );
107
108 /// Factory function for rare cases of creating a root Span that starts
109 /// the trace_id chain, ignoring `CurrentSpan`, if any. Useful
110 /// in background jobs, periodics, distlock tasks, cron tasks, etc.
111 /// The result of such jobs is not directly requested by anything.
112 ///
113 /// @return A new Span that is the root of a new Span hierarchy.
114 /// @param name Name of a new Span
115 /// @param source_location Implementation detail, do not touch.
116 static Span MakeRootSpan(
117 std::string name,
118 const utils::impl::SourceLocation& source_location = utils::impl::SourceLocation::Current()
119 );
120
121 /// Create a child which can be used independently of the parent.
122 ///
123 /// The child shares no state with its parent. If you need to run code in
124 /// parallel, create a child span and use the child in a separate task.
126 std::string name,
127 const utils::impl::SourceLocation& source_location = utils::impl::SourceLocation::Current()
128 ) const;
129
130 Span CreateFollower(
131 std::string name,
132 const utils::impl::SourceLocation& source_location = utils::impl::SourceLocation::Current()
133 ) const;
134
135 /// @brief Creates a tracing::ScopeTime attached to the span.
137
138 /// @brief Creates a tracing::ScopeTime attached to the Span and starts
139 /// measuring execution time.
140 /// Tag `{scope_name}_time` with elapsed time is added to result span.
141 ///
142 /// @note `name` parameter is expected to satisfy snake case.
143 /// Otherwise, it is converted to snake case.
144 ScopeTime CreateScopeTime(std::string name);
145
146 /// Returns total time elapsed for a certain scope of this span.
147 /// If there is no record for the scope, returns 0.
148 ScopeTime::Duration GetTotalDuration(const std::string& scope_name) const;
149
150 /// Returns total time elapsed for a certain scope of this span.
151 /// If there is no record for the scope, returns 0.
152 ///
153 /// Prefer using Span::GetTotalDuration()
154 ScopeTime::DurationMillis GetTotalElapsedTime(const std::string& scope_name) const;
155
156 /// Add a tag that is used on each logging in this Span and all
157 /// future children.
158 void AddTag(std::string key, logging::LogExtra::Value value);
159
160 /// Add a tag that is used on each logging in this Span and all
161 /// future children. It will not be possible to change its value.
162 void AddTagFrozen(std::string key, logging::LogExtra::Value value);
163
164 /// Add a tag that is local to the Span (IOW, it is not propagated to
165 /// future children) and logged only once in the destructor of the Span.
166 void AddNonInheritableTag(std::string key, logging::LogExtra::Value value);
167
168 /// @overload AddNonInheritableTag
169 void AddNonInheritableTags(const logging::LogExtra&);
170
171 /// Add an event to Span.
172 void AddEvent(SpanEvent&& event);
173
174 /// Add an event (without attributes) to Span.
175 /// @overload AddEvent
176 void AddEvent(std::string_view event_name);
177
178 /// @brief Sets log level with which the current span itself is written into the tracing
179 /// system.
180 ///
181 /// This (mostly) does not affect logs written within the span,
182 /// unlike @ref tracing::Span::SetLocalLogLevel.
183 ///
184 /// If `Span`'s log level is less than the global logger's log level, then the span is
185 /// not written out. In that case:
186 /// * nested logs are still written to the logging system;
187 /// * they inherit `trace_id`, `link` and `span_id` of the nearest *written* `Span` object;
188 /// * tags are still inherited from the *nearest* `Span` even if it is hidden;
189 /// * this allows to use `Span`s as tag scopes regardless of their tracing purposes.
190 ///
191 /// Tracing systems use span's log level to highlight `warning` and `error` spans.
192 void SetLogLevel(logging::Level log_level);
193
194 /// See @ref tracing::Span::SetLogLevel.
196
197 /// @brief Sets an additional cutoff for the logs written in the scope of this `Span`,
198 /// and in nested scopes recursively.
199 ///
200 /// For example, if the global log level is `info`, and the current `Span` has
201 /// (own or inherited) local log level `warning`, then all `LOG_INFO`s within the current
202 /// scope will be thrown away.
203 ///
204 /// The cutoff also applies to the span itself. If the @ref tracing::Span::SetLogLevel "span's log level"
205 /// is less than the local log level, then the span is not written to the tracing system.
206 ///
207 /// Local log level of child spans can override local log level of parent spans in both directions.
208 /// For example:
209 /// * if local log level of a parent `Span` is `warning`,
210 /// * and local log level of a child span is set `info`,
211 /// * then `info` logs within that `Span` will be written,
212 /// * as long as the global log level is not higher than `info`.
213 ///
214 /// Currently, local log level cannot override the global log level of the logger.
215 /// For example, if the global log level is `info`, and the current `Span` has
216 /// (own or inherited) local log level `debug`, then all `LOG_DEBUG`s within the current
217 /// scope will **still** be thrown away.
218 void SetLocalLogLevel(std::optional<logging::Level> log_level);
219
220 /// See @ref tracing::Span::SetLocalLogLevel.
221 std::optional<logging::Level> GetLocalLogLevel() const;
222
223 /// Set link - a request ID within a service. Can be called only once.
224 ///
225 /// Propagates within a single service, but not from client to server. A new
226 /// link is generated for the "root" request handling task.
227 void SetLink(std::string_view link);
228
229 /// Set parent link - request ID of the upstream service. Can only be called once.
230 ///
231 /// Propagates within a single service.
232 void SetParentLink(std::string_view parent_link);
233
234 /// Get link - a request ID within the service.
235 ///
236 /// Propagates within a single service, but not from client to server. A new
237 /// link is generated for the "root" request handling task.
238 std::string_view GetLink() const;
239
240 /// Set parent link - request ID of the upstream service. Can only be called once.
241 ///
242 /// Propagates within a single service.
243 std::string_view GetParentLink() const;
244
245 /// An ID of the request that does not change from service to service.
246 ///
247 /// Propagates both to sub-spans within a single service, and from client
248 /// to server
249 std::string_view GetTraceId() const;
250
251 /// Identifies a specific span. It does not propagate.
252 std::string_view GetSpanId() const;
253
254 /// Span ID of the nearest loggable parent span, or empty string if none exists.
255 std::string_view GetParentId() const;
256
257 /// Span ID of the nearest loggable span within the span chain, including the current span.
258 /// If the current span and all parent spans will not be logged, returns `std::nullopt`.
259 std::optional<std::string_view> GetSpanIdForChildLogs() const;
260
261 /// Get name the Span was created with
262 std::string_view GetName() const;
263
264 /// @returns true if this span would be logged with the current local and
265 /// global log levels to the default logger.
266 bool ShouldLogDefault() const noexcept;
267
268 /// Detach the Span from current engine::Task so it is not
269 /// returned by CurrentSpan() any more.
271
272 /// Attach the Span to current engine::Task so it is returned
273 /// by CurrentSpan().
275
276 std::chrono::system_clock::time_point GetStartSystemTime() const;
277
278 /// @cond
279 // For internal use only.
280 void AddTags(const logging::LogExtra&, utils::impl::InternalTag);
281
282 // For internal use only.
283 impl::TimeStorage& GetTimeStorage(utils::impl::InternalTag);
284
285 // For internal use only.
286 void LogTo(utils::impl::InternalTag, logging::impl::TagWriter writer) const;
287 /// @endcond
288
289private:
290 struct OptionalDeleter {
291 void operator()(Impl*) const noexcept;
292
293 static OptionalDeleter ShouldDelete() noexcept;
294
295 static OptionalDeleter DoNotDelete() noexcept;
296
297 private:
298 explicit OptionalDeleter(bool do_delete) : do_delete(do_delete) {}
299
300 const bool do_delete;
301 };
302
303 friend class SpanBuilder;
304 friend class TagScope;
305 friend class InPlaceSpan;
306
307 explicit Span(std::unique_ptr<Impl, OptionalDeleter>&& pimpl);
308
309 std::string_view GetTag(std::string_view tag) const;
310
311 std::unique_ptr<Impl, OptionalDeleter> pimpl_;
312};
313
314namespace impl {
315
316class DetachLocalSpansScope final {
317public:
318 DetachLocalSpansScope() noexcept;
319 ~DetachLocalSpansScope();
320
321 DetachLocalSpansScope(DetachLocalSpansScope&&) = delete;
322 DetachLocalSpansScope& operator=(DetachLocalSpansScope&&) = delete;
323
324private:
325 struct Impl;
326 utils::FastPimpl<Impl, 16, 8> impl_;
327};
328
329struct LogSpanAsLastNoCurrent final {
330 const Span& span;
331};
332
333logging::LogHelper& operator<<(logging::LogHelper& lh, LogSpanAsLastNoCurrent span);
334
335} // namespace impl
336
337} // namespace tracing
338
339USERVER_NAMESPACE_END