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