26using namespace std::chrono_literals;
40 const std::map<std::string, std::string>& headers) {
41 std::cout <<
"[" <<
service_name_ <<
"] Processing request: " << request_id << std::endl;
46 std::shared_ptr<trace_span> span;
48 if (context_result.is_ok()) {
51 context_result.value(),
54 if (span_result.is_ok()) {
55 span = span_result.value();
57 << context_result.value().trace_id << std::endl;
65 if (span_result.is_ok()) {
66 span = span_result.value();
68 << span->trace_id << std::endl;
75 span->tags[
"request_id"] = request_id;
76 span->tags[
"http.method"] =
"GET";
77 span->tags[
"http.url"] =
"/api/process";
78 span->tags[
"user.id"] =
"user123";
87 span->status = trace_span::status_code::ok;
93 << span->span_id << std::endl;
101 if (!span_result.is_ok())
return;
103 auto span = span_result.value();
104 span->tags[
"operation"] =
"data_processing";
106 std::cout <<
"[" <<
service_name_ <<
"] Processing business logic..." << std::endl;
109 std::this_thread::sleep_for(50ms);
120 if (!span_result.is_ok())
return;
122 auto span = span_result.value();
123 span->tags[
"db.type"] =
"postgresql";
124 span->tags[
"db.statement"] =
"SELECT * FROM users WHERE id = ?";
126 std::cout <<
"[" <<
service_name_ <<
"] Querying database..." << std::endl;
129 std::this_thread::sleep_for(20ms);
137 if (!span_result.is_ok())
return;
139 auto span = span_result.value();
140 span->tags[
"peer.service"] =
"downstream_service";
141 span->tags[
"span.kind"] =
"client";
147 std::map<std::string, std::string> headers;
150 std::cout <<
"[" <<
service_name_ <<
"] Calling downstream service..." << std::endl;
151 std::cout <<
" Propagating trace: " << context.trace_id << std::endl;
154 std::this_thread::sleep_for(30ms);
167 WebService database_service(tracer,
"database_service");
169 std::cout <<
"\n=== Simulating distributed request flow ===" << std::endl;
172 std::map<std::string, std::string> initial_headers;
173 initial_headers[
"user-agent"] =
"example-client";
178 std::cout <<
"\n=== Simulating request with existing trace ===" << std::endl;
181 std::map<std::string, std::string> traced_headers;
182 traced_headers[
"traceparent"] =
"00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01";
183 traced_headers[
"baggage-user-id"] =
"user456";
190 std::cout <<
"\n=== Analyzing traces ===" << std::endl;
193 auto root_span_result = tracer.
start_span(
"analyze_operation",
"analyzer");
194 if (!root_span_result.is_ok())
return;
196 auto root_span = root_span_result.value();
197 root_span->tags[
"analysis.type"] =
"performance";
200 std::vector<std::shared_ptr<trace_span>> child_spans;
202 for (
int i = 0; i < 5; ++i) {
204 "sub_operation_" + std::to_string(i));
206 if (child_result.is_ok()) {
207 auto child = child_result.value();
208 child->tags[
"index"] = std::to_string(i);
209 child->tags[
"complexity"] = (i % 2 == 0) ?
"low" :
"high";
212 std::this_thread::sleep_for(std::chrono::milliseconds(10 * (i + 1)));
214 child_spans.push_back(child);
219 for (
auto& child : child_spans) {
224 auto error_span_result = tracer.
start_child_span(*root_span,
"failing_operation");
225 if (error_span_result.is_ok()) {
226 auto error_span = error_span_result.value();
227 error_span->status = trace_span::status_code::error;
228 error_span->status_message =
"Database connection timeout";
229 error_span->tags[
"error"] =
"true";
230 error_span->tags[
"error.type"] =
"timeout";
238 auto trace_result = tracer.
get_trace(root_span->trace_id);
239 if (trace_result.is_ok()) {
240 auto& spans = trace_result.value();
242 std::cout <<
"Trace ID: " << root_span->trace_id << std::endl;
243 std::cout <<
"Total spans in trace: " << spans.size() << std::endl;
246 if (!spans.empty()) {
247 auto min_time = spans[0].start_time;
248 auto max_time = spans[0].end_time;
250 for (
const auto& span : spans) {
251 if (span.start_time < min_time) min_time = span.start_time;
252 if (span.end_time > max_time) max_time = span.end_time;
255 auto total_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
259 std::cout <<
"Total trace duration: " << total_duration.count() <<
" ms" << std::endl;
264 for (
const auto& span : spans) {
265 if (span.status == trace_span::status_code::error) {
267 std::cout <<
"Error in span: " << span.operation_name
268 <<
" - " << span.status_message << std::endl;
272 std::cout <<
"Spans with errors: " << error_count << std::endl;
277 std::cout <<
"=== Distributed Tracing Example ===" << std::endl;
281 std::cout <<
"\n--- Part 1: Basic Span Management ---" << std::endl;
286 auto root_span_result = tracer.
start_span(
"main_operation",
"example_service");
287 if (!root_span_result.is_ok()) {
288 std::cerr <<
"Failed to create root span" << std::endl;
292 auto root_span = root_span_result.value();
294 std::cout <<
"Created root span:" << std::endl;
295 std::cout <<
" Trace ID: " << root_span->trace_id << std::endl;
296 std::cout <<
" Span ID: " << root_span->span_id << std::endl;
297 std::cout <<
" Operation: " << root_span->operation_name << std::endl;
300 root_span->tags[
"version"] =
"1.0.0";
301 root_span->tags[
"environment"] =
"development";
304 root_span->baggage[
"user.id"] =
"user789";
305 root_span->baggage[
"session.id"] =
"sess123";
308 std::cout <<
"\nCreating child spans..." << std::endl;
310 auto child1_result = tracer.
start_child_span(*root_span,
"child_operation_1");
311 auto child2_result = tracer.
start_child_span(*root_span,
"child_operation_2");
313 if (child1_result.is_ok() && child2_result.is_ok()) {
314 auto child1 = child1_result.value();
315 auto child2 = child2_result.value();
317 std::cout <<
" Child 1 span ID: " << child1->span_id << std::endl;
318 std::cout <<
" Child 2 span ID: " << child2->span_id << std::endl;
321 std::this_thread::sleep_for(10ms);
331 std::cout <<
"All spans finished" << std::endl;
334 std::cout <<
"\n--- Part 2: Distributed System Simulation ---" << std::endl;
338 std::cout <<
"\n--- Part 3: Trace Analysis ---" << std::endl;
342 std::cout <<
"\n--- Part 4: Context Propagation ---" << std::endl;
344 auto demo_span_result = tracer.
start_span(
"propagation_demo");
345 if (demo_span_result.is_ok()) {
346 auto demo_span = demo_span_result.value();
352 std::map<std::string, std::string> http_headers;
355 std::cout <<
"Context injected into headers:" << std::endl;
356 for (
const auto& [key, value] : http_headers) {
357 std::cout <<
" " << key <<
": " << value << std::endl;
362 if (extracted_context.is_ok()) {
363 std::cout <<
"\nContext extracted from headers:" << std::endl;
364 std::cout <<
" Trace ID: " << extracted_context.value().trace_id << std::endl;
365 std::cout <<
" Span ID: " << extracted_context.value().span_id << std::endl;
369 extracted_context.value(),
370 "continued_operation"
373 if (continued_span.is_ok()) {
374 std::cout <<
" Continued span ID: "
375 << continued_span.value()->span_id << std::endl;
383 }
catch (
const std::exception& e) {
384 std::cerr <<
"Exception: " << e.what() << std::endl;
388 std::cout <<
"\n=== Example completed successfully ===" << std::endl;
void handle_request(const std::string &request_id, const std::map< std::string, std::string > &headers)
void process_business_logic(std::shared_ptr< trace_span > parent_span)
std::string service_name_
WebService(distributed_tracer &tracer, const std::string &name)
void call_downstream_service(std::shared_ptr< trace_span > parent_span)
distributed_tracer & tracer_
void query_database(std::shared_ptr< trace_span > parent_span)
Distributed tracer for managing spans and traces.
common::Result< std::shared_ptr< trace_span > > start_span_from_context(const trace_context &context, const std::string &operation_name)
Start a span from trace context (for incoming requests)
common::Result< trace_context > extract_context_from_carrier(const Carrier &carrier)
Extract trace context from carrier.
trace_context extract_context(const trace_span &span) const
Extract trace context for propagation.
void inject_context(const trace_context &context, Carrier &carrier)
Inject trace context into carrier (e.g., HTTP headers)
common::Result< std::vector< trace_span > > get_trace(const std::string &trace_id) const
Get all spans for a trace.
common::Result< std::shared_ptr< trace_span > > start_span(const std::string &operation_name, const std::string &service_name="monitoring_system")
Start a new root span.
common::Result< bool > finish_span(std::shared_ptr< trace_span > span)
Finish a span.
common::Result< std::shared_ptr< trace_span > > start_child_span(const trace_span &parent, const std::string &operation_name)
Start a child span.
Distributed tracing implementation for monitoring system.
void simulate_distributed_system()
void analyze_traces(distributed_tracer &tracer)
Thread-local context management for request tracking and distributed tracing.