6#include <gtest/gtest.h>
27 std::vector<trace_span> spans;
35 root_span.
start_time = std::chrono::system_clock::now();
37 root_span.
tags[
"http.method"] =
"GET";
38 root_span.
tags[
"http.url"] =
"/api/users";
39 root_span.
tags[
"span.kind"] =
"server";
40 spans.push_back(root_span);
51 child_span.
tags[
"db.statement"] =
"SELECT * FROM users WHERE id = ?";
52 child_span.
tags[
"db.type"] =
"postgresql";
53 child_span.
tags[
"span.kind"] =
"client";
54 spans.push_back(child_span);
66 valid_config.
endpoint =
"http://jaeger:14268/api/traces";
67 valid_config.
format = trace_export_format::jaeger_thrift;
68 valid_config.
timeout = std::chrono::milliseconds(5000);
72 auto validation = valid_config.
validate();
73 EXPECT_TRUE(validation.is_ok());
78 auto endpoint_validation = invalid_endpoint.
validate();
79 EXPECT_TRUE(endpoint_validation.is_err());
80 EXPECT_EQ(endpoint_validation.error().code,
static_cast<int>(monitoring_error_code::invalid_configuration));
84 invalid_timeout.
endpoint =
"http://test";
85 invalid_timeout.
timeout = std::chrono::milliseconds(0);
86 auto timeout_validation = invalid_timeout.
validate();
87 EXPECT_TRUE(timeout_validation.is_err());
91 invalid_batch.
endpoint =
"http://test";
93 auto batch_validation = invalid_batch.
validate();
94 EXPECT_TRUE(batch_validation.is_err());
98 invalid_queue.
endpoint =
"http://test";
101 auto queue_validation = invalid_queue.
validate();
102 EXPECT_TRUE(queue_validation.is_err());
107 config.
endpoint =
"http://jaeger:14268/api/traces";
108 config.
format = trace_export_format::jaeger_thrift;
113 const auto& span = test_spans_[0];
116 EXPECT_EQ(jaeger_span.trace_id, span.trace_id);
117 EXPECT_EQ(jaeger_span.span_id, span.span_id);
118 EXPECT_EQ(jaeger_span.operation_name, span.operation_name);
119 EXPECT_EQ(jaeger_span.service_name,
"test_service");
122 bool found_http_method =
false;
123 bool found_http_url =
false;
124 for (
const auto& [key, value] : jaeger_span.tags) {
125 if (key ==
"http.method" && value ==
"GET") {
126 found_http_method =
true;
128 if (key ==
"http.url" && value ==
"/api/users") {
129 found_http_url =
true;
132 EXPECT_TRUE(found_http_method);
133 EXPECT_TRUE(found_http_url);
136 bool found_service_name =
false;
137 for (
const auto& [key, value] : jaeger_span.process_tags) {
138 if (key ==
"service.name" && value ==
"test_service") {
139 found_service_name =
true;
142 EXPECT_TRUE(found_service_name);
147 config.
endpoint =
"http://jaeger:14268/api/traces";
148 config.
format = trace_export_format::jaeger_thrift;
153 auto export_result = exporter.
export_spans(test_spans_);
154 EXPECT_TRUE(export_result.is_err());
158 EXPECT_EQ(stats[
"failed_exports"], 1);
161 auto flush_result = exporter.
flush();
162 EXPECT_TRUE(flush_result.is_ok());
164 auto shutdown_result = exporter.
shutdown();
165 EXPECT_TRUE(shutdown_result.is_ok());
170 config.
endpoint =
"http://zipkin:9411/api/v2/spans";
171 config.
format = trace_export_format::zipkin_json;
176 const auto& span = test_spans_[0];
179 EXPECT_EQ(zipkin_span.trace_id, span.trace_id);
180 EXPECT_EQ(zipkin_span.span_id, span.span_id);
181 EXPECT_EQ(zipkin_span.name, span.operation_name);
182 EXPECT_EQ(zipkin_span.local_endpoint_service_name,
"test_service");
183 EXPECT_EQ(zipkin_span.kind,
"server");
186 EXPECT_EQ(zipkin_span.tags.count(
"span.kind"), 0);
187 EXPECT_EQ(zipkin_span.tags.count(
"http.method"), 1);
188 EXPECT_EQ(zipkin_span.tags[
"http.method"],
"GET");
193 config.
endpoint =
"http://zipkin:9411/api/v2/spans";
194 config.
format = trace_export_format::zipkin_json;
199 auto export_result = exporter.
export_spans(test_spans_);
200 EXPECT_TRUE(export_result.is_err());
204 EXPECT_EQ(stats[
"failed_exports"], 1);
207 auto flush_result = exporter.
flush();
208 EXPECT_TRUE(flush_result.is_ok());
210 auto shutdown_result = exporter.
shutdown();
211 EXPECT_TRUE(shutdown_result.is_ok());
216 config.
endpoint =
"http://otlp-collector:4317";
217 config.
format = trace_export_format::otlp_grpc;
222 auto export_result = exporter.
export_spans(test_spans_);
223 EXPECT_TRUE(export_result.is_ok());
227 EXPECT_EQ(stats[
"exported_spans"], test_spans_.size());
228 EXPECT_EQ(stats[
"failed_exports"], 0);
231 auto flush_result = exporter.
flush();
232 EXPECT_TRUE(flush_result.is_ok());
234 auto shutdown_result = exporter.
shutdown();
235 EXPECT_TRUE(shutdown_result.is_ok());
241 jaeger_config.
endpoint =
"http://jaeger:14268";
242 jaeger_config.
format = trace_export_format::jaeger_grpc;
249 zipkin_config.
endpoint =
"http://zipkin:9411";
250 zipkin_config.
format = trace_export_format::zipkin_json;
257 otlp_config.
endpoint =
"http://otlp-collector:4317";
258 otlp_config.
format = trace_export_format::otlp_grpc;
266 EXPECT_EQ(jaeger_formats.size(), 2);
267 EXPECT_TRUE(std::find(jaeger_formats.begin(), jaeger_formats.end(),
268 trace_export_format::jaeger_thrift) != jaeger_formats.end());
269 EXPECT_TRUE(std::find(jaeger_formats.begin(), jaeger_formats.end(),
270 trace_export_format::jaeger_grpc) != jaeger_formats.end());
273 EXPECT_EQ(zipkin_formats.size(), 2);
274 EXPECT_TRUE(std::find(zipkin_formats.begin(), zipkin_formats.end(),
275 trace_export_format::zipkin_json) != zipkin_formats.end());
276 EXPECT_TRUE(std::find(zipkin_formats.begin(), zipkin_formats.end(),
277 trace_export_format::zipkin_protobuf) != zipkin_formats.end());
280 EXPECT_EQ(otlp_formats.size(), 3);
281 EXPECT_TRUE(std::find(otlp_formats.begin(), otlp_formats.end(),
282 trace_export_format::otlp_grpc) != otlp_formats.end());
285 EXPECT_EQ(unknown_formats.size(), 0);
291 trace_export_format::jaeger_thrift);
296 trace_export_format::zipkin_protobuf);
301 trace_export_format::otlp_http_json);
307 invalid_jaeger_config.
endpoint =
"http://jaeger:14268";
308 invalid_jaeger_config.
format = trace_export_format::zipkin_json;
311 auto jaeger_result = jaeger_exp.
export_spans(test_spans_);
312 EXPECT_TRUE(jaeger_result.is_err());
313 EXPECT_EQ(jaeger_result.error().code,
static_cast<int>(monitoring_error_code::invalid_configuration));
316 invalid_zipkin_config.
endpoint =
"http://zipkin:9411";
317 invalid_zipkin_config.
format = trace_export_format::jaeger_grpc;
320 auto zipkin_result = zipkin_exp.
export_spans(test_spans_);
321 EXPECT_TRUE(zipkin_result.is_err());
322 EXPECT_EQ(zipkin_result.error().code,
static_cast<int>(monitoring_error_code::invalid_configuration));
325 invalid_otlp_config.
endpoint =
"http://otlp:4317";
326 invalid_otlp_config.
format = trace_export_format::jaeger_thrift;
330 EXPECT_TRUE(otlp_result.is_err());
331 EXPECT_EQ(otlp_result.error().code,
static_cast<int>(monitoring_error_code::invalid_configuration));
335 std::vector<trace_span> empty_spans;
338 config.
endpoint =
"http://test:1234";
339 config.
format = trace_export_format::jaeger_grpc;
346 EXPECT_EQ(stats[
"exported_spans"], 0);
351 std::vector<trace_span> large_batch;
352 for (
int i = 0; i < 1000; ++i) {
354 span.
trace_id =
"trace" + std::to_string(i);
355 span.
span_id =
"span" + std::to_string(i);
358 span.
start_time = std::chrono::system_clock::now();
360 large_batch.push_back(span);
364 config.
endpoint =
"http://test:1234";
365 config.
format = trace_export_format::otlp_grpc;
370 EXPECT_TRUE(result.is_ok());
373 EXPECT_EQ(stats[
"exported_spans"],
static_cast<std::size_t
>(1000));
392 valid_config.
endpoint =
"localhost:4317";
393 valid_config.
timeout = std::chrono::milliseconds(5000);
396 auto validation = valid_config.
validate();
397 EXPECT_TRUE(validation.is_ok());
402 auto endpoint_validation = invalid_endpoint.
validate();
403 EXPECT_TRUE(endpoint_validation.is_err());
407 invalid_timeout.
endpoint =
"localhost:4317";
408 invalid_timeout.
timeout = std::chrono::milliseconds(0);
409 auto timeout_validation = invalid_timeout.
validate();
410 EXPECT_TRUE(timeout_validation.is_err());
414 invalid_batch.
endpoint =
"localhost:4317";
416 auto batch_validation = invalid_batch.
validate();
417 EXPECT_TRUE(batch_validation.is_err());
426 {{
"environment",
"test"}});
429 EXPECT_GT(payload.size(), 0u);
433 EXPECT_EQ(payload[0], 0x0A);
437 std::vector<trace_span> empty_spans;
446 EXPECT_GT(payload.size(), 0u);
457 auto* stub_ptr = stub_transport.get();
462 auto start_result = exporter.
start();
463 EXPECT_TRUE(start_result.is_ok());
467 auto export_result = exporter.
export_spans(test_spans_);
468 EXPECT_TRUE(export_result.is_ok());
472 EXPECT_EQ(stats[
"exported_spans"], test_spans_.size());
473 EXPECT_EQ(stats[
"dropped_spans"], 0u);
474 EXPECT_EQ(stats[
"failed_exports"], 0u);
477 auto transport_stats = stub_ptr->get_statistics();
478 EXPECT_EQ(transport_stats.requests_sent, 1u);
479 EXPECT_GT(transport_stats.bytes_sent, 0u);
482 auto shutdown_result = exporter.
shutdown();
483 EXPECT_TRUE(shutdown_result.is_ok());
493 stub_transport->set_simulate_success(
false);
498 auto start_result = exporter.
start();
499 EXPECT_TRUE(start_result.is_err());
512 stub_transport->set_response_handler([&call_count](
const grpc_request&) {
515 if (call_count < 3) {
529 auto start_result = exporter.
start();
530 EXPECT_TRUE(start_result.is_ok());
532 auto export_result = exporter.
export_spans(test_spans_);
533 EXPECT_TRUE(export_result.is_ok());
536 EXPECT_EQ(call_count, 3);
539 EXPECT_EQ(stats[
"retries"], 2u);
540 EXPECT_EQ(stats[
"exported_spans"], test_spans_.size());
549 stub_transport->set_response_handler([](
const grpc_request&) {
551 std::this_thread::sleep_for(std::chrono::microseconds(100));
559 auto start_result = exporter.
start();
560 EXPECT_TRUE(start_result.is_ok());
563 for (
int i = 0; i < 3; ++i) {
565 EXPECT_TRUE(result.is_ok());
569 EXPECT_EQ(detailed_stats.spans_exported, test_spans_.size() * 3);
570 EXPECT_EQ(detailed_stats.spans_dropped, 0u);
571 EXPECT_EQ(detailed_stats.export_failures, 0u);
572 EXPECT_GT(detailed_stats.total_export_time.count(), 0);
578 EXPECT_TRUE(exporter1 !=
nullptr);
579 EXPECT_EQ(exporter1->config().endpoint,
"localhost:4317");
583 EXPECT_TRUE(exporter2 !=
nullptr);
584 EXPECT_EQ(exporter2->config().endpoint,
"collector:4317");
588 config.
endpoint =
"otlp.example.com:443";
593 EXPECT_TRUE(exporter3 !=
nullptr);
594 EXPECT_EQ(exporter3->config().endpoint,
"otlp.example.com:443");
595 EXPECT_TRUE(exporter3->config().use_tls);
596 EXPECT_EQ(exporter3->config().service_name,
"my_service");
606 auto start_result = exporter.
start();
607 EXPECT_TRUE(start_result.is_ok());
610 std::vector<trace_span> empty_spans;
611 auto export_result = exporter.
export_spans(empty_spans);
612 EXPECT_TRUE(export_result.is_ok());
615 EXPECT_EQ(stats[
"exported_spans"], 0u);
otel_resource otel_resource_
std::vector< trace_span > create_test_spans()
std::vector< trace_span > test_spans_
Jaeger trace exporter implementation.
std::unordered_map< std::string, std::size_t > get_stats() const override
Get exporter statistics.
common::VoidResult flush() override
Flush any pending spans.
jaeger_span_data convert_span(const trace_span &span) const
Convert internal span to Jaeger format.
common::VoidResult shutdown() override
Shutdown the exporter.
common::VoidResult export_spans(const std::vector< trace_span > &spans) override
Export a batch of spans.
OpenTelemetry Protocol (OTLP) trace exporter implementation.
common::VoidResult shutdown() override
Shutdown the exporter.
common::VoidResult flush() override
Flush any pending spans.
common::VoidResult export_spans(const std::vector< trace_span > &spans) override
Export a batch of spans.
std::unordered_map< std::string, std::size_t > get_stats() const override
Get exporter statistics.
OTLP gRPC trace exporter.
common::VoidResult shutdown() override
Shutdown the exporter.
otlp_exporter_stats get_detailed_stats() const
Get detailed statistics.
common::VoidResult start()
Start the exporter.
bool is_running() const
Check if exporter is running.
std::unordered_map< std::string, std::size_t > get_stats() const override
Get exporter statistics.
common::VoidResult export_spans(const std::vector< trace_span > &spans) override
Export a batch of spans.
static std::vector< uint8_t > convert_to_otlp(const std::vector< trace_span > &spans, const std::string &service_name, const std::string &service_version, const std::unordered_map< std::string, std::string > &resource_attributes)
Convert spans to OTLP protobuf format.
static std::vector< trace_export_format > get_supported_formats(const std::string &backend)
Get supported formats for a specific backend.
static std::unique_ptr< trace_exporter_interface > create_exporter(const trace_export_config &config, const otel_resource &resource=create_service_resource("monitoring_system", "2.0.0"))
Create a trace exporter based on format.
Zipkin trace exporter implementation.
common::VoidResult export_spans(const std::vector< trace_span > &spans) override
Export a batch of spans.
std::unordered_map< std::string, std::size_t > get_stats() const override
Get exporter statistics.
common::VoidResult shutdown() override
Shutdown the exporter.
common::VoidResult flush() override
Flush any pending spans.
zipkin_span_data convert_span(const trace_span &span) const
Convert internal span to Zipkin format.
std::unique_ptr< stub_grpc_transport > create_stub_grpc_transport()
Create stub gRPC transport for testing.
std::unique_ptr< zipkin_exporter > create_zipkin_exporter(const std::string &endpoint, trace_export_format format=trace_export_format::zipkin_json)
Helper function to create a Zipkin exporter.
std::unique_ptr< otlp_grpc_exporter > create_otlp_grpc_exporter(const std::string &endpoint="localhost:4317")
Create OTLP gRPC exporter with default configuration.
otel_resource create_service_resource(const std::string &service_name, const std::string &service_version="1.0.0", const std::string &service_namespace="")
Create OpenTelemetry resource with service information.
std::unique_ptr< otlp_exporter > create_otlp_exporter(const std::string &endpoint, const otel_resource &resource, trace_export_format format=trace_export_format::otlp_grpc)
Helper function to create an OTLP exporter.
std::unique_ptr< jaeger_exporter > create_jaeger_exporter(const std::string &endpoint, trace_export_format format=trace_export_format::jaeger_grpc)
Helper function to create a Jaeger exporter.
OpenTelemetry compatibility layer for monitoring system integration.
OTLP gRPC trace exporter implementation.
gRPC request configuration
std::string status_message
OpenTelemetry resource representation.
Configuration for OTLP gRPC exporter.
std::string service_version
Service version.
std::string endpoint
OTLP receiver endpoint.
std::size_t max_retry_attempts
Maximum retry attempts.
std::string service_name
Service name.
common::VoidResult validate() const
Validate configuration.
std::size_t max_batch_size
Maximum spans per batch.
std::chrono::milliseconds initial_backoff
Initial retry backoff.
std::chrono::milliseconds timeout
Request timeout.
Configuration for trace exporters.
std::chrono::milliseconds timeout
Request timeout.
std::string endpoint
Endpoint URL.
trace_export_format format
std::size_t max_queue_size
Maximum queued spans.
std::optional< std::string > service_name
Override service name.
common::VoidResult validate() const
Validate export configuration.
std::size_t max_batch_size
Maximum spans per batch.
Trace span representing a unit of work in distributed tracing.
std::string parent_span_id
std::unordered_map< std::string, std::string > tags
std::chrono::system_clock::time_point end_time
std::string operation_name
std::chrono::system_clock::time_point start_time
TEST_F(TraceExportersTest, TraceExportConfigValidation)
Trace data exporters for various distributed tracing systems.