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 using Value = std::variant<
52 std::string,
53 int,
54 bool,
55 long,
56 long long,
57 unsigned int,
58 unsigned long,
59 unsigned long long,
60 float,
61 double,
63 using Key = std::string;
64 using Pair = std::pair<Key, Value>;
65
66 using ValueView = std::variant<
67 std::string_view,
68 int,
69 bool,
70 long,
71 long long,
72 unsigned int,
73 unsigned long,
74 unsigned long long,
75 float,
76 double,
77 impl::JsonStringViewForInitializerList>;
78 // std::initializer_list does not allow moving out values, so we use views to avoid copying data into it.
79 using InitializerList = std::initializer_list<std::pair<std::string_view, ValueView>>;
80
81 /// Specifies replacement policy for newly added values
82 enum class ExtendType {
83 kNormal, ///< Added value can be replaced
84 kFrozen, ///< Attempts to replace this value will be ignored
85 };
86
87 LogExtra() noexcept;
88
89 LogExtra(const LogExtra&);
90
91 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
92 LogExtra(LogExtra&&);
93
94 ~LogExtra();
95
96 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
97 LogExtra& operator=(LogExtra&&);
98
99 LogExtra& operator=(const LogExtra&);
100
101 /// Constructs LogExtra containing an initial batch of key-value pairs
102 LogExtra(InitializerList initial, ExtendType extend_type = ExtendType::kNormal);
103
104 /// Adds a single key-value pair
105 void Extend(std::string key, Value value, ExtendType extend_type = ExtendType::kNormal);
106
107 /// Adds a single key-value pair
108 void Extend(Pair extra, ExtendType extend_type = ExtendType::kNormal);
109
110 /// Adds a batch of key-value pairs
111 void Extend(InitializerList extra, ExtendType extend_type = ExtendType::kNormal);
112
113 /// @brief Merges contents of other LogExtra with existing key-value pairs
114 /// preserving freeze states
115 void Extend(const LogExtra& extra);
116
117 /// @brief Merges contents of other LogExtra with existing key-value pairs
118 /// preserving freeze states
119 void Extend(LogExtra&& extra);
120
121 /// @brief Creates a LogExtra with current thread's stacktrace if the default
122 /// log level is less or equal to DEBUG
123 static LogExtra StacktraceNocache() noexcept;
124
125 /// @brief Creates a LogExtra with current thread's stacktrace if the logger
126 /// log level is less or equal to DEBUG
127 static LogExtra StacktraceNocache(logging::LoggerRef logger) noexcept;
128
129 /// @brief Creates a LogExtra with current thread's stacktrace if the logger
130 /// log level is less or equal to DEBUG. Uses cache for
131 /// faster stacktrace symbolization.
132 static LogExtra Stacktrace() noexcept;
133
134 /// @brief Creates a LogExtra with current thread's stacktrace if the logger
135 /// log level is less or equal to DEBUG. Uses cache for
136 /// faster stacktrace symbolization.
137 static LogExtra Stacktrace(logging::LoggerRef logger) noexcept;
138
139 /// @brief Adds a range of key-value pairs
140 template <typename Iterator>
141 void ExtendRange(Iterator first, Iterator last, ExtendType extend_type = ExtendType::kNormal) {
142 // NOTE: must replace existing rewritable values
143 for (Iterator it = first; it != last; ++it) {
144 Extend(*it, extend_type);
145 }
146 }
147
148 /// @brief Marks specified value as frozen, all attempts to overwrite it will
149 /// 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;
172 void SetFrozen();
173 Value& GetValue() { return value_; }
174 const Value& GetValue() const { 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