10#include <gtest/gtest.h>
13#include <unordered_map>
33 auto span_result = tracer.start_span(
"test_operation",
"test_service");
34 ASSERT_TRUE(span_result.is_ok());
36 auto span = span_result.value();
37 EXPECT_FALSE(span->trace_id.empty());
38 EXPECT_FALSE(span->span_id.empty());
39 EXPECT_TRUE(span->parent_span_id.empty());
40 EXPECT_EQ(span->operation_name,
"test_operation");
41 EXPECT_EQ(span->service_name,
"test_service");
42 EXPECT_FALSE(span->is_finished());
46 auto parent_result = tracer.start_span(
"parent_operation");
47 ASSERT_TRUE(parent_result.is_ok());
48 auto parent = parent_result.value();
50 auto child_result = tracer.start_child_span(*parent,
"child_operation");
51 ASSERT_TRUE(child_result.is_ok());
52 auto child = child_result.value();
54 EXPECT_EQ(child->trace_id, parent->trace_id);
55 EXPECT_NE(child->span_id, parent->span_id);
56 EXPECT_EQ(child->parent_span_id, parent->span_id);
57 EXPECT_EQ(child->operation_name,
"child_operation");
61 auto span_result = tracer.start_span(
"test_operation");
62 ASSERT_TRUE(span_result.is_ok());
63 auto span = span_result.value();
66 std::this_thread::sleep_for(std::chrono::milliseconds(10));
68 auto finish_result = tracer.finish_span(span);
69 ASSERT_TRUE(finish_result.is_ok());
71 EXPECT_TRUE(span->is_finished());
72 EXPECT_GT(span->duration.count(), 0);
73 EXPECT_EQ(span->status, trace_span::status_code::ok);
77 auto span_result = tracer.start_span(
"test_operation");
78 ASSERT_TRUE(span_result.is_ok());
79 auto span = span_result.value();
81 auto first_finish = tracer.finish_span(span);
82 ASSERT_TRUE(first_finish.is_ok());
84 auto second_finish = tracer.finish_span(span);
85 ASSERT_TRUE(second_finish.is_err());
89 auto span_result = tracer.start_span(
"test_operation");
90 ASSERT_TRUE(span_result.is_ok());
91 auto span = span_result.value();
94 span->baggage[
"user_id"] =
"12345";
95 span->baggage[
"request_type"] =
"api";
99 auto context = tracer.extract_context(span_ref);
100 EXPECT_EQ(context.trace_id, span->trace_id);
101 EXPECT_EQ(context.span_id, span->span_id);
102 EXPECT_EQ(context.baggage[
"user_id"],
"12345");
103 EXPECT_EQ(context.baggage[
"request_type"],
"api");
108 ctx.
trace_id =
"0af7651916cd43dd8448eb211c80319c";
109 ctx.
span_id =
"b7ad6b7169203331";
113 EXPECT_EQ(header,
"00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01");
116 ASSERT_TRUE(parsed_result.is_ok());
117 auto parsed = parsed_result.value();
119 EXPECT_EQ(parsed.trace_id, ctx.
trace_id);
120 EXPECT_EQ(parsed.span_id, ctx.
span_id);
125 auto span_result = tracer.start_span(
"test_operation");
126 ASSERT_TRUE(span_result.is_ok());
127 auto span = span_result.value();
129 span->baggage[
"test_key"] =
"test_value";
132 std::unordered_map<std::string, std::string> headers;
133 auto context = tracer.extract_context(*span);
134 tracer.inject_context(context, headers);
136 EXPECT_TRUE(headers.contains(
"traceparent"));
137 EXPECT_TRUE(headers.contains(
"baggage-test_key"));
140 auto traceparent = headers[
"traceparent"];
141 EXPECT_EQ(traceparent.substr(0, 3),
"00-");
142 EXPECT_FALSE(traceparent.empty());
145 auto extracted_result = tracer.extract_context_from_carrier(headers);
146 ASSERT_TRUE(extracted_result.is_ok());
147 auto extracted = extracted_result.value();
150 EXPECT_EQ(extracted.baggage[
"test_key"],
"test_value");
153 EXPECT_FALSE(extracted.trace_id.empty());
154 EXPECT_FALSE(extracted.span_id.empty());
160 incoming_ctx.
trace_id =
"0af7651916cd43dd8448eb211c80319c";
161 incoming_ctx.
span_id =
"b7ad6b7169203331";
162 incoming_ctx.
baggage[
"user_id"] =
"67890";
164 auto span_result = tracer.start_span_from_context(incoming_ctx,
"handle_request");
165 ASSERT_TRUE(span_result.is_ok());
166 auto span = span_result.value();
168 EXPECT_EQ(span->trace_id, incoming_ctx.
trace_id);
169 EXPECT_NE(span->span_id, incoming_ctx.
span_id);
170 EXPECT_EQ(span->parent_span_id, incoming_ctx.
span_id);
171 EXPECT_EQ(span->baggage[
"user_id"],
"67890");
175 EXPECT_EQ(tracer.get_current_span(),
nullptr);
177 auto span_result = tracer.start_span(
"test_operation");
178 ASSERT_TRUE(span_result.is_ok());
179 auto span = span_result.value();
181 tracer.set_current_span(span);
182 EXPECT_EQ(tracer.get_current_span(), span);
185 std::thread other_thread([&]() {
186 EXPECT_EQ(tracer.get_current_span(),
nullptr);
188 auto other_span_result = tracer.start_span(
"other_operation");
189 ASSERT_TRUE(other_span_result.is_ok());
190 auto other_span = other_span_result.value();
192 tracer.set_current_span(other_span);
193 EXPECT_EQ(tracer.get_current_span(), other_span);
198 EXPECT_EQ(tracer.get_current_span(), span);
203 auto span_result = tracer.start_span(
"scoped_operation");
204 ASSERT_TRUE(span_result.is_ok());
207 EXPECT_EQ(tracer.get_current_span(), span_result.value());
211 scoped->
tags[
"custom_tag"] =
"custom_value";
218 auto span1_result = tracer.start_span(
"operation1");
219 ASSERT_TRUE(span1_result.is_ok());
220 auto span1 = span1_result.value();
222 auto span2_result = tracer.start_child_span(*span1,
"operation2");
223 ASSERT_TRUE(span2_result.is_ok());
224 auto span2 = span2_result.value();
226 auto span3_result = tracer.start_child_span(*span2,
"operation3");
227 ASSERT_TRUE(span3_result.is_ok());
228 auto span3 = span3_result.value();
231 tracer.finish_span(span1);
232 tracer.finish_span(span2);
233 tracer.finish_span(span3);
236 auto trace_result = tracer.get_trace(span1->trace_id);
237 ASSERT_TRUE(trace_result.is_ok());
238 auto trace = trace_result.value();
240 EXPECT_EQ(trace.size(), 3);
243 for (
const auto& span : trace) {
244 EXPECT_EQ(span.trace_id, span1->trace_id);
245 EXPECT_TRUE(span.is_finished());
250 auto span_result = tracer.start_span(
"tagged_operation",
"my_service");
251 ASSERT_TRUE(span_result.is_ok());
252 auto span = span_result.value();
255 EXPECT_EQ(span->tags[
"span.kind"],
"internal");
256 EXPECT_EQ(span->tags[
"service.name"],
"my_service");
259 span->tags[
"http.method"] =
"GET";
260 span->tags[
"http.status_code"] =
"200";
261 span->tags[
"user.id"] =
"user123";
263 EXPECT_EQ(span->tags[
"http.method"],
"GET");
264 EXPECT_EQ(span->tags[
"http.status_code"],
"200");
265 EXPECT_EQ(span->tags[
"user.id"],
"user123");
269 auto span_result = tracer.start_span(
"status_operation");
270 ASSERT_TRUE(span_result.is_ok());
271 auto span = span_result.value();
273 EXPECT_EQ(span->status, trace_span::status_code::unset);
276 span->status = trace_span::status_code::error;
277 span->status_message =
"Operation failed due to timeout";
279 tracer.finish_span(span);
281 EXPECT_EQ(span->status, trace_span::status_code::error);
282 EXPECT_EQ(span->status_message,
"Operation failed due to timeout");
286 auto parent_result = tracer.start_span(
"parent");
287 ASSERT_TRUE(parent_result.is_ok());
288 auto parent = parent_result.value();
290 parent->baggage[
"session_id"] =
"abc123";
291 parent->baggage[
"feature_flag"] =
"enabled";
293 auto child_result = tracer.start_child_span(*parent,
"child");
294 ASSERT_TRUE(child_result.is_ok());
295 auto child = child_result.value();
298 EXPECT_EQ(child->baggage[
"session_id"],
"abc123");
299 EXPECT_EQ(child->baggage[
"feature_flag"],
"enabled");
302 child->baggage[
"child_data"] =
"xyz";
304 auto grandchild_result = tracer.start_child_span(*child,
"grandchild");
305 ASSERT_TRUE(grandchild_result.is_ok());
306 auto grandchild = grandchild_result.value();
309 EXPECT_EQ(grandchild->baggage[
"session_id"],
"abc123");
310 EXPECT_EQ(grandchild->baggage[
"feature_flag"],
"enabled");
311 EXPECT_EQ(grandchild->baggage[
"child_data"],
"xyz");
315 std::vector<trace_span> spans_to_export;
318 for (
int i = 0; i < 5; ++i) {
319 auto span_result = tracer.start_span(
"operation_" + std::to_string(i));
320 ASSERT_TRUE(span_result.is_ok());
321 auto span = span_result.value();
323 tracer.finish_span(span);
324 spans_to_export.push_back(*span);
327 auto export_result = tracer.export_spans(spans_to_export);
328 ASSERT_TRUE(export_result.is_ok());
331 auto trace_result = tracer.get_trace(spans_to_export[0].trace_id);
332 ASSERT_TRUE(trace_result.is_ok());
333 auto trace = trace_result.value();
346 ASSERT_NE(current,
nullptr);
347 EXPECT_EQ(current->operation_name,
"macro_operation");
353 ASSERT_NE(nested,
nullptr);
354 EXPECT_EQ(nested->operation_name,
"nested_operation");
355 EXPECT_EQ(nested->parent_span_id, current->span_id);
370 kcenon::common::VoidResult
export_spans(
const std::vector<trace_span>& spans)
override {
372 return kcenon::common::VoidResult::err(
error_info(monitoring_error_code::operation_failed,
373 "Mock export failure",
"test").to_common_error());
375 for (
const auto& span : spans) {
379 return kcenon::common::ok();
382 kcenon::common::VoidResult
flush()
override {
384 return kcenon::common::ok();
389 return kcenon::common::ok();
392 std::unordered_map<std::string, std::size_t>
get_stats()
const override {
417 EXPECT_EQ(tracer.get_exporter(),
nullptr);
419 tracer.set_exporter(mock_exporter);
420 EXPECT_EQ(tracer.get_exporter(), mock_exporter);
422 tracer.set_exporter(
nullptr);
423 EXPECT_EQ(tracer.get_exporter(),
nullptr);
432 tracer.configure_export(settings);
434 auto retrieved = tracer.get_export_settings();
435 EXPECT_EQ(retrieved.batch_size, 50);
436 EXPECT_EQ(retrieved.max_queue_size, 1000);
437 EXPECT_TRUE(retrieved.export_on_finish);
441 tracer.set_exporter(mock_exporter);
446 tracer.configure_export(settings);
449 for (
int i = 0; i < 5; ++i) {
450 auto span_result = tracer.start_span(
"operation_" + std::to_string(i));
451 ASSERT_TRUE(span_result.is_ok());
452 tracer.finish_span(span_result.value());
456 EXPECT_EQ(mock_exporter->export_count.load(), 1);
457 EXPECT_EQ(mock_exporter->exported_spans.size(), 5);
461 tracer.set_exporter(mock_exporter);
466 tracer.configure_export(settings);
469 for (
int i = 0; i < 3; ++i) {
470 auto span_result = tracer.start_span(
"operation_" + std::to_string(i));
471 ASSERT_TRUE(span_result.is_ok());
472 tracer.finish_span(span_result.value());
476 EXPECT_EQ(mock_exporter->export_count.load(), 0);
479 auto flush_result = tracer.flush();
480 ASSERT_TRUE(flush_result.is_ok());
483 EXPECT_EQ(mock_exporter->export_count.load(), 1);
484 EXPECT_EQ(mock_exporter->exported_spans.size(), 3);
489 EXPECT_EQ(tracer.get_exporter(),
nullptr);
492 for (
int i = 0; i < 3; ++i) {
493 auto span_result = tracer.start_span(
"operation_" + std::to_string(i));
494 ASSERT_TRUE(span_result.is_ok());
495 tracer.finish_span(span_result.value());
499 auto flush_result = tracer.flush();
500 EXPECT_TRUE(flush_result.is_ok());
504 mock_exporter->should_fail =
true;
505 tracer.set_exporter(mock_exporter);
510 tracer.configure_export(settings);
513 for (
int i = 0; i < 3; ++i) {
514 auto span_result = tracer.start_span(
"operation_" + std::to_string(i));
515 ASSERT_TRUE(span_result.is_ok());
516 tracer.finish_span(span_result.value());
520 auto flush_result = tracer.flush();
521 EXPECT_TRUE(flush_result.is_err());
524 auto stats = tracer.get_export_stats();
525 EXPECT_EQ(stats[
"pending_spans"], 3);
528 mock_exporter->should_fail =
false;
529 flush_result = tracer.flush();
530 EXPECT_TRUE(flush_result.is_ok());
533 EXPECT_EQ(mock_exporter->exported_spans.size(), 3);
537 tracer.set_exporter(mock_exporter);
541 tracer.configure_export(settings);
544 for (
int i = 0; i < 10; ++i) {
545 auto span_result = tracer.start_span(
"operation_" + std::to_string(i));
546 ASSERT_TRUE(span_result.is_ok());
547 tracer.finish_span(span_result.value());
550 auto stats = tracer.get_export_stats();
551 EXPECT_EQ(stats[
"exported_spans"], 10);
552 EXPECT_EQ(stats[
"failed_exports"], 0);
553 EXPECT_EQ(stats[
"dropped_spans"], 0);
557 tracer.set_exporter(mock_exporter);
558 mock_exporter->should_fail =
true;
564 tracer.configure_export(settings);
567 for (
int i = 0; i < 10; ++i) {
568 auto span_result = tracer.start_span(
"operation_" + std::to_string(i));
569 ASSERT_TRUE(span_result.is_ok());
570 tracer.finish_span(span_result.value());
574 auto stats = tracer.get_export_stats();
575 EXPECT_GT(stats[
"dropped_spans"], 0);
576 EXPECT_LE(stats[
"pending_spans"], 5);
580 tracer.set_exporter(mock_exporter);
584 tracer.configure_export(settings);
586 auto span_result = tracer.start_span(
"test_operation",
"test_service");
587 ASSERT_TRUE(span_result.is_ok());
588 auto span = span_result.value();
589 span->tags[
"custom_tag"] =
"custom_value";
591 tracer.finish_span(span);
593 ASSERT_EQ(mock_exporter->exported_spans.size(), 1);
594 const auto& exported = mock_exporter->exported_spans[0];
596 EXPECT_EQ(exported.operation_name,
"test_operation");
597 EXPECT_EQ(exported.service_name,
"test_service");
598 EXPECT_EQ(exported.trace_id, span->trace_id);
599 EXPECT_EQ(exported.span_id, span->span_id);
600 auto tag_it = exported.tags.find(
"custom_tag");
601 ASSERT_NE(tag_it, exported.tags.end());
602 EXPECT_EQ(tag_it->second,
"custom_value");
603 EXPECT_TRUE(exported.is_finished());
distributed_tracer tracer
distributed_tracer tracer
std::shared_ptr< MockTraceExporter > mock_exporter
kcenon::common::VoidResult export_spans(const std::vector< trace_span > &spans) override
Export a batch of spans.
std::atomic< std::size_t > export_count
std::atomic< std::size_t > flush_count
kcenon::common::VoidResult shutdown() override
Shutdown the exporter.
kcenon::common::VoidResult flush() override
Flush any pending spans.
std::atomic< std::size_t > shutdown_count
std::vector< trace_span > exported_spans
std::unordered_map< std::string, std::size_t > get_stats() const override
Get exporter statistics.
Distributed tracer for managing spans and traces.
std::shared_ptr< trace_span > get_current_span() const
Get current active span for this thread.
void set_exporter(std::shared_ptr< trace_exporter_interface > exporter)
Set the trace exporter for span export.
Scoped span for RAII-style span management.
Abstract interface for trace exporters.
Distributed tracing implementation for monitoring system.
#define TRACE_CHILD_SPAN(parent, operation_name)
#define TRACE_SPAN(operation_name)
Helper macro for creating a scoped span.
distributed_tracer & global_tracer()
Global tracer instance.
Extended error information with context.
Trace context for propagation across service boundaries.
std::string to_w3c_traceparent() const
Serialize to W3C Trace Context format.
std::unordered_map< std::string, std::string > baggage
static common::Result< trace_context > from_w3c_traceparent(const std::string &header)
Parse from W3C Trace Context format.
Configuration settings for trace export behavior.
std::size_t max_queue_size
Maximum spans in queue before dropping.
bool export_on_finish
Export when batch is full.
std::size_t batch_size
Number of spans to batch before export.
Trace span representing a unit of work in distributed tracing.
std::unordered_map< std::string, std::string > tags
bool is_finished() const
Check if span has finished.
TEST_F(DistributedTracingTest, CreateRootSpan)
Trace data exporters for various distributed tracing systems.