22
33use anyhow:: Result ;
44use ctor:: dtor;
5- use integration_test_runner:: logs_asserter:: { read_logs_from_json, LogsAsserter } ;
65use integration_test_runner:: test_utils;
76use opentelemetry_otlp:: LogExporter ;
87use opentelemetry_sdk:: logs:: LoggerProvider ;
98use opentelemetry_sdk:: { logs as sdklogs, Resource } ;
109use std:: fs:: File ;
11- use std:: os :: unix :: fs :: MetadataExt ;
10+ use std:: io :: Read ;
1211
13- fn init_logs ( ) -> Result < sdklogs:: LoggerProvider > {
12+ fn init_logs ( is_simple : bool ) -> Result < sdklogs:: LoggerProvider > {
1413 let exporter_builder = LogExporter :: builder ( ) ;
1514 #[ cfg( feature = "tonic-client" ) ]
1615 let exporter_builder = exporter_builder. with_tonic ( ) ;
@@ -24,24 +23,43 @@ fn init_logs() -> Result<sdklogs::LoggerProvider> {
2423
2524 let exporter = exporter_builder. build ( ) ?;
2625
27- Ok ( LoggerProvider :: builder ( )
28- . with_batch_exporter ( exporter)
26+ let mut logger_provider_builder = LoggerProvider :: builder ( ) ;
27+ if is_simple {
28+ logger_provider_builder = logger_provider_builder. with_simple_exporter ( exporter)
29+ } else {
30+ logger_provider_builder = logger_provider_builder. with_batch_exporter ( exporter)
31+ } ;
32+
33+ let logger_provider = logger_provider_builder
2934 . with_resource (
3035 Resource :: builder_empty ( )
3136 . with_service_name ( "logs-integration-test" )
3237 . build ( ) ,
3338 )
34- . build ( ) )
39+ . build ( ) ;
40+
41+ Ok ( logger_provider)
3542}
3643
3744#[ cfg( test) ]
3845mod logtests {
46+ // TODO: The tests in this mod works like below: Emit a log with a UUID,
47+ // then read the logs from the file and check if the UUID is present in the
48+ // logs. This makes it easy to validate with a single collector and its
49+ // output. This is a very simple test but good enough to validate that OTLP
50+ // Exporter did work! A more comprehensive test would be to validate the
51+ // entire Payload. The infra for it already exists (logs_asserter.rs), the
52+ // TODO here is to write a test that validates the entire payload.
53+
3954 use super :: * ;
4055 use integration_test_runner:: logs_asserter:: { read_logs_from_json, LogsAsserter } ;
56+ use integration_test_runner:: test_utils;
57+ use opentelemetry_appender_tracing:: layer;
4158 use opentelemetry_appender_tracing:: layer:: OpenTelemetryTracingBridge ;
4259 use std:: { fs:: File , time:: Duration } ;
4360 use tracing:: info;
4461 use tracing_subscriber:: layer:: SubscriberExt ;
62+ use uuid:: Uuid ;
4563
4664 #[ test]
4765 #[ should_panic( expected = "assertion `left == right` failed: body does not match" ) ]
@@ -68,41 +86,91 @@ mod logtests {
6886 }
6987
7088 #[ 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
89+ #[ cfg( any ( feature = "tonic-client" , feature = "reqwest-blocking -client") ) ]
90+ pub async fn logs_batch_tokio_multi_thread ( ) -> Result < ( ) > {
91+ logs_batch_tokio_helper ( ) . await
92+ }
7593
76- use integration_test_runner:: test_utils;
77- use opentelemetry_appender_tracing:: layer;
78- use tracing:: info;
79- use tracing_subscriber:: layer:: SubscriberExt ;
94+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
95+ #[ cfg( any( feature = "tonic-client" , feature = "reqwest-blocking-client" ) ) ]
96+ pub async fn logs_batch_tokio_multi_with_one_worker ( ) -> Result < ( ) > {
97+ logs_batch_tokio_helper ( ) . await
98+ }
8099
100+ #[ tokio:: test( flavor = "current_thread" ) ]
101+ #[ cfg( any( feature = "tonic-client" , feature = "reqwest-blocking-client" ) ) ]
102+ pub async fn logs_batch_tokio_current ( ) -> Result < ( ) > {
103+ logs_batch_tokio_helper ( ) . await
104+ }
105+
106+ async fn logs_batch_tokio_helper ( ) -> Result < ( ) > {
81107 use crate :: { assert_logs_results, init_logs} ;
82108 test_utils:: start_collector_container ( ) . await ?;
83109
84- let logger_provider = init_logs ( ) . unwrap ( ) ;
85- let layer = layer :: OpenTelemetryTracingBridge :: new ( & logger_provider) ;
110+ let logger_provider = init_logs ( false ) . unwrap ( ) ;
111+ let layer = OpenTelemetryTracingBridge :: new ( & logger_provider) ;
86112 let subscriber = tracing_subscriber:: registry ( ) . with ( layer) ;
113+ // generate a random uuid and store it to expected guid
114+ let expected_uuid = Uuid :: new_v4 ( ) . to_string ( ) ;
87115 {
88116 let _guard = tracing:: subscriber:: set_default ( subscriber) ;
89- info ! ( target: "my-target" , "hello from {}. My price is {}." , "banana" , 2.99 ) ;
117+ info ! ( target: "my-target" , uuid = expected_uuid , "hello from {}. My price is {}." , "banana" , 2.99 ) ;
90118 }
91- // TODO: remove below wait before calling logger_provider.shutdown()
92- // tokio::time::sleep(Duration::from_secs(10)).await;
119+
93120 let _ = logger_provider. shutdown ( ) ;
121+ tokio:: time:: sleep ( Duration :: from_secs ( 5 ) ) . await ;
122+ assert_logs_results ( test_utils:: LOGS_FILE , expected_uuid. as_str ( ) ) ?;
123+ Ok ( ( ) )
124+ }
94125
95- tokio:: time:: sleep ( Duration :: from_secs ( 10 ) ) . await ;
126+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 4 ) ]
127+ #[ cfg( any( feature = "tonic-client" , feature = "reqwest-client" ) ) ]
128+ pub async fn logs_simple_tokio_multi_thread ( ) -> Result < ( ) > {
129+ logs_simple_tokio_helper ( ) . await
130+ }
131+
132+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
133+ #[ cfg( any( feature = "tonic-client" , feature = "reqwest-client" ) ) ]
134+ pub async fn logs_simple_tokio_multi_with_one_worker ( ) -> Result < ( ) > {
135+ logs_simple_tokio_helper ( ) . await
136+ }
137+
138+ // Ignored, to be investigated
139+ #[ ignore]
140+ #[ tokio:: test( flavor = "current_thread" ) ]
141+ #[ cfg( any( feature = "tonic-client" , feature = "reqwest-client" ) ) ]
142+ pub async fn logs_simple_tokio_current ( ) -> Result < ( ) > {
143+ logs_simple_tokio_helper ( ) . await
144+ }
145+
146+ async fn logs_simple_tokio_helper ( ) -> Result < ( ) > {
147+ use crate :: { assert_logs_results, init_logs} ;
148+ test_utils:: start_collector_container ( ) . await ?;
96149
97- assert_logs_results ( test_utils:: LOGS_FILE , "expected/logs.json" ) ?;
150+ let logger_provider = init_logs ( true ) . unwrap ( ) ;
151+ let layer = OpenTelemetryTracingBridge :: new ( & logger_provider) ;
152+ let subscriber = tracing_subscriber:: registry ( ) . with ( layer) ;
153+ info ! ( "Tracing initialized" ) ;
154+ // generate a random uuid and store it to expected guid
155+ let expected_uuid = Uuid :: new_v4 ( ) . to_string ( ) ;
156+ {
157+ let _guard = tracing:: subscriber:: set_default ( subscriber) ;
158+ info ! ( target: "my-target" , uuid = expected_uuid, "hello from {}. My price is {}." , "banana" , 2.99 ) ;
159+ }
98160
161+ let _ = logger_provider. shutdown ( ) ;
162+ tokio:: time:: sleep ( Duration :: from_secs ( 5 ) ) . await ;
163+ assert_logs_results ( test_utils:: LOGS_FILE , expected_uuid. as_str ( ) ) ?;
99164 Ok ( ( ) )
100165 }
101166
102- #[ ignore = "TODO: [Fix Me] Failing on CI. Needs to be investigated and resolved." ]
103167 #[ test]
104168 #[ cfg( any( feature = "tonic-client" , feature = "reqwest-blocking-client" ) ) ]
105169 pub fn logs_batch_non_tokio_main ( ) -> Result < ( ) > {
170+ logs_batch_non_tokio_helper ( )
171+ }
172+
173+ fn logs_batch_non_tokio_helper ( ) -> Result < ( ) > {
106174 // Initialize the logger provider inside a tokio runtime
107175 // as this allows tonic client to capture the runtime,
108176 // but actual export occurs from the dedicated std::thread
@@ -111,31 +179,61 @@ mod logtests {
111179 let logger_provider = rt. block_on ( async {
112180 // While we're here setup our collector container too, as this needs tokio to run
113181 test_utils:: start_collector_container ( ) . await ?;
114- init_logs ( )
182+ init_logs ( false )
115183 } ) ?;
116-
117- info ! ( "LoggerProvider created" ) ;
118- let layer = OpenTelemetryTracingBridge :: new ( & logger_provider) ;
184+ let layer = layer:: OpenTelemetryTracingBridge :: new ( & logger_provider) ;
119185 let subscriber = tracing_subscriber:: registry ( ) . with ( layer) ;
186+ // generate a random uuid and store it to expected guid
187+ let expected_uuid = Uuid :: new_v4 ( ) . to_string ( ) ;
120188 {
121189 let _guard = tracing:: subscriber:: set_default ( subscriber) ;
122- info ! ( target: "my-target" , "hello from {}. My price is {}." , "banana" , 2.99 ) ;
190+ info ! ( target: "my-target" , uuid = expected_uuid , "hello from {}. My price is {}." , "banana" , 2.99 ) ;
123191 }
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" ) ?;
127192
193+ let _ = logger_provider. shutdown ( ) ;
194+ std:: thread:: sleep ( Duration :: from_secs ( 5 ) ) ;
195+ assert_logs_results ( test_utils:: LOGS_FILE , expected_uuid. as_str ( ) ) ?;
128196 Ok ( ( ) )
129197 }
130- }
131198
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) ?) ?;
199+ #[ test]
200+ #[ cfg( any( feature = "tonic-client" , feature = "reqwest-blocking-client" ) ) ]
201+ pub fn logs_simple_non_tokio_main ( ) -> Result < ( ) > {
202+ logs_simple_non_tokio_helper ( )
203+ }
135204
136- LogsAsserter :: new ( left, right) . assert ( ) ;
205+ fn logs_simple_non_tokio_helper ( ) -> Result < ( ) > {
206+ // Initialize the logger provider inside a tokio runtime
207+ // as this allows tonic client to capture the runtime,
208+ // but actual export occurs from the main non-tokio thread.
209+ let rt = tokio:: runtime:: Runtime :: new ( ) ?;
210+ let logger_provider = rt. block_on ( async {
211+ // While we're here setup our collector container too, as this needs tokio to run
212+ test_utils:: start_collector_container ( ) . await ?;
213+ init_logs ( true )
214+ } ) ?;
215+ let layer = layer:: OpenTelemetryTracingBridge :: new ( & logger_provider) ;
216+ let subscriber = tracing_subscriber:: registry ( ) . with ( layer) ;
217+ // generate a random uuid and store it to expected guid
218+ let expected_uuid = Uuid :: new_v4 ( ) . to_string ( ) ;
219+ {
220+ let _guard = tracing:: subscriber:: set_default ( subscriber) ;
221+ info ! ( target: "my-target" , uuid = expected_uuid, "hello from {}. My price is {}." , "banana" , 2.99 ) ;
222+ }
223+
224+ let _ = logger_provider. shutdown ( ) ;
225+ std:: thread:: sleep ( Duration :: from_secs ( 5 ) ) ;
226+ assert_logs_results ( test_utils:: LOGS_FILE , expected_uuid. as_str ( ) ) ?;
227+ Ok ( ( ) )
228+ }
229+ }
137230
138- assert ! ( File :: open( result) . unwrap( ) . metadata( ) . unwrap( ) . size( ) > 0 ) ;
231+ pub fn assert_logs_results ( result : & str , expected_content : & str ) -> Result < ( ) > {
232+ let file = File :: open ( result) ?;
233+ let mut contents = String :: new ( ) ;
234+ let mut reader = std:: io:: BufReader :: new ( & file) ;
235+ reader. read_to_string ( & mut contents) ?;
236+ assert ! ( contents. contains( expected_content) ) ;
139237 Ok ( ( ) )
140238}
141239
0 commit comments