1
- //! based on https://github.com/open-telemetry/opentelemetry-rust/blob/main/opentelemetry-otlp/tests/smoke.rs
1
+ mod common;
2
+ mod logs;
3
+ mod trace;
4
+ pub use logs:: ExportedLog ;
5
+ pub use trace:: ExportedSpan ;
6
+
7
+ use logs:: * ;
8
+ use trace:: * ;
9
+
10
+ use std:: net:: SocketAddr ;
11
+
2
12
use futures:: StreamExt ;
3
- use opentelemetry_proto:: tonic:: collector:: trace:: v1:: {
4
- trace_service_server:: { TraceService , TraceServiceServer } ,
5
- ExportTraceServiceRequest , ExportTraceServiceResponse ,
6
- } ;
7
- use serde:: Serialize ;
8
- use std:: collections:: BTreeMap ;
13
+ use opentelemetry_otlp:: WithExportConfig ;
14
+ use opentelemetry_proto:: tonic:: collector:: logs:: v1:: logs_service_server:: LogsServiceServer ;
15
+ use opentelemetry_proto:: tonic:: collector:: trace:: v1:: trace_service_server:: TraceServiceServer ;
9
16
use std:: sync:: mpsc;
10
- use std:: { net:: SocketAddr , sync:: Mutex } ;
11
17
use tokio_stream:: wrappers:: TcpListenerStream ;
12
18
use tracing:: debug;
13
19
14
- //pub type ExportedSpan = opentelemetry_proto::tonic::trace::v1::Span;
15
-
16
- /// opentelemetry_proto::tonic::trace::v1::Span is no compatible with serde::Serialize
17
- /// and to be able to test with insta,... it's needed (Debug is not enough to be able to filter unstable value,...)
18
- #[ derive( Debug , Clone , PartialEq , Eq , Serialize ) ]
19
- pub struct ExportedSpan {
20
- pub trace_id : String ,
21
- pub span_id : String ,
22
- pub trace_state : String ,
23
- pub parent_span_id : String ,
24
- pub name : String ,
25
- pub kind : String , //SpanKind,
26
- pub start_time_unix_nano : u64 ,
27
- pub end_time_unix_nano : u64 ,
28
- pub attributes : BTreeMap < String , String > ,
29
- pub dropped_attributes_count : u32 ,
30
- pub events : Vec < Event > ,
31
- pub dropped_events_count : u32 ,
32
- pub links : Vec < Link > ,
33
- pub dropped_links_count : u32 ,
34
- pub status : Option < Status > ,
35
- }
36
-
37
- impl From < opentelemetry_proto:: tonic:: trace:: v1:: Span > for ExportedSpan {
38
- fn from ( value : opentelemetry_proto:: tonic:: trace:: v1:: Span ) -> Self {
39
- Self {
40
- trace_id : hex:: encode ( & value. trace_id ) ,
41
- span_id : hex:: encode ( & value. span_id ) ,
42
- trace_state : value. trace_state . clone ( ) ,
43
- parent_span_id : hex:: encode ( & value. parent_span_id ) ,
44
- name : value. name . clone ( ) ,
45
- kind : value. kind ( ) . as_str_name ( ) . to_owned ( ) ,
46
- start_time_unix_nano : value. start_time_unix_nano ,
47
- end_time_unix_nano : value. end_time_unix_nano ,
48
- attributes : cnv_attributes ( & value. attributes ) ,
49
- dropped_attributes_count : value. dropped_attributes_count ,
50
- events : value. events . iter ( ) . map ( Event :: from) . collect ( ) ,
51
- dropped_events_count : value. dropped_events_count ,
52
- links : value. links . iter ( ) . map ( Link :: from) . collect ( ) ,
53
- dropped_links_count : value. dropped_links_count ,
54
- status : value. status . map ( Status :: from) ,
55
- }
56
- }
57
- }
58
-
59
- #[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Serialize ) ]
60
- pub struct Status {
61
- message : String ,
62
- code : String ,
63
- }
64
-
65
- impl From < opentelemetry_proto:: tonic:: trace:: v1:: Status > for Status {
66
- fn from ( value : opentelemetry_proto:: tonic:: trace:: v1:: Status ) -> Self {
67
- Self {
68
- message : value. message . clone ( ) ,
69
- code : value. code ( ) . as_str_name ( ) . to_string ( ) ,
70
- }
71
- }
72
- }
73
-
74
- #[ derive( Debug , Clone , PartialEq , Eq , Serialize ) ]
75
- pub struct Link {
76
- pub trace_id : String ,
77
- pub span_id : String ,
78
- pub trace_state : String ,
79
- pub attributes : BTreeMap < String , String > ,
80
- pub dropped_attributes_count : u32 ,
81
- }
82
-
83
- impl From < & opentelemetry_proto:: tonic:: trace:: v1:: span:: Link > for Link {
84
- fn from ( value : & opentelemetry_proto:: tonic:: trace:: v1:: span:: Link ) -> Self {
85
- Self {
86
- trace_id : hex:: encode ( & value. trace_id ) ,
87
- span_id : hex:: encode ( & value. span_id ) ,
88
- trace_state : value. trace_state . clone ( ) ,
89
- attributes : cnv_attributes ( & value. attributes ) ,
90
- dropped_attributes_count : value. dropped_attributes_count ,
91
- }
92
- }
93
- }
94
-
95
- fn cnv_attributes (
96
- attributes : & [ opentelemetry_proto:: tonic:: common:: v1:: KeyValue ] ,
97
- ) -> BTreeMap < String , String > {
98
- attributes
99
- . iter ( )
100
- . map ( |kv| ( kv. key . to_string ( ) , format ! ( "{:?}" , kv. value) ) )
101
- . collect :: < BTreeMap < String , String > > ( )
102
- // v.sort_by_key(|kv| kv.0.clone());
103
- // v
104
- }
105
-
106
- #[ derive( Debug , Clone , PartialEq , Eq , Serialize ) ]
107
- pub struct Event {
108
- time_unix_nano : u64 ,
109
- name : String ,
110
- attributes : BTreeMap < String , String > ,
111
- dropped_attributes_count : u32 ,
112
- }
113
-
114
- impl From < & opentelemetry_proto:: tonic:: trace:: v1:: span:: Event > for Event {
115
- fn from ( value : & opentelemetry_proto:: tonic:: trace:: v1:: span:: Event ) -> Self {
116
- Self {
117
- time_unix_nano : value. time_unix_nano ,
118
- name : value. name . clone ( ) ,
119
- attributes : cnv_attributes ( & value. attributes ) ,
120
- dropped_attributes_count : value. dropped_attributes_count ,
121
- }
122
- }
123
- }
124
-
125
- struct FakeTraceService {
126
- tx : Mutex < mpsc:: SyncSender < ExportedSpan > > ,
127
- }
128
-
129
- impl FakeTraceService {
130
- pub fn new ( tx : mpsc:: SyncSender < ExportedSpan > ) -> Self {
131
- Self { tx : Mutex :: new ( tx) }
132
- }
133
- }
134
-
135
- #[ tonic:: async_trait]
136
- impl TraceService for FakeTraceService {
137
- async fn export (
138
- & self ,
139
- request : tonic:: Request < ExportTraceServiceRequest > ,
140
- ) -> Result < tonic:: Response < ExportTraceServiceResponse > , tonic:: Status > {
141
- debug ! ( "Sending request into channel..." ) ;
142
- request
143
- . into_inner ( )
144
- . resource_spans
145
- . into_iter ( )
146
- . flat_map ( |rs| rs. scope_spans )
147
- . flat_map ( |ss| ss. spans )
148
- . map ( ExportedSpan :: from)
149
- . for_each ( |es| {
150
- self . tx . lock ( ) . unwrap ( ) . send ( es) . expect ( "Channel full" ) ;
151
- } ) ;
152
- Ok ( tonic:: Response :: new ( ExportTraceServiceResponse {
153
- partial_success : None ,
154
- } ) )
155
- }
156
- }
157
-
158
20
pub struct FakeCollectorServer {
159
21
address : SocketAddr ,
160
22
req_rx : mpsc:: Receiver < ExportedSpan > ,
23
+ log_rx : mpsc:: Receiver < ExportedLog > ,
161
24
handle : tokio:: task:: JoinHandle < ( ) > ,
162
25
}
163
26
@@ -174,20 +37,23 @@ impl FakeCollectorServer {
174
37
} ) ;
175
38
176
39
let ( req_tx, req_rx) = mpsc:: sync_channel :: < ExportedSpan > ( 1024 ) ;
177
- let service = TraceServiceServer :: new ( FakeTraceService :: new ( req_tx) ) ;
40
+ let ( log_tx, log_rx) = mpsc:: sync_channel :: < ExportedLog > ( 1024 ) ;
41
+ let trace_service = TraceServiceServer :: new ( FakeTraceService :: new ( req_tx) ) ;
42
+ let logs_service = LogsServiceServer :: new ( FakeLogsService :: new ( log_tx) ) ;
178
43
let handle = tokio:: task:: spawn ( async move {
179
44
debug ! ( "start FakeCollectorServer http://{addr}" ) ; //Devskim: ignore DS137138)
180
45
tonic:: transport:: Server :: builder ( )
181
- . add_service ( service)
46
+ . add_service ( trace_service)
47
+ . add_service ( logs_service)
182
48
. serve_with_incoming ( stream)
183
- // .serve(addr)
184
49
. await
185
50
. expect ( "Server failed" ) ;
186
51
debug ! ( "stop FakeCollectorServer" ) ;
187
52
} ) ;
188
53
Ok ( Self {
189
54
address : addr,
190
55
req_rx,
56
+ log_rx,
191
57
handle,
192
58
} )
193
59
}
@@ -204,13 +70,16 @@ impl FakeCollectorServer {
204
70
std:: iter:: from_fn ( || self . req_rx . try_recv ( ) . ok ( ) ) . collect :: < Vec < _ > > ( )
205
71
}
206
72
73
+ pub fn exported_logs ( & self ) -> Vec < ExportedLog > {
74
+ std:: iter:: from_fn ( || self . log_rx . try_recv ( ) . ok ( ) ) . collect :: < Vec < _ > > ( )
75
+ }
76
+
207
77
pub fn abort ( self ) {
208
78
self . handle . abort ( )
209
79
}
210
80
}
211
81
212
82
pub async fn setup_tracer ( fake_server : & FakeCollectorServer ) -> opentelemetry_sdk:: trace:: Tracer {
213
- use opentelemetry_otlp:: WithExportConfig ;
214
83
// if the environment variable is set (in test or in caller), `with_endpoint` value is ignored
215
84
std:: env:: remove_var ( "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" ) ;
216
85
opentelemetry_otlp:: new_pipeline ( )
@@ -221,14 +90,29 @@ pub async fn setup_tracer(fake_server: &FakeCollectorServer) -> opentelemetry_sd
221
90
. with_endpoint ( fake_server. endpoint ( ) ) ,
222
91
)
223
92
. install_batch ( opentelemetry_sdk:: runtime:: Tokio )
224
- . expect ( "failed to install" )
93
+ . expect ( "failed to install tracer" )
94
+ }
95
+
96
+ pub async fn setup_logger (
97
+ fake_server : & FakeCollectorServer ,
98
+ ) -> opentelemetry_sdk:: logs:: LoggerProvider {
99
+ opentelemetry_otlp:: new_pipeline ( )
100
+ . logging ( )
101
+ . with_exporter (
102
+ opentelemetry_otlp:: new_exporter ( )
103
+ . tonic ( )
104
+ . with_endpoint ( fake_server. endpoint ( ) ) ,
105
+ )
106
+ . install_simple ( ) //Install simple so we don't have to wait for batching in tests
107
+ . expect ( "failed to install logging" )
225
108
}
226
109
227
110
#[ cfg( test) ]
228
111
mod tests {
229
112
use super :: * ;
230
- //use opentelemetry::{KeyValue, Value};
113
+
231
114
use opentelemetry:: global:: shutdown_tracer_provider;
115
+ use opentelemetry:: logs:: { LogRecord , Logger , LoggerProvider , Severity } ;
232
116
use opentelemetry:: trace:: { Span , SpanKind , Tracer } ;
233
117
234
118
#[ tokio:: test( flavor = "multi_thread" ) ]
@@ -245,7 +129,6 @@ mod tests {
245
129
. start ( & tracer) ;
246
130
span. add_event ( "my-test-event" , vec ! [ ] ) ;
247
131
span. end ( ) ;
248
-
249
132
shutdown_tracer_provider ( ) ;
250
133
251
134
let otel_spans = fake_collector. exported_spans ( ) ;
@@ -272,4 +155,35 @@ mod tests {
272
155
} ) ,
273
156
} ) ;
274
157
}
158
+
159
+ #[ tokio:: test( flavor = "multi_thread" ) ]
160
+ async fn test_fake_logger_and_collector ( ) {
161
+ let fake_collector = FakeCollectorServer :: start ( )
162
+ . await
163
+ . expect ( "fake collector setup and started" ) ;
164
+
165
+ let logger_provider = setup_logger ( & fake_collector) . await ;
166
+ let logger = logger_provider. logger ( "test" ) ;
167
+ let mut record = logger. create_log_record ( ) ;
168
+ record. set_body ( "This is information" . into ( ) ) ;
169
+ record. set_severity_number ( Severity :: Info ) ;
170
+ record. set_severity_text ( "info" . into ( ) ) ;
171
+ logger. emit ( record) ;
172
+
173
+ let otel_logs = fake_collector. exported_logs ( ) ;
174
+ insta:: assert_yaml_snapshot!( otel_logs, {
175
+ "[].trace_id" => insta:: dynamic_redaction( |value, _path| {
176
+ assert2:: let_assert!( Some ( trace_id) = value. as_str( ) ) ;
177
+ format!( "[trace_id:lg{}]" , trace_id. len( ) )
178
+ } ) ,
179
+ "[].span_id" => insta:: dynamic_redaction( |value, _path| {
180
+ assert2:: let_assert!( Some ( span_id) = value. as_str( ) ) ;
181
+ format!( "[span_id:lg{}]" , span_id. len( ) )
182
+ } ) ,
183
+ "[].observed_time_unix_nano" => "[timestamp]" ,
184
+ "[].severity_number" => 9 ,
185
+ "[].severity_text" => "info" ,
186
+ "[].body" => "AnyValue { value: Some(StringValue(\" This is information\" )) }" ,
187
+ } ) ;
188
+ }
275
189
}
0 commit comments