Skip to main content

mock_collector/
lib.rs

1//! A mock OpenTelemetry OTLP collector server for testing.
2//!
3//! This library provides a mock collector that can receive OTLP logs, traces, and metrics over gRPC, HTTP/JSON, or HTTP/Protobuf,
4//! and provides a fluent assertion API for verifying the received telemetry data in tests.
5//!
6//! # Features
7//!
8//! - **Multiple Signal Support**: Logs, Traces, and Metrics
9//! - **Single Collector**: One collector handles all signals - test logs, traces, and metrics together
10//! - **Multiple Protocol Support**: gRPC, HTTP/Protobuf, and HTTP/JSON
11//! - **Fluent Assertion API**: Easy-to-use builder pattern for test assertions
12//! - **Async Waiting**: Wait for telemetry to arrive with timeout support
13//! - **Severity Level Assertions**: Assert on log severity levels (Debug, Info, Warn, Error, Fatal)
14//! - **Count-Based Assertions**: Assert exact counts, minimums, or maximums
15//! - **Negative Assertions**: Verify logs/spans/metrics don't exist
16//! - **Async-Ready**: Built with Tokio for async/await compatibility
17//! - **Graceful Shutdown**: Proper resource cleanup
18//!
19//! # Quick Start
20//!
21//! ```no_run
22//! use mock_collector::{MockServer, Protocol};
23//!
24//! #[tokio::main]
25//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
26//!     // Start a server (supports logs, traces, and metrics)
27//!     let server = MockServer::builder().start().await?;
28//!
29//!     // Your application exports logs, traces, and metrics here...
30//!
31//!     // Assert on collected data
32//!     server.with_collector(|collector| {
33//!         // Logs
34//!         collector
35//!             .expect_log_with_body("Application started")
36//!             .with_resource_attributes([("service.name", "my-service")])
37//!             .assert_exists();
38//!
39//!         // Logs with severity
40//!         use mock_collector::SeverityNumber;
41//!         collector
42//!             .expect_log()
43//!             .with_severity(SeverityNumber::Error)
44//!             .assert_not_exists();
45//!
46//!         // Traces
47//!         collector
48//!             .expect_span_with_name("Initialize")
49//!             .with_resource_attributes([("service.name", "my-service")])
50//!             .assert_exists();
51//!
52//!         // Metrics
53//!         collector
54//!             .expect_metric_with_name("requests_total")
55//!             .with_resource_attributes([("service.name", "my-service")])
56//!             .assert_exists();
57//!     }).await;
58//!
59//!     // Graceful shutdown
60//!     server.shutdown().await?;
61//!     Ok(())
62//! }
63//! ```
64//!
65//! # Async Waiting
66//!
67//! When testing async telemetry pipelines, signals often arrive asynchronously after the
68//! operation that generates them completes. The library provides waiting methods to handle
69//! this pattern:
70//!
71//! ```no_run
72//! use mock_collector::MockServer;
73//! use std::time::Duration;
74//!
75//! # #[tokio::main]
76//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
77//! let server = MockServer::builder().start().await?;
78//!
79//! // Trigger async telemetry export...
80//!
81//! // Wait for telemetry to arrive before asserting
82//! server.wait_for_spans(1, Duration::from_secs(5)).await?;
83//! server.wait_for_logs(2, Duration::from_secs(5)).await?;
84//! server.wait_for_metrics(3, Duration::from_secs(5)).await?;
85//!
86//! // Or use a custom predicate for complex conditions
87//! server.wait_until(
88//!     |c| c.expect_span_with_name("http.request")
89//!         .with_attributes([("http.status_code", 200)])
90//!         .count() >= 1,
91//!     Duration::from_secs(5),
92//! ).await?;
93//!
94//! // Now safe to run assertions
95//! server.with_collector(|collector| {
96//!     collector.expect_span_with_name("http.request").assert_exists();
97//! }).await;
98//! # Ok(())
99//! # }
100//! ```
101//!
102//! # Assertion API
103//!
104//! The library provides assertion methods for logs, traces, and metrics:
105//!
106//! ## Log Assertions
107//!
108//! - [`LogAssertion::assert_exists`]: Assert at least one log matches
109//! - [`LogAssertion::assert_not_exists`]: Assert no logs match
110//! - [`LogAssertion::assert_count`]: Assert exact number of matches
111//! - [`LogAssertion::assert_at_least`]: Assert minimum matches
112//! - [`LogAssertion::assert_at_most`]: Assert maximum matches
113//!
114//! ## Trace Assertions
115//!
116//! - [`SpanAssertion::assert_exists`]: Assert at least one span matches
117//! - [`SpanAssertion::assert_not_exists`]: Assert no spans match
118//! - [`SpanAssertion::assert_count`]: Assert exact number of matches
119//! - [`SpanAssertion::assert_at_least`]: Assert minimum matches
120//! - [`SpanAssertion::assert_at_most`]: Assert maximum matches
121//!
122//! ## Metric Assertions
123//!
124//! - [`MetricAssertion::assert_exists`]: Assert at least one metric matches
125//! - [`MetricAssertion::assert_not_exists`]: Assert no metrics match
126//! - [`MetricAssertion::assert_count`]: Assert exact number of matches
127//! - [`MetricAssertion::assert_at_least`]: Assert minimum matches
128//! - [`MetricAssertion::assert_at_most`]: Assert maximum matches
129//!
130//! ## Histogram, ExponentialHistogram, and Summary Assertions
131//!
132//! For type-specific metric assertions, use the dedicated builders:
133//!
134//! - [`HistogramAssertion`]: Assert on histogram count, sum, min, max, and bucket counts
135//! - [`ExponentialHistogramAssertion`]: Assert on exponential histogram with zero_count and scale
136//! - [`SummaryAssertion`]: Assert on summary count, sum, and quantile values
137//!
138//! ```no_run
139//! # use mock_collector::MockCollector;
140//! # let collector = MockCollector::new();
141//! // Histogram with value assertions
142//! collector
143//!     .expect_histogram("http_request_duration")
144//!     .with_count_gte(100)
145//!     .with_sum_gte(5000.0)
146//!     .assert_exists();
147//!
148//! // Summary with quantile assertions
149//! collector
150//!     .expect_summary("response_time")
151//!     .with_quantile_lte(0.99, 500.0)  // p99 <= 500ms
152//!     .assert_exists();
153//! ```
154//!
155//! ## Waiting Methods
156//!
157//! - [`ServerHandle::wait_until`]: Wait for a custom predicate to return true
158//! - [`ServerHandle::wait_for_spans`]: Wait for at least N spans to arrive
159//! - [`ServerHandle::wait_for_logs`]: Wait for at least N logs to arrive
160//! - [`ServerHandle::wait_for_metrics`]: Wait for at least N metrics to arrive
161//!
162//! # Examples
163//!
164//! See the [examples directory](https://github.com/djvcom/mock-collector/tree/main/examples)
165//! for complete working examples.
166
167mod collector;
168mod error;
169mod server;
170
171pub use collector::{
172    ExponentialHistogramAssertion, HistogramAssertion, LogAssertion, MetricAssertion,
173    MockCollector, SpanAssertion, SummaryAssertion, TestLogRecord, TestMetric, TestSpan,
174};
175pub use error::MockServerError;
176pub use opentelemetry_otlp::Protocol;
177pub use opentelemetry_proto::tonic::logs::v1::SeverityNumber;
178pub use server::{MockServer, MockServerBuilder, ServerHandle};