userver: userver/logging/log_extra.hpp Source File
Loading...
Searching...
No Matches
log_extra.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/logging/log_extra.hpp
4/// @brief @copybrief logging::LogExtra
5
6#include <initializer_list>
7#include <string>
8#include <utility>
9#include <variant>
10
11#include <boost/container/container_fwd.hpp>
12
13#include <userver/compiler/select.hpp>
14#include <userver/logging/fwd.hpp>
15#include <userver/logging/json_string.hpp>
16#include <userver/utils/fast_pimpl.hpp>
17
18USERVER_NAMESPACE_BEGIN
19
20/// @brief Distributed tracing helpers and identifiers.
21namespace tracing {
22
23class TagScope;
24
25class Span;
26
27} // namespace tracing
28
29namespace logging {
30
31class LogHelper;
32
33namespace impl {
34class TagWriter;
35class LogExtraTskvFormatter;
36
37struct JsonStringViewForInitializerList {
38 JsonStringViewForInitializerList() = delete;
39 /*implicit*/ JsonStringViewForInitializerList(const JsonString& json) noexcept : json_str{&json} {}
40 /*implicit*/ JsonStringViewForInitializerList(const formats::json::Value& json) noexcept : json_value{&json} {}
41
42 const JsonString* const json_str{nullptr};
43 const formats::json::Value* const json_value{nullptr};
44};
45
46} // namespace impl
47
48/// Extra tskv fields storage
49class LogExtra final {
50public:
51 /// @brief Stored tag value type
52 using Value = std::variant<
53 std::string,
54 int,
55 bool,
56 long,
57 long long,
58 unsigned int,
59 unsigned long,
60 unsigned long long,
61 float,
62 double,
64 using Key = std::string;
65 using Pair = std::pair<Key, Value>;
66
67 using ValueView = std::variant<
68 std::string_view,
69 int,
70 bool,
71 long,
72 long long,
73 unsigned int,
74 unsigned long,
75 unsigned long long,
76 float,
77 double,
78 impl::JsonStringViewForInitializerList>;
79 // std::initializer_list does not allow moving out values, so we use views to avoid copying data into it.
80 using InitializerList = std::initializer_list<std::pair<std::string_view, ValueView>>;
81
82 /// Specifies replacement policy for newly added values
83 enum class ExtendType {
84 kNormal, ///< Added value can be replaced
85 kFrozen, ///< Attempts to replace this value will be ignored
86 };
87
88 LogExtra() noexcept;
89
90 LogExtra(const LogExtra&);
91
92 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
93 LogExtra(LogExtra&&);
94
95 ~LogExtra();
96
97 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
98 LogExtra& operator=(LogExtra&&);
99
100 LogExtra& operator=(const LogExtra&);
101
102 /// Constructs LogExtra containing an initial batch of key-value pairs
103 LogExtra(InitializerList initial, ExtendType extend_type = ExtendType::kNormal);
104
105 /// Adds a single key-value pair
106 void Extend(std::string key, Value value, ExtendType extend_type = ExtendType::kNormal);
107
108 /// Adds a single key-value pair
109 void Extend(Pair extra, ExtendType extend_type = ExtendType::kNormal);
110
111 /// Adds a batch of key-value pairs
112 void Extend(InitializerList extra, ExtendType extend_type = ExtendType::kNormal);
113
114 /// @brief Merges contents of other LogExtra with existing key-value pairs
115 /// preserving freeze states
116 void Extend(const LogExtra& extra);
117
118 /// @brief Merges contents of other LogExtra with existing key-value pairs
119 /// preserving freeze states
120 void Extend(LogExtra&& extra);
121
122 /// @brief Creates a LogExtra with current thread's stacktrace if the default
123 /// log level is less or equal to DEBUG
124 static LogExtra StacktraceNocache() noexcept;
125
126 /// @brief Creates a LogExtra with current thread's stacktrace if the logger
127 /// log level is less or equal to DEBUG
128 static LogExtra StacktraceNocache(logging::LoggerRef logger) noexcept;
129
130 /// @brief Creates a LogExtra with current thread's stacktrace if the logger
131 /// log level is less or equal to DEBUG. Uses cache for
132 /// faster stacktrace symbolization.
133 static LogExtra Stacktrace() noexcept;
134
135 /// @brief Creates a LogExtra with current thread's stacktrace if the logger
136 /// log level is less or equal to DEBUG. Uses cache for
137 /// faster stacktrace symbolization.
138 static LogExtra Stacktrace(logging::LoggerRef logger) noexcept;
139
140 /// @brief Adds a range of key-value pairs
141 template <typename Iterator>
142 void ExtendRange(Iterator first, Iterator last, ExtendType extend_type = ExtendType::kNormal) {
143 // NOTE: must replace existing rewritable values
144 for (Iterator it = first; it != last; ++it) {
145 Extend(*it, extend_type);
146 }
147 }
148
149 /// @brief Marks specified value as frozen, all attempts to overwrite it will be silently ignored.
150 void SetFrozen(std::string_view key);
151
152 friend class LogHelper;
153 friend class impl::LogExtraTskvFormatter;
154 friend class impl::TagWriter;
155 friend class tracing::Span;
156 friend class tracing::TagScope;
157
158private:
159 const Value& GetValue(std::string_view key) const;
160
161 class ProtectedValue final {
162 public:
163 ProtectedValue() = default;
164 ProtectedValue(Value value, bool frozen);
165 ProtectedValue(const ProtectedValue& other) = default;
166 ProtectedValue(ProtectedValue&& other) = default;
167
168 ProtectedValue& operator=(const ProtectedValue& other);
169 ProtectedValue& operator=(ProtectedValue&& other) noexcept;
170
171 bool IsFrozen() const noexcept;
172 void SetFrozen() noexcept;
173 Value& GetValue() noexcept { return value_; }
174 const Value& GetValue() const noexcept { return value_; }
175 void AssignIgnoringFrozenness(ProtectedValue other);
176
177 private:
178 Value value_;
179 bool frozen_ = false;
180 };
181
182 static constexpr std::size_t kSmallVectorSize = 24;
183 static constexpr std::size_t kPimplSize =
184 compiler::SelectSize().ForLibCpp32(1168).ForLibCpp64(1560).ForLibStdCpp64(1944).ForLibStdCpp32(1356);
185 using MapItem = std::pair<Key, ProtectedValue>;
186 using Map = boost::container::small_vector<MapItem, kSmallVectorSize>;
187
188 void Extend(std::string key, ProtectedValue protected_value, ExtendType extend_type = ExtendType::kNormal);
189
190 void Extend(MapItem extra, ExtendType extend_type = ExtendType::kNormal);
191
192 std::pair<Key, ProtectedValue>* Find(std::string_view);
193
194 const std::pair<Key, ProtectedValue>* Find(std::string_view) const;
195
196 utils::FastPimpl<Map, kPimplSize, alignof(void*)> extra_;
197};
198
199extern const LogExtra kEmptyLogExtra;
200
201} // namespace logging
202
203USERVER_NAMESPACE_END