Skip to content

Commit 27410b0

Browse files
authored
Integration test for non tokio main (#2520)
1 parent c51c4b2 commit 27410b0

File tree

6 files changed

+93
-43
lines changed

6 files changed

+93
-43
lines changed

.cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"shoppingcart",
6565
"struct",
6666
"Tescher",
67+
"testcontainers",
6768
"testresults",
6869
"thiserror",
6970
"tracerprovider",

opentelemetry-otlp/tests/integration_test/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ testcontainers = { version = "0.23.1", features = ["http_wait"]}
1414
once_cell.workspace = true
1515
anyhow = "1.0.94"
1616
ctor = "0.2.9"
17+
uuid = { version = "1.3", features = ["v4"] }
1718
tracing-subscriber = { workspace = true, features = ["env-filter","registry", "std", "fmt"] }
1819
tracing = {workspace = true}
1920

opentelemetry-otlp/tests/integration_test/src/test_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ fn init_tracing() {
5252
// Initialize the tracing subscriber with the OpenTelemetry layer and the
5353
// Fmt layer.
5454
tracing_subscriber::registry().with(fmt_layer).init();
55-
otel_info!(name: "tracing initializing completed!");
55+
otel_info!(name: "tracing::fmt initializing completed! SDK internal logs will be printed to stdout.");
5656
});
5757
}
5858

opentelemetry-otlp/tests/integration_test/tests/logs.rs

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
use anyhow::Result;
44
use ctor::dtor;
5-
use integration_test_runner::logs_asserter::{read_logs_from_json, LogsAsserter};
65
use integration_test_runner::test_utils;
76
use opentelemetry_otlp::LogExporter;
87
use opentelemetry_sdk::logs::LoggerProvider;
98
use opentelemetry_sdk::{logs as sdklogs, Resource};
109
use std::fs::File;
11-
use std::os::unix::fs::MetadataExt;
10+
use std::io::Read;
1211

