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