Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
unified_log_context.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
6
7#include <algorithm>
8#include <mutex>
9
10namespace kcenon::logger {
11
13 std::shared_lock lock(other.mutex_);
14 data_ = other.data_;
15}
16
18 std::unique_lock lock(other.mutex_);
19 data_ = std::move(other.data_);
20}
21
23 if (this != &other) {
24 std::scoped_lock lock(mutex_, other.mutex_);
25 data_ = other.data_;
26 }
27 return *this;
28}
29
31 if (this != &other) {
32 std::scoped_lock lock(mutex_, other.mutex_);
33 data_ = std::move(other.data_);
34 }
35 return *this;
36}
37
38// =========================================================================
39// Setters
40// =========================================================================
41
43 context_value value,
44 context_category category) {
45 std::unique_lock lock(mutex_);
46 data_[std::string(key)] = entry{std::move(value), category};
47 return *this;
48}
49
51 std::string_view trace_id,
52 std::string_view span_id,
53 std::optional<std::string_view> parent_span_id) {
54 std::unique_lock lock(mutex_);
55 data_["trace_id"] = entry{std::string(trace_id), context_category::trace};
56 data_["span_id"] = entry{std::string(span_id), context_category::trace};
57 if (parent_span_id) {
58 data_["parent_span_id"] = entry{std::string(*parent_span_id), context_category::trace};
59 }
60 return *this;
61}
62
64 std::string_view request_id,
65 std::optional<std::string_view> correlation_id) {
66 std::unique_lock lock(mutex_);
67 data_["request_id"] = entry{std::string(request_id), context_category::request};
68 if (correlation_id) {
69 data_["correlation_id"] = entry{std::string(*correlation_id), context_category::request};
70 }
71 return *this;
72}
73
75 std::unique_lock lock(mutex_);
76 if (!ctx.trace_id.empty()) {
77 data_["otel_trace_id"] = entry{ctx.trace_id, context_category::otel};
78 }
79 if (!ctx.span_id.empty()) {
80 data_["otel_span_id"] = entry{ctx.span_id, context_category::otel};
81 }
82 if (!ctx.trace_flags.empty()) {
83 data_["otel_trace_flags"] = entry{ctx.trace_flags, context_category::otel};
84 }
85 if (!ctx.trace_state.empty()) {
86 data_["otel_trace_state"] = entry{ctx.trace_state, context_category::otel};
87 }
88 return *this;
89}
90
91// =========================================================================
92// Getters
93// =========================================================================
94
95std::optional<context_value> unified_log_context::get(std::string_view key) const {
96 std::shared_lock lock(mutex_);
97 auto it = data_.find(std::string(key));
98 if (it != data_.end()) {
99 return it->second.value;
100 }
101 return std::nullopt;
102}
103
104std::string unified_log_context::get_string(std::string_view key,
105 std::string_view default_value) const {
106 auto value = get(key);
107 if (!value) {
108 return std::string(default_value);
109 }
110 if (auto* str = std::get_if<std::string>(&*value)) {
111 return *str;
112 }
113 return std::string(default_value);
114}
115
116std::optional<context_category> unified_log_context::get_category(std::string_view key) const {
117 std::shared_lock lock(mutex_);
118 auto it = data_.find(std::string(key));
119 if (it != data_.end()) {
120 return it->second.category;
121 }
122 return std::nullopt;
123}
124
125// =========================================================================
126// Query methods
127// =========================================================================
128
129bool unified_log_context::has(std::string_view key) const {
130 std::shared_lock lock(mutex_);
131 return data_.find(std::string(key)) != data_.end();
132}
133
135 std::shared_lock lock(mutex_);
136 return data_.empty();
137}
138
140 std::shared_lock lock(mutex_);
141 return data_.size();
142}
143
144std::vector<std::string> unified_log_context::keys() const {
145 std::shared_lock lock(mutex_);
146 std::vector<std::string> result;
147 result.reserve(data_.size());
148 for (const auto& [key, _] : data_) {
149 result.push_back(key);
150 }
151 return result;
152}
153
154std::vector<std::string> unified_log_context::keys(context_category category) const {
155 std::shared_lock lock(mutex_);
156 std::vector<std::string> result;
157 for (const auto& [key, entry] : data_) {
158 if (entry.category == category) {
159 result.push_back(key);
160 }
161 }
162 return result;
163}
164
165// =========================================================================
166// Removal
167// =========================================================================
168
169void unified_log_context::remove(std::string_view key) {
170 std::unique_lock lock(mutex_);
171 data_.erase(std::string(key));
172}
173
175 std::unique_lock lock(mutex_);
176 data_.clear();
177}
178
180 std::unique_lock lock(mutex_);
181 for (auto it = data_.begin(); it != data_.end();) {
182 if (it->second.category == category) {
183 it = data_.erase(it);
184 } else {
185 ++it;
186 }
187 }
188}
189
190// =========================================================================
191// Export
192// =========================================================================
193
195 std::shared_lock lock(mutex_);
197 for (const auto& [key, entry] : data_) {
198 std::visit(
199 [&result, &key](const auto& val) {
200 using T = std::decay_t<decltype(val)>;
201 if constexpr (std::is_same_v<T, std::monostate>) {
202 // Skip null values
203 } else if constexpr (std::is_same_v<T, bool>) {
204 result[key] = val;
205 } else if constexpr (std::is_same_v<T, int64_t>) {
206 result[key] = val;
207 } else if constexpr (std::is_same_v<T, double>) {
208 result[key] = val;
209 } else if constexpr (std::is_same_v<T, std::string>) {
210 result[key] = val;
211 }
212 },
213 entry.value);
214 }
215 return result;
216}
217
219 std::scoped_lock lock(mutex_, other.mutex_);
220 for (const auto& [key, entry] : other.data_) {
221 if (overwrite || data_.find(key) == data_.end()) {
222 data_[key] = entry;
223 }
224 }
225 return *this;
226}
227
228} // namespace kcenon::logger
Unified interface for managing all types of logging context.
bool empty() const
Check if the context is empty.
unified_log_context()=default
Default constructor.
unified_log_context & set_trace(std::string_view trace_id, std::string_view span_id, std::optional< std::string_view > parent_span_id=std::nullopt)
Set trace context.
std::vector< std::string > keys() const
Get all keys in the context.
unified_log_context & set_otel(const otlp::otel_context &ctx)
Set OpenTelemetry context.
unified_log_context & merge(const unified_log_context &other, bool overwrite=true)
Merge another context into this one.
unified_log_context & set_request(std::string_view request_id, std::optional< std::string_view > correlation_id=std::nullopt)
Set request context.
bool has(std::string_view key) const
Check if a key exists in the context.
std::optional< context_value > get(std::string_view key) const
Get a context value by key.
size_t size() const
Get the number of entries.
std::optional< context_category > get_category(std::string_view key) const
Get the category of a context entry.
void clear()
Clear all entries from the context.
std::unordered_map< std::string, entry > data_
std::string get_string(std::string_view key, std::string_view default_value="") const
Get a context value as string.
unified_log_context & set(std::string_view key, context_value value, context_category category=context_category::custom)
Set a context value.
void remove(std::string_view key)
Remove a specific key from the context.
log_fields to_fields() const
Export context to log_fields format.
unified_log_context & operator=(const unified_log_context &other)
Copy assignment operator.
std::unordered_map< std::string, log_value > log_fields
Type alias for structured fields map.
Definition log_entry.h:75
std::variant< std::monostate, bool, int64_t, double, std::string > context_value
Value type for unified context storage.
context_category
Categories for organizing context entries.
@ trace
Distributed tracing (trace_id, span_id, parent_span_id)
@ request
Request metadata (request_id, correlation_id)
@ otel
OpenTelemetry specific fields.
OpenTelemetry context for trace correlation.
Unified interface for managing all types of logging context.