Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
distributed_tracing_example.cpp File Reference

Example demonstrating distributed tracing across services. More...

#include <iostream>
#include <thread>
#include <map>
#include <vector>
#include "kcenon/monitoring/tracing/distributed_tracer.h"
#include "kcenon/monitoring/context/thread_context.h"
Include dependency graph for distributed_tracing_example.cpp:

Go to the source code of this file.

Classes

class  WebService
 

Functions

void simulate_distributed_system ()
 
void analyze_traces (distributed_tracer &tracer)
 
int main ()
 

Detailed Description

Example demonstrating distributed tracing across services.

Definition in file distributed_tracing_example.cpp.

Function Documentation

◆ analyze_traces()

void analyze_traces ( distributed_tracer & tracer)
Examples
distributed_tracing_example.cpp.

Definition at line 189 of file distributed_tracing_example.cpp.

189 {
190 std::cout << "\n=== Analyzing traces ===" << std::endl;
191
192 // Create a sample trace for analysis
193 auto root_span_result = tracer.start_span("analyze_operation", "analyzer");
194 if (!root_span_result.is_ok()) return;
195
196 auto root_span = root_span_result.value();
197 root_span->tags["analysis.type"] = "performance";
198
199 // Create multiple child spans to simulate complex operation
200 std::vector<std::shared_ptr<trace_span>> child_spans;
201
202 for (int i = 0; i < 5; ++i) {
203 auto child_result = tracer.start_child_span(*root_span,
204 "sub_operation_" + std::to_string(i));
205
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";
210
211 // Simulate varying durations
212 std::this_thread::sleep_for(std::chrono::milliseconds(10 * (i + 1)));
213
214 child_spans.push_back(child);
215 }
216 }
217
218 // Finish all child spans
219 for (auto& child : child_spans) {
220 tracer.finish_span(child);
221 }
222
223 // Simulate an error in one operation
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";
231
232 tracer.finish_span(error_span);
233 }
234
235 tracer.finish_span(root_span);
236
237 // Get all spans for the trace
238 auto trace_result = tracer.get_trace(root_span->trace_id);
239 if (trace_result.is_ok()) {
240 auto& spans = trace_result.value();
241
242 std::cout << "Trace ID: " << root_span->trace_id << std::endl;
243 std::cout << "Total spans in trace: " << spans.size() << std::endl;
244
245 // Calculate total duration
246 if (!spans.empty()) {
247 auto min_time = spans[0].start_time;
248 auto max_time = spans[0].end_time;
249
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;
253 }
254
255 auto total_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
256 max_time - min_time
257 );
258
259 std::cout << "Total trace duration: " << total_duration.count() << " ms" << std::endl;
260 }
261
262 // Count errors
263 int error_count = 0;
264 for (const auto& span : spans) {
265 if (span.status == trace_span::status_code::error) {
266 error_count++;
267 std::cout << "Error in span: " << span.operation_name
268 << " - " << span.status_message << std::endl;
269 }
270 }
271
272 std::cout << "Spans with errors: " << error_count << std::endl;
273 }
274}
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.

References kcenon::monitoring::distributed_tracer::finish_span(), kcenon::monitoring::distributed_tracer::get_trace(), kcenon::monitoring::distributed_tracer::start_child_span(), and kcenon::monitoring::distributed_tracer::start_span().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( )

Definition at line 276 of file distributed_tracing_example.cpp.

276 {
277 std::cout << "=== Distributed Tracing Example ===" << std::endl;
278
279 try {
280 // Part 1: Basic span creation and management
281 std::cout << "\n--- Part 1: Basic Span Management ---" << std::endl;
282
283 distributed_tracer tracer;
284
285 // Create a root span
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;
289 return 1;
290 }
291
292 auto root_span = root_span_result.value();
293
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;
298
299 // Add tags
300 root_span->tags["version"] = "1.0.0";
301 root_span->tags["environment"] = "development";
302
303 // Add baggage (propagated to child spans)
304 root_span->baggage["user.id"] = "user789";
305 root_span->baggage["session.id"] = "sess123";
306
307 // Create child spans
308 std::cout << "\nCreating child spans..." << std::endl;
309
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");
312
313 if (child1_result.is_ok() && child2_result.is_ok()) {
314 auto child1 = child1_result.value();
315 auto child2 = child2_result.value();
316
317 std::cout << " Child 1 span ID: " << child1->span_id << std::endl;
318 std::cout << " Child 2 span ID: " << child2->span_id << std::endl;
319
320 // Simulate some work
321 std::this_thread::sleep_for(10ms);
322
323 // Finish child spans
324 tracer.finish_span(child1);
325 tracer.finish_span(child2);
326 }
327
328 // Finish root span
329 tracer.finish_span(root_span);
330
331 std::cout << "All spans finished" << std::endl;
332
333 // Part 2: Distributed system simulation
334 std::cout << "\n--- Part 2: Distributed System Simulation ---" << std::endl;
336
337 // Part 3: Trace analysis
338 std::cout << "\n--- Part 3: Trace Analysis ---" << std::endl;
339 analyze_traces(tracer);
340
341 // Part 4: Context propagation demonstration
342 std::cout << "\n--- Part 4: Context Propagation ---" << std::endl;
343
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();
347
348 // Extract context for propagation
349 auto context = tracer.extract_context(*demo_span);
350
351 // Simulate HTTP headers
352 std::map<std::string, std::string> http_headers;
353 tracer.inject_context(context, http_headers);
354
355 std::cout << "Context injected into headers:" << std::endl;
356 for (const auto& [key, value] : http_headers) {
357 std::cout << " " << key << ": " << value << std::endl;
358 }
359
360 // Simulate receiving headers in another service
361 auto extracted_context = tracer.extract_context_from_carrier(http_headers);
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;
366
367 // Continue trace in new service
368 auto continued_span = tracer.start_span_from_context(
369 extracted_context.value(),
370 "continued_operation"
371 );
372
373 if (continued_span.is_ok()) {
374 std::cout << " Continued span ID: "
375 << continued_span.value()->span_id << std::endl;
376 tracer.finish_span(continued_span.value());
377 }
378 }
379
380 tracer.finish_span(demo_span);
381 }
382
383 } catch (const std::exception& e) {
384 std::cerr << "Exception: " << e.what() << std::endl;
385 return 1;
386 }
387
388 std::cout << "\n=== Example completed successfully ===" << std::endl;
389
390 return 0;
391}
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)
void simulate_distributed_system()
void analyze_traces(distributed_tracer &tracer)

References analyze_traces(), kcenon::monitoring::distributed_tracer::extract_context(), kcenon::monitoring::distributed_tracer::extract_context_from_carrier(), kcenon::monitoring::distributed_tracer::finish_span(), kcenon::monitoring::distributed_tracer::inject_context(), simulate_distributed_system(), kcenon::monitoring::distributed_tracer::start_child_span(), kcenon::monitoring::distributed_tracer::start_span(), and kcenon::monitoring::distributed_tracer::start_span_from_context().

Here is the call graph for this function:

◆ simulate_distributed_system()

void simulate_distributed_system ( )
Examples
distributed_tracing_example.cpp.

Definition at line 161 of file distributed_tracing_example.cpp.

161 {
162 distributed_tracer tracer;
163
164 // Create services
165 WebService frontend(tracer, "frontend");
166 WebService backend(tracer, "backend");
167 WebService database_service(tracer, "database_service");
168
169 std::cout << "\n=== Simulating distributed request flow ===" << std::endl;
170
171 // Simulate incoming request to frontend
172 std::map<std::string, std::string> initial_headers;
173 initial_headers["user-agent"] = "example-client";
174
175 // Process request through frontend
176 frontend.handle_request("req-001", initial_headers);
177
178 std::cout << "\n=== Simulating request with existing trace ===" << std::endl;
179
180 // Simulate request with existing trace context (e.g., from another service)
181 std::map<std::string, std::string> traced_headers;
182 traced_headers["traceparent"] = "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01";
183 traced_headers["baggage-user-id"] = "user456";
184
185 backend.handle_request("req-002", traced_headers);
186}

References WebService::handle_request().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function: