Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
span.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
12
13#include <utility>
14
16
21{
22 std::string name;
26 std::string status_description;
27 std::map<std::string, attribute_value> attributes;
28 std::vector<span_event> events;
29 std::chrono::steady_clock::time_point start_time;
30 std::chrono::steady_clock::time_point end_time;
31 bool ended{false};
33 span* owner{nullptr};
34
35 impl(std::string_view span_name, trace_context ctx, span_kind span_kind_value)
36 : name(span_name)
37 , context(std::move(ctx))
38 , kind(span_kind_value)
39 , start_time(std::chrono::steady_clock::now())
42 {
43 // Set this span's context as the current context
45 }
46
48 {
49 // Note: do_end() is now called from span::~span() before impl_ destruction
50 // to ensure owner->impl_ is still valid when export_span is called.
51 // This is necessary because libc++'s unique_ptr sets its internal pointer
52 // to null before calling the deleter, which would cause owner->impl_ to
53 // be null when export_span tries to access span data.
54 }
55
56 void do_end()
57 {
58 if (ended)
59 {
60 return;
61 }
62
63 ended = true;
64 end_time = std::chrono::steady_clock::now();
65
66 // Restore previous context
68 {
70 }
71 else
72 {
74 }
75
76 // Export the span
77 if (owner)
78 {
80 }
81 }
82};
83
84span::span(std::string_view name, trace_context ctx, span_kind kind)
85 : impl_(std::make_unique<impl>(name, std::move(ctx), kind))
86{
87 impl_->owner = this;
88}
89
91{
92 // End span before impl_ destruction to ensure owner->impl_ is still valid
93 if (impl_ && !impl_->ended)
94 {
95 impl_->do_end();
96 }
97}
98
99span::span(span&& other) noexcept
100 : impl_(std::move(other.impl_))
101{
102 if (impl_)
103 {
104 impl_->owner = this;
105 }
106}
107
108auto span::operator=(span&& other) noexcept -> span&
109{
110 if (this != &other)
111 {
112 impl_ = std::move(other.impl_);
113 if (impl_)
114 {
115 impl_->owner = this;
116 }
117 }
118 return *this;
119}
120
121auto span::set_attribute(std::string_view key, std::string_view value) -> span&
122{
123 if (impl_ && !impl_->ended)
124 {
125 impl_->attributes[std::string(key)] = std::string(value);
126 }
127 return *this;
128}
129
130auto span::set_attribute(std::string_view key, const char* value) -> span&
131{
132 return set_attribute(key, std::string_view(value));
133}
134
135auto span::set_attribute(std::string_view key, int64_t value) -> span&
136{
137 if (impl_ && !impl_->ended)
138 {
139 impl_->attributes[std::string(key)] = value;
140 }
141 return *this;
142}
143
144auto span::set_attribute(std::string_view key, double value) -> span&
145{
146 if (impl_ && !impl_->ended)
147 {
148 impl_->attributes[std::string(key)] = value;
149 }
150 return *this;
151}
152
153auto span::set_attribute(std::string_view key, bool value) -> span&
154{
155 if (impl_ && !impl_->ended)
156 {
157 impl_->attributes[std::string(key)] = value;
158 }
159 return *this;
160}
161
162auto span::add_event(std::string_view name) -> span&
163{
164 if (impl_ && !impl_->ended)
165 {
166 span_event event;
167 event.name = std::string(name);
168 event.timestamp = std::chrono::steady_clock::now();
169 impl_->events.push_back(std::move(event));
170 }
171 return *this;
172}
173
174auto span::add_event(std::string_view name,
175 const std::map<std::string, attribute_value>& attributes) -> span&
176{
177 if (impl_ && !impl_->ended)
178 {
179 span_event event;
180 event.name = std::string(name);
181 event.timestamp = std::chrono::steady_clock::now();
182 event.attributes = attributes;
183 impl_->events.push_back(std::move(event));
184 }
185 return *this;
186}
187
189{
190 if (impl_ && !impl_->ended)
191 {
192 impl_->status = status;
193 }
194 return *this;
195}
196
197auto span::set_status(span_status status, std::string_view description) -> span&
198{
199 if (impl_ && !impl_->ended)
200 {
201 impl_->status = status;
202 impl_->status_description = std::string(description);
203 }
204 return *this;
205}
206
207auto span::set_error(std::string_view message) -> span&
208{
209 if (impl_ && !impl_->ended)
210 {
211 impl_->status = span_status::error;
212 impl_->status_description = std::string(message);
213
214 // Also add an exception event following OpenTelemetry conventions
215 std::map<std::string, attribute_value> event_attrs;
216 event_attrs["exception.message"] = std::string(message);
217 add_event("exception", event_attrs);
218 }
219 return *this;
220}
221
223{
224 if (impl_)
225 {
226 impl_->do_end();
227 }
228}
229
230auto span::is_ended() const noexcept -> bool
231{
232 return impl_ ? impl_->ended : true;
233}
234
235auto span::context() const noexcept -> const trace_context&
236{
237 static const trace_context empty_context;
238 return impl_ ? impl_->context : empty_context;
239}
240
241auto span::name() const noexcept -> const std::string&
242{
243 static const std::string empty_name;
244 return impl_ ? impl_->name : empty_name;
245}
246
247auto span::kind() const noexcept -> span_kind
248{
250}
251
252auto span::status() const noexcept -> span_status
253{
255}
256
257auto span::status_description() const noexcept -> const std::string&
258{
259 static const std::string empty_description;
260 return impl_ ? impl_->status_description : empty_description;
261}
262
263auto span::attributes() const noexcept
264 -> const std::map<std::string, attribute_value>&
265{
266 static const std::map<std::string, attribute_value> empty_attrs;
267 return impl_ ? impl_->attributes : empty_attrs;
268}
269
270auto span::events() const noexcept -> const std::vector<span_event>&
271{
272 static const std::vector<span_event> empty_events;
273 return impl_ ? impl_->events : empty_events;
274}
275
276auto span::start_time() const noexcept -> std::chrono::steady_clock::time_point
277{
278 return impl_ ? impl_->start_time : std::chrono::steady_clock::time_point{};
279}
280
281auto span::end_time() const noexcept -> std::chrono::steady_clock::time_point
282{
283 return impl_ ? impl_->end_time : std::chrono::steady_clock::time_point{};
284}
285
286auto span::duration() const noexcept -> std::chrono::nanoseconds
287{
288 if (!impl_)
289 {
290 return std::chrono::nanoseconds::zero();
291 }
292
293 auto end = impl_->ended ? impl_->end_time : std::chrono::steady_clock::now();
294 return std::chrono::duration_cast<std::chrono::nanoseconds>(end - impl_->start_time);
295}
296
297} // namespace kcenon::network::tracing
RAII span for distributed tracing.
Definition span.h:103
auto status() const noexcept -> span_status
Get the span status.
Definition span.cpp:252
auto is_ended() const noexcept -> bool
Check if the span has ended.
Definition span.cpp:230
auto start_time() const noexcept -> std::chrono::steady_clock::time_point
Get the span start time.
Definition span.cpp:276
auto attributes() const noexcept -> const std::map< std::string, attribute_value > &
Get the span attributes.
Definition span.cpp:263
auto set_attribute(std::string_view key, std::string_view value) -> span &
Set a string attribute.
Definition span.cpp:121
auto kind() const noexcept -> span_kind
Get the span kind.
Definition span.cpp:247
span(std::string_view name, trace_context ctx, span_kind kind=span_kind::internal)
Construct a new span.
Definition span.cpp:84
auto add_event(std::string_view name) -> span &
Add an event to the span.
Definition span.cpp:162
auto set_error(std::string_view message) -> span &
Set error status with message.
Definition span.cpp:207
auto status_description() const noexcept -> const std::string &
Get the status description.
Definition span.cpp:257
auto context() const noexcept -> const trace_context &
Get the trace context for this span.
Definition span.cpp:235
auto name() const noexcept -> const std::string &
Get the span name.
Definition span.cpp:241
auto operator=(const span &) -> span &=delete
~span()
Destructor - automatically ends the span if not ended.
Definition span.cpp:90
auto events() const noexcept -> const std::vector< span_event > &
Get the span events.
Definition span.cpp:270
auto set_status(span_status status) -> span &
Set the span status.
Definition span.cpp:188
auto duration() const noexcept -> std::chrono::nanoseconds
Get the span duration.
Definition span.cpp:286
void end()
Manually end the span.
Definition span.cpp:222
std::unique_ptr< impl > impl_
Definition span.h:286
auto end_time() const noexcept -> std::chrono::steady_clock::time_point
Get the span end time.
Definition span.cpp:281
Immutable trace context for distributed tracing.
static void clear_current()
Clear the current thread-local trace context.
auto is_valid() const noexcept -> bool
Check if this context is valid.
static void set_current(const trace_context &ctx)
Set the current thread-local trace context.
std::variant< std::string, int64_t, double, bool > attribute_value
Attribute value type (supports string, int64, double, bool)
Definition span.h:55
span_kind
Span kind following OpenTelemetry conventions.
Definition span.h:44
@ internal
Default, represents internal operations.
span_status
Span status codes following OpenTelemetry conventions.
Definition span.h:34
@ unset
Default status, span completed without explicit status.
void export_span(const span &s)
Export a completed span.
RAII span implementation for distributed tracing.
Internal implementation structure for span.
Definition span.cpp:21
std::map< std::string, attribute_value > attributes
Definition span.cpp:27
std::chrono::steady_clock::time_point end_time
Definition span.cpp:30
impl(std::string_view span_name, trace_context ctx, span_kind span_kind_value)
Definition span.cpp:35
std::chrono::steady_clock::time_point start_time
Definition span.cpp:29
std::vector< span_event > events
Definition span.cpp:28
Span event (timestamped annotation)
Definition span.h:61
Configuration structures for OpenTelemetry tracing.