1312
fn init_logs() -> Result<sdklogs::LoggerProvider> {
1413
let exporter_builder = LogExporter::builder();
@@ -36,12 +35,23 @@ fn init_logs() -> Result<sdklogs::LoggerProvider> {
3635

3736
#[cfg(test)]
3837
mod logtests {
38+
// TODO: The tests in this mod works like below: Emit a log with a UUID,
39+
// then read the logs from the file and check if the UUID is present in the
40+
// logs. This makes it easy to validate with a single collector and its
41+
// output. This is a very simple test but good enough to validate that OTLP
42+
// Exporter did work! A more comprehensive test would be to validate the
43+
// entire Payload. The infra for it already exists (logs_asserter.rs), the
44+
// TODO here is to write a test that validates the entire payload.
45+
3946
use super::*;
4047
use integration_test_runner::logs_asserter::{read_logs_from_json, LogsAsserter};
48+
use integration_test_runner::test_utils;
49+
use opentelemetry_appender_tracing::layer;
4150
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
4251
use std::{fs::File, time::Duration};
4352
use tracing::info;
4453
use tracing_subscriber::layer::SubscriberExt;
54+
use uuid::Uuid;
4555

4656
#[test]
4757
#[should_panic(expected = "assertion `left == right` failed: body does not match")]
@@ -68,41 +78,50 @@ mod logtests {
6878
}
6979

7080
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
71-
#[cfg(not(feature = "hyper-client"))]
72-
#[cfg(not(feature = "reqwest-client"))]
73-
pub async fn test_logs() -> Result<()> {
74-
// Make sure the container is running
81+
#[cfg(any(feature = "tonic-client", feature = "reqwest-blocking-client"))]
82+
pub async fn logs_batch_tokio_multi_thread() -> Result<()> {
83+
logs_batch_tokio_helper().await
84+
}
85+
86+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
87+
#[cfg(any(feature = "tonic-client", feature = "reqwest-blocking-client"))]
88+
pub async fn logs_batch_tokio_multi_with_one_worker() -> Result<()> {
89+
logs_batch_tokio_helper().await
90+
}
7591

76-
use integration_test_runner::test_utils;
77-
use opentelemetry_appender_tracing::layer;
78-
use tracing::info;
79-
use tracing_subscriber::layer::SubscriberExt;
92+
#[tokio::test(flavor = "current_thread")]
93+
#[cfg(any(feature = "tonic-client", feature = "reqwest-blocking-client"))]
94+
pub async fn logs_batch_tokio_current() -> Result<()> {
95+
logs_batch_tokio_helper().await
96+
}
8097

98+
async fn logs_batch_tokio_helper() -> Result<()> {
8199
use crate::{assert_logs_results, init_logs};
82100
test_utils::start_collector_container().await?;
83101

84102
let logger_provider = init_logs().unwrap();
85-
let layer = layer::OpenTelemetryTracingBridge::new(&logger_provider);
103+
let layer = OpenTelemetryTracingBridge::new(&logger_provider);
86104
let subscriber = tracing_subscriber::registry().with(layer);
105+
// generate a random uuid and store it to expected guid
106+
let expected_uuid = Uuid::new_v4().to_string();
87107
{
88108
let _guard = tracing::subscriber::set_default(subscriber);
89-
info!(target: "my-target", "hello from {}. My price is {}.", "banana", 2.99);
109+
info!(target: "my-target", uuid = expected_uuid, "hello from {}. My price is {}.", "banana", 2.99);
90110
}
91-
// TODO: remove below wait before calling logger_provider.shutdown()
92-
// tokio::time::sleep(Duration::from_secs(10)).await;
93-
let _ = logger_provider.shutdown();
94-
95-
tokio::time::sleep(Duration::from_secs(10)).await;
96-
97-
assert_logs_results(test_utils::LOGS_FILE, "expected/logs.json")?;
98111

112+
let _ = logger_provider.shutdown();
113+
tokio::time::sleep(Duration::from_secs(5)).await;
114+
assert_logs_results(test_utils::LOGS_FILE, expected_uuid.as_str())?;
99115
Ok(())
100116
}
101117

102-
#[ignore = "TODO: [Fix Me] Failing on CI. Needs to be investigated and resolved."]
103118
#[test]
104119
#[cfg(any(feature = "tonic-client", feature = "reqwest-blocking-client"))]
105120
pub fn logs_batch_non_tokio_main() -> Result<()> {
121+
logs_batch_non_tokio_helper()
122+
}
123+
124+
fn logs_batch_non_tokio_helper() -> Result<()> {
106125
// Initialize the logger provider inside a tokio runtime
107126
// as this allows tonic client to capture the runtime,
108127
// but actual export occurs from the dedicated std::thread
@@ -113,29 +132,28 @@ mod logtests {
113132
test_utils::start_collector_container().await?;
114133
init_logs()
115134
})?;
116-
117-
info!("LoggerProvider created");
118-
let layer = OpenTelemetryTracingBridge::new(&logger_provider);
135+
let layer = layer::OpenTelemetryTracingBridge::new(&logger_provider);
119136
let subscriber = tracing_subscriber::registry().with(layer);
137+
// generate a random uuid and store it to expected guid
138+
let expected_uuid = Uuid::new_v4().to_string();
120139
{
121140
let _guard = tracing::subscriber::set_default(subscriber);
122-
info!(target: "my-target", "hello from {}. My price is {}.", "banana", 2.99);
141+
info!(target: "my-target", uuid = expected_uuid, "hello from {}. My price is {}.", "banana", 2.99);
123142
}
124-
let _ = logger_provider.shutdown();
125-
// tokio::time::sleep(Duration::from_secs(10)).await;
126-
assert_logs_results(test_utils::LOGS_FILE, "expected/logs.json")?;
127143

144+
let _ = logger_provider.shutdown();
145+
std::thread::sleep(Duration::from_secs(5));
146+
assert_logs_results(test_utils::LOGS_FILE, expected_uuid.as_str())?;
128147
Ok(())
129148
}
130149
}
131150

132-
pub fn assert_logs_results(result: &str, expected: &str) -> Result<()> {
133-
let left = read_logs_from_json(File::open(expected)?)?;
134-
let right = read_logs_from_json(File::open(result)?)?;
135-
136-
LogsAsserter::new(left, right).assert();
137-
138-
assert!(File::open(result).unwrap().metadata().unwrap().size() > 0);
151+
pub fn assert_logs_results(result: &str, expected_content: &str) -> Result<()> {
152+
let file = File::open(result)?;
153+
let mut contents = String::new();
154+
let mut reader = std::io::BufReader::new(&file);
155+
reader.read_to_string(&mut contents)?;
156+
assert!(contents.contains(expected_content));
139157
Ok(())
140158
}
141159

opentelemetry-otlp/tests/integration_test/tests/metrics.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ pub fn validate_metrics_against_results(scope_name: &str) -> Result<()> {
191191
#[cfg(test)]
192192
#[cfg(not(feature = "hyper-client"))]
193193
#[cfg(not(feature = "reqwest-client"))]
194-
mod tests {
194+
mod metrictests {
195195

196196
use super::*;
197197
use opentelemetry::metrics::MeterProvider;
@@ -246,7 +246,6 @@ mod tests {
246246
}
247247

248248
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
249-
// #[ignore] // skip when running unit test
250249
async fn test_histogram() -> Result<()> {
251250
_ = setup_metrics_test().await;
252251
const METER_NAME: &str = "test_histogram_meter";
@@ -263,7 +262,6 @@ mod tests {
263262
}
264263

265264
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
266-
// #[ignore] // skip when running unit test
267265
async fn test_up_down_counter() -> Result<()> {
268266
_ = setup_metrics_test().await;
269267
const METER_NAME: &str = "test_up_down_meter";

opentelemetry-sdk/CHANGELOG.md

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@
5858
**`experimental_metrics_periodicreader_with_async_runtime`**.
5959

6060
Migration Guide:
61-
62-
1. *Default Implementation, requires no async runtime* (**Recommended**) The
61+
1. *Default Implementation, requires no async runtime* (**Recommended**) The
6362
new default implementation does not require a runtime argument. Replace the
6463
builder method accordingly:
6564
- *Before:*
@@ -71,18 +70,28 @@
7170
let reader = opentelemetry_sdk::metrics::PeriodicReader::builder(exporter).build();
7271
```
7372

73+
The new PeriodicReader can be used with OTLP Exporter, and supports
74+
following exporter features:
75+
- `grpc-tonic`: This requires `MeterProvider` to be created within a tokio
76+
runtime.
77+
- `reqwest-blocking-client`: Works with a regular `main` or `tokio::main`.
78+
79+
In other words, other clients like `reqwest` and `hyper` are not supported.
80+
7481
2. *Async Runtime Support*
7582
If your application cannot spin up new threads or you prefer using async
7683
runtimes, enable the
7784
"experimental_metrics_periodicreader_with_async_runtime" feature flag and
7885
adjust code as below.
7986

8087
- *Before:*
88+
8189
```rust
8290
let reader = opentelemetry_sdk::metrics::PeriodicReader::builder(exporter, runtime::Tokio).build();
8391
```
8492

8593
- *After:*
94+
8695
```rust
8796
let reader = opentelemetry_sdk::metrics::periodic_reader_with_async_runtime::PeriodicReader::builder(exporter, runtime::Tokio).build();
8897
```
@@ -107,8 +116,7 @@
107116
- Upgrade the tracing crate used for internal logging to version 0.1.40 or later. This is necessary because the internal logging macros utilize the name field as
108117
metadata, a feature introduced in version 0.1.40. [#2418](https://github.com/open-telemetry/opentelemetry-rust/pull/2418)
109118

110-
- **Breaking** [#2436](https://github.com/open-telemetry/opentelemetry-rust/pull/2436)
111-
119+
- *Breaking* - `BatchLogProcessor` Updates [#2436](https://github.com/open-telemetry/opentelemetry-rust/pull/2436)
112120
`BatchLogProcessor` no longer requires an async runtime by default. Instead, a dedicated
113121
background thread is created to do the batch processing and exporting.
114122

@@ -120,33 +128,45 @@ metadata, a feature introduced in version 0.1.40. [#2418](https://github.com/ope
120128
new default implementation does not require a runtime argument. Replace the
121129
builder method accordingly:
122130
- *Before:*
131+
123132
```rust
124133
let logger_provider = LoggerProvider::builder()
125134
.with_log_processor(BatchLogProcessor::builder(exporter, runtime::Tokio).build())
126135
.build();
127136
```
128137

129138
- *After:*
139+
130140
```rust
131141
let logger_provider = LoggerProvider::builder()
132142
.with_log_processor(BatchLogProcessor::builder(exporter).build())
133143
.build();
134144
```
135145

146+
The new BatchLogProcessor can be used with OTLP Exporter, and supports
147+
following exporter features:
148+
- `grpc-tonic`: This requires `MeterProvider` to be created within a tokio
149+
runtime.
150+
- `reqwest-blocking-client`: Works with a regular `main` or `tokio::main`.
151+
152+
In other words, other clients like `reqwest` and `hyper` are not supported.
153+
136154
2. *Async Runtime Support*
137155
If your application cannot spin up new threads or you prefer using async
138156
runtimes, enable the
139157
"experimental_logs_batch_log_processor_with_async_runtime" feature flag and
140158
adjust code as below.
141159

142160
- *Before:*
161+
143162
```rust
144163
let logger_provider = LoggerProvider::builder()
145164
.with_log_processor(BatchLogProcessor::builder(exporter, runtime::Tokio).build())
146165
.build();
147166
```
148167

149168
- *After:*
169+
150170
```rust
151171
let logger_provider = LoggerProvider::builder()
152172
.with_log_processor(log_processor_with_async_runtime::BatchLogProcessor::builder(exporter, runtime::Tokio).build())
@@ -159,7 +179,7 @@ metadata, a feature introduced in version 0.1.40. [#2418](https://github.com/ope
159179
- Continue enabling one of the async runtime feature flags: `rt-tokio`,
160180
`rt-tokio-current-thread`, or `rt-async-std`.
161181

162-
- **Breaking** [#2456](https://github.com/open-telemetry/opentelemetry-rust/pull/2456)
182+
- *Breaking* - `BatchSpanProcessor` Updates [#2435](https://github.com/open-telemetry/opentelemetry-rust/pull/2456)
163183

164184
`BatchSpanProcessor` no longer requires an async runtime by default. Instead, a dedicated
165185
background thread is created to do the batch processing and exporting.
@@ -172,33 +192,45 @@ metadata, a feature introduced in version 0.1.40. [#2418](https://github.com/ope
172192
new default implementation does not require a runtime argument. Replace the
173193
builder method accordingly:
174194
- *Before:*
195+
175196
```rust
176197
let tracer_provider = TracerProvider::builder()
177198
.with_span_processor(BatchSpanProcessor::builder(exporter, runtime::Tokio).build())
178199
.build();
179200
```
180201

181202
- *After:*
203+
182204
```rust
183205
let tracer_provider = TracerProvider::builder()
184206
.with_span_processor(BatchSpanProcessor::builder(exporter).build())
185207
.build();
186208
```
187209

210+
The new BatchLogProcessor can be used with OTLP Exporter, and supports
211+
following exporter features:
212+
- `grpc-tonic`: This requires `MeterProvider` to be created within a tokio
213+
runtime.
214+
- `reqwest-blocking-client`: Works with a regular `main` or `tokio::main`.
215+
216+
In other words, other clients like `reqwest` and `hyper` are not supported.
217+
188218
2. *Async Runtime Support*
189219
If your application cannot spin up new threads or you prefer using async
190220
runtimes, enable the
191221
"experimental_trace_batch_span_processor_with_async_runtime" feature flag and
192222
adjust code as below.
193223

194224
- *Before:*
225+
195226
```rust
196227
let tracer_provider = TracerProvider::builder()
197228
.with_span_processor(BatchSpanProcessor::builder(exporter, runtime::Tokio).build())
198229
.build();
199230
```
200231

201232
- *After:*
233+
202234
```rust
203235
let tracer_provider = TracerProvider::builder()
204236
.with_span_processor(span_processor_with_async_runtime::BatchSpanProcessor::builder(exporter, runtime::Tokio).build())

0 commit comments

Comments
 (0)