@@ -140,3 +140,145 @@ const fn severity_of_level(level: &Level) -> Severity {
140
140
Level :: ERROR => Severity :: Error ,
141
141
}
142
142
}
143
+
144
+ #[ cfg( test) ]
145
+ mod tests {
146
+ use crate :: layer;
147
+ use opentelemetry:: logs:: Severity ;
148
+ use opentelemetry:: trace:: TracerProvider as _;
149
+ use opentelemetry:: trace:: { TraceContextExt , TraceFlags , Tracer } ;
150
+ use opentelemetry:: { logs:: AnyValue , Key } ;
151
+ use opentelemetry_sdk:: logs:: LoggerProvider ;
152
+ use opentelemetry_sdk:: testing:: logs:: InMemoryLogsExporter ;
153
+ use opentelemetry_sdk:: trace:: { config, Sampler , TracerProvider } ;
154
+ use tracing:: error;
155
+ use tracing_subscriber:: layer:: SubscriberExt ;
156
+
157
+ // cargo test --features=testing
158
+ #[ test]
159
+ fn tracing_appender_standalone ( ) {
160
+ // Arrange
161
+ let exporter: InMemoryLogsExporter = InMemoryLogsExporter :: default ( ) ;
162
+ let logger_provider = LoggerProvider :: builder ( )
163
+ . with_simple_exporter ( exporter. clone ( ) )
164
+ . build ( ) ;
165
+
166
+ let layer = layer:: OpenTelemetryTracingBridge :: new ( & logger_provider) ;
167
+ let subscriber = tracing_subscriber:: registry ( ) . with ( layer) ;
168
+
169
+ // avoiding setting tracing subscriber as global as that does not
170
+ // play well with unit tests.
171
+ let _guard = tracing:: subscriber:: set_default ( subscriber) ;
172
+
173
+ // Act
174
+ error ! ( name
: "my-event-name" , target
: "my-system" , event_id =
20 , user_name =
"otel" , user_email =
"[email protected] " ) ;
175
+ logger_provider. force_flush ( ) ;
176
+
177
+ // Assert TODO: move to helper methods
178
+ let exported_logs = exporter
179
+ . get_emitted_logs ( )
180
+ . expect ( "Logs are expected to be exported." ) ;
181
+ assert_eq ! ( exported_logs. len( ) , 1 ) ;
182
+ let log = exported_logs
183
+ . get ( 0 )
184
+ . expect ( "Atleast one log is expected to be present." ) ;
185
+
186
+ // Validate common fields
187
+ assert_eq ! ( log. instrumentation. name, "opentelemetry-appender-tracing" ) ;
188
+ assert_eq ! ( log. record. severity_number, Some ( Severity :: Error ) ) ;
189
+
190
+ // Validate trace context is none.
191
+ assert ! ( log. record. trace_context. is_none( ) ) ;
192
+
193
+ // Validate attributes
194
+ let attributes: Vec < ( Key , AnyValue ) > = log
195
+ . record
196
+ . attributes
197
+ . clone ( )
198
+ . expect ( "Attributes are expected" ) ;
199
+ assert_eq ! ( attributes. len( ) , 4 ) ;
200
+ assert ! ( attributes. contains( & ( Key :: new( "name" ) , "my-event-name" . into( ) ) ) ) ;
201
+ assert ! ( attributes. contains( & ( Key :: new( "event_id" ) , 20 . into( ) ) ) ) ;
202
+ assert ! ( attributes. contains( & ( Key :: new( "user_name" ) , "otel" . into( ) ) ) ) ;
203
+ assert ! ( attributes
. contains
( & ( Key :: new
( "user_email" ) , "[email protected] " . into
( ) ) ) ) ;
204
+ }
205
+
206
+ #[ test]
207
+ fn tracing_appender_inside_tracing_context ( ) {
208
+ // Arrange
209
+ let exporter: InMemoryLogsExporter = InMemoryLogsExporter :: default ( ) ;
210
+ let logger_provider = LoggerProvider :: builder ( )
211
+ . with_simple_exporter ( exporter. clone ( ) )
212
+ . build ( ) ;
213
+
214
+ let layer = layer:: OpenTelemetryTracingBridge :: new ( & logger_provider) ;
215
+ let subscriber = tracing_subscriber:: registry ( ) . with ( layer) ;
216
+
217
+ // avoiding setting tracing subscriber as global as that does not
218
+ // play well with unit tests.
219
+ let _guard = tracing:: subscriber:: set_default ( subscriber) ;
220
+
221
+ // setup tracing as well.
222
+ let tracer_provider = TracerProvider :: builder ( )
223
+ . with_config ( config ( ) . with_sampler ( Sampler :: AlwaysOn ) )
224
+ . build ( ) ;
225
+ let tracer = tracer_provider. tracer ( "test-tracer" ) ;
226
+
227
+ // Act
228
+ let ( trace_id_expected, span_id_expected) = tracer. in_span ( "test-span" , |cx| {
229
+ let trace_id = cx. span ( ) . span_context ( ) . trace_id ( ) ;
230
+ let span_id = cx. span ( ) . span_context ( ) . span_id ( ) ;
231
+
232
+ // logging is done inside span context.
233
+ error ! ( name
: "my-event-name" , target
: "my-system" , event_id =
20 , user_name =
"otel" , user_email =
"[email protected] " ) ;
234
+ ( trace_id, span_id)
235
+ } ) ;
236
+
237
+ logger_provider. force_flush ( ) ;
238
+
239
+ // Assert TODO: move to helper methods
240
+ let exported_logs = exporter
241
+ . get_emitted_logs ( )
242
+ . expect ( "Logs are expected to be exported." ) ;
243
+ assert_eq ! ( exported_logs. len( ) , 1 ) ;
244
+ let log = exported_logs
245
+ . get ( 0 )
246
+ . expect ( "Atleast one log is expected to be present." ) ;
247
+
248
+ // validate common fields.
249
+ assert_eq ! ( log. instrumentation. name, "opentelemetry-appender-tracing" ) ;
250
+ assert_eq ! ( log. record. severity_number, Some ( Severity :: Error ) ) ;
251
+
252
+ // validate trace context.
253
+ assert ! ( log. record. trace_context. is_some( ) ) ;
254
+ assert_eq ! (
255
+ log. record. trace_context. as_ref( ) . unwrap( ) . trace_id,
256
+ trace_id_expected
257
+ ) ;
258
+ assert_eq ! (
259
+ log. record. trace_context. as_ref( ) . unwrap( ) . span_id,
260
+ span_id_expected
261
+ ) ;
262
+ assert_eq ! (
263
+ log. record
264
+ . trace_context
265
+ . as_ref( )
266
+ . unwrap( )
267
+ . trace_flags
268
+ . unwrap( ) ,
269
+ TraceFlags :: SAMPLED
270
+ ) ;
271
+
272
+ // validate attributes.
273
+ let attributes: Vec < ( Key , AnyValue ) > = log
274
+ . record
275
+ . attributes
276
+ . clone ( )
277
+ . expect ( "Attributes are expected" ) ;
278
+ assert_eq ! ( attributes. len( ) , 4 ) ;
279
+ assert ! ( attributes. contains( & ( Key :: new( "name" ) , "my-event-name" . into( ) ) ) ) ;
280
+ assert ! ( attributes. contains( & ( Key :: new( "event_id" ) , 20 . into( ) ) ) ) ;
281
+ assert ! ( attributes. contains( & ( Key :: new( "user_name" ) , "otel" . into( ) ) ) ) ;
282
+ assert ! ( attributes
. contains
( & ( Key :: new
( "user_email" ) , "[email protected] " . into
( ) ) ) ) ;
283
+ }
284
+ }
0 commit comments