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