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