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 explicit Span(
38 TracerPtr tracer,
39 std::string name,
40 const Span* parent,
41 ReferenceType reference_type,
42 logging::Level log_level = logging::Level::kInfo,
43 utils::impl::SourceLocation source_location = utils::impl::SourceLocation::Current()
44 );
45
46 /// Use default tracer and implicit coro local storage for parent
47 /// identification, takes TraceID from the parent.
48 ///
49 /// For extremely rare cases where a new Trace ID is required use
50 /// tracing::Span::MakeSpan().
51 explicit Span(
52 std::string name,
53 ReferenceType reference_type = ReferenceType::kChild,
54 logging::Level log_level = logging::Level::kInfo,
55 utils::impl::SourceLocation source_location = utils::impl::SourceLocation::Current()
56 );
57
58 /// @cond
59 // For internal use only
60 explicit Span(Span::Impl& impl);
61 /// @endcond
62
63 Span(Span&& other) noexcept;
64
65 ~Span();
66
67 Span& operator=(const Span&) = delete;
68
69 Span& operator=(Span&&) = delete;
70
71 /// @brief Returns the Span of the current task.
72 ///
73 /// Should not be called in non-coroutine
74 /// context. Should not be called from a task with no alive Span.
75 ///
76 /// Rule of thumb: it is safe to call it from a task created by
77 /// utils::Async/utils::CriticalAsync/utils::PeriodicTask. If current task was
78 /// created with an explicit engine::impl::*Async(), you have to create a Span
79 /// beforehand.
80 static Span& CurrentSpan();
81
82 /// @brief Returns nullptr if called in non-coroutine context or from a task
83 /// with no alive Span; otherwise returns the Span of the current task.
84 static Span* CurrentSpanUnchecked();
85
86 /// Factory function for extremely rare cases of creating a Span with custom
87 /// IDs; prefer Span constructor instead.
88 ///
89 /// @return A new Span attached to current Span (if any) but with a new
90 /// Trace ID.
91 /// @param name Name of a new Span
92 /// @param trace_id New Trace ID; if empty then the Trace ID is autogenerated
93 /// @param parent_span_id Id of the parent Span, could be empty.
94 static Span MakeSpan(std::string name, std::string_view trace_id, std::string_view parent_span_id);
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 attached to current Span (if any), sets `link`.
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, could be empty.
103 /// @param link The new link
104 static Span
105 MakeSpan(std::string name, std::string_view trace_id, std::string_view parent_span_id, std::string link);
106
107 /// Factory function for rare cases of creating a root Span that starts
108 /// the trace_id chain, ignoring `CurrentSpan`, if any. Useful
109 /// in background jobs, periodics, distlock tasks, cron tasks, etc.
110 /// The result of such jobs is not directly requested by anything.
111 ///
112 /// @return A new Span that is the root of a new Span hierarchy.
113 /// @param name Name of a new Span
114 /// @param log_level Log level for the span's own log record
115 static Span MakeRootSpan(std::string name, logging::Level log_level = logging::Level::kInfo);
116
117 /// Create a child which can be used independently from the parent.
118 ///
119 /// The child shares no state with its parent. If you need to run code in
120 /// parallel, create a child span and use the child in a separate task.
121 Span CreateChild(std::string name) const;
122
123 Span CreateFollower(std::string name) const;
124
125 /// @brief Creates a tracing::ScopeTime attached to the span.
127
128 /// @brief Creates a tracing::ScopeTime attached to the Span and starts
129 /// measuring execution time.
130 /// Tag `{scope_name}_time` with elapsed time is added to result span.
131 ///
132 /// @note `name` parameter is expected to satisfy snake case.
133 /// Otherwise, it is converted to snake case.
134 ScopeTime CreateScopeTime(std::string name);
135
136 /// Returns total time elapsed for a certain scope of this span.
137 /// If there is no record for the scope, returns 0.
138 ScopeTime::Duration GetTotalDuration(const std::string& scope_name) const;
139
140 /// Returns total time elapsed for a certain scope of this span.
141 /// If there is no record for the scope, returns 0.
142 ///
143 /// Prefer using Span::GetTotalDuration()
144 ScopeTime::DurationMillis GetTotalElapsedTime(const std::string& scope_name) const;
145
146 /// Add a tag that is used on each logging in this Span and all
147 /// future children.
148 void AddTag(std::string key, logging::LogExtra::Value value);
149
150 /// Add a tag that is used on each logging in this Span and all
151 /// future children. It will not be possible to change its value.
152 void AddTagFrozen(std::string key, logging::LogExtra::Value value);
153
154 /// Add a tag that is local to the Span (IOW, it is not propagated to
155 /// future children) and logged only once in the destructor of the Span.
156 void AddNonInheritableTag(std::string key, logging::LogExtra::Value value);
157
158 /// @overload AddNonInheritableTag
159 void AddNonInheritableTags(const logging::LogExtra&);
160
161 /// Add an event to Span.
162 void AddEvent(SpanEvent&& event);
163
164 /// Add an event (without attributes) to Span.
165 /// @overload AddEvent
166 void AddEvent(std::string_view event_name);
167
168 /// @brief Sets log level with which the current span itself is written into the tracing
169 /// system.
170 ///
171 /// If `Span`'s log level is less than the global logger's log level, then the span is
172 /// not written out. In that case, nested logs are still written to the logging system
173 /// as usual, inheriting `trace_id`, `link`, `span_id` and inheritable tags of the current
174 /// `Span` object.
175 void SetLogLevel(logging::Level log_level);
176
177 /// @brief Returns level for tags logging
179
180 /// @brief Sets an additional cutoff for the logs written in the scope of this `Span`,
181 /// and in nested scopes recursively.
182 ///
183 /// For example, if the global log level is `info`, and the current `Span` has
184 /// (own or inherited) local log level `warning`, then all `LOG_INFO`s within the current
185 /// scope will be thrown away.
186 ///
187 /// Currently, local log level cannot override the global log level of the logger.
188 /// For example, if the global log level is `info`, and the current `Span` has
189 /// (own or inherited) local log level `debug`, then all `LOG_DEBUG`s within the current
190 /// scope will **still** be thrown away.
191 void SetLocalLogLevel(std::optional<logging::Level> log_level);
192
193 /// @brief Returns the local log level that disables logging of this span if
194 /// it is set and greater than the main log level of the Span.
195 std::optional<logging::Level> GetLocalLogLevel() const;
196
197 /// Set link - a request ID within a service. Can be called only once.
198 ///
199 /// Propagates within a single service, but not from client to server. A new
200 /// link is generated for the "root" request handling task
201 void SetLink(std::string link);
202
203 /// Set parent_link - an ID . Can be called only once.
204 void SetParentLink(std::string parent_link);
205
206 /// Get link - a request ID within the service.
207 ///
208 /// Propagates within a single service, but not from client to server. A new
209 /// link is generated for the "root" request handling task
210 std::string GetLink() const;
211
212 std::string GetParentLink() const;
213
214 /// An ID of the request that does not change from service to service.
215 ///
216 /// Propagates both to sub-spans within a single service, and from client
217 /// to server
218 const std::string& GetTraceId() const;
219
220 /// Identifies a specific span. It does not propagate
221 const std::string& GetSpanId() const;
222 const std::string& GetParentId() const;
223
224 /// @returns true if this span would be logged with the current local and
225 /// global log levels to the default logger.
226 bool ShouldLogDefault() const noexcept;
227
228 /// Detach the Span from current engine::Task so it is not
229 /// returned by CurrentSpan() any more.
231
232 /// Attach the Span to current engine::Task so it is returned
233 /// by CurrentSpan().
235
236 std::chrono::system_clock::time_point GetStartSystemTime() const;
237
238 /// @cond
239 // For internal use only.
240 void AddTags(const logging::LogExtra&, utils::impl::InternalTag);
241
242 // For internal use only.
243 impl::TimeStorage& GetTimeStorage(utils::impl::InternalTag);
244
245 // For internal use only.
246 void LogTo(logging::impl::TagWriter writer) const&;
247 /// @endcond
248
249private:
250 struct OptionalDeleter {
251 void operator()(Impl*) const noexcept;
252
253 static OptionalDeleter ShouldDelete() noexcept;
254
255 static OptionalDeleter DoNotDelete() noexcept;
256
257 private:
258 explicit OptionalDeleter(bool do_delete) : do_delete(do_delete) {}
259
260 const bool do_delete;
261 };
262
263 friend class SpanBuilder;
264 friend class TagScope;
265
266 explicit Span(std::unique_ptr<Impl, OptionalDeleter>&& pimpl);
267
268 std::string GetTag(std::string_view tag) const;
269
270 std::unique_ptr<Impl, OptionalDeleter> pimpl_;
271};
272
273namespace impl {
274
275class DetachLocalSpansScope final {
276public:
277 DetachLocalSpansScope() noexcept;
278 ~DetachLocalSpansScope();
279
280 DetachLocalSpansScope(DetachLocalSpansScope&&) = delete;
281 DetachLocalSpansScope& operator=(DetachLocalSpansScope&&) = delete;
282
283private:
284 struct Impl;
285 utils::FastPimpl<Impl, 16, 8> impl_;
286};
287
288struct LogSpanAsLastNoCurrent final {
289 const Span& span;
290};
291
292logging::LogHelper& operator<<(logging::LogHelper& lh, LogSpanAsLastNoCurrent span);
293
294} // namespace impl
295
296} // namespace tracing
297
298USERVER_NAMESPACE_END