11use opentelemetry:: {
22 logs:: { AnyValue , LogRecord , Logger , LoggerProvider , Severity } ,
3- Key ,
3+ InstrumentationScope , Key ,
44} ;
55#[ cfg( feature = "experimental_span_attributes" ) ]
66use std:: borrow:: Cow ;
@@ -326,33 +326,35 @@ where
326326 Self :: builder ( provider) . build ( )
327327 }
328328
329- pub fn builder ( provider : & P ) -> OpenTelemetryTracingBridgeBuilder < P , L > {
329+ pub fn builder < ' a > ( provider : & ' a P ) -> OpenTelemetryTracingBridgeBuilder < ' a , P , L > {
330330 OpenTelemetryTracingBridgeBuilder {
331331 // Using empty scope name.
332332 // The name/version of this library itself can be added
333333 // as a Scope attribute, once a semantic convention is
334334 // defined for the same.
335335 // See https://github.com/open-telemetry/semantic-conventions/issues/1550
336- logger : provider. logger ( "" ) ,
336+ provider,
337+ scope : None ,
337338 _phantom : Default :: default ( ) ,
338339 #[ cfg( feature = "experimental_span_attributes" ) ]
339340 span_attribute_allowlist : None ,
340341 }
341342 }
342343}
343344
344- pub struct OpenTelemetryTracingBridgeBuilder < P , L >
345+ pub struct OpenTelemetryTracingBridgeBuilder < ' a , P , L >
345346where
346347 P : LoggerProvider < Logger = L > + Send + Sync ,
347348 L : Logger + Send + Sync ,
348349{
349- logger : L ,
350+ provider : & ' a P ,
351+ scope : Option < InstrumentationScope > ,
350352 _phantom : std:: marker:: PhantomData < P > ,
351353 #[ cfg( feature = "experimental_span_attributes" ) ]
352354 span_attribute_allowlist : Option < HashSet < Cow < ' static , str > > > ,
353355}
354356
355- impl < P , L > OpenTelemetryTracingBridgeBuilder < P , L >
357+ impl < ' a , P , L > OpenTelemetryTracingBridgeBuilder < ' a , P , L >
356358where
357359 P : LoggerProvider < Logger = L > + Send + Sync ,
358360 L : Logger + Send + Sync ,
@@ -368,9 +370,21 @@ where
368370 self
369371 }
370372
373+ /// Configures the OpenTelemetry `InstrumentationScope` used to create the
374+ /// logger for this bridge.
375+ ///
376+ /// When not set, the bridge preserves the existing behavior and creates a
377+ /// logger with an empty scope name.
378+ pub fn with_scope ( mut self , scope : InstrumentationScope ) -> Self {
379+ self . scope = Some ( scope) ;
380+ self
381+ }
382+
371383 pub fn build ( self ) -> OpenTelemetryTracingBridge < P , L > {
372384 OpenTelemetryTracingBridge {
373- logger : self . logger ,
385+ logger : self . scope . map ( |scope|
386+ self . provider . logger_with_scope ( scope)
387+ ) . unwrap_or_else ( ||self . provider . logger ( "" ) ) ,
374388 _phantom : self . _phantom ,
375389 #[ cfg( feature = "experimental_span_attributes" ) ]
376390 // Treat empty allowlist as not set - disable the feature flag instead.
@@ -509,7 +523,7 @@ mod tests {
509523 use opentelemetry:: trace:: TracerProvider ;
510524 use opentelemetry:: trace:: { TraceContextExt , TraceFlags , Tracer } ;
511525 use opentelemetry:: InstrumentationScope ;
512- use opentelemetry:: { logs:: AnyValue , Key } ;
526+ use opentelemetry:: { logs:: AnyValue , Key , KeyValue } ;
513527 use opentelemetry_sdk:: error:: { OTelSdkError , OTelSdkResult } ;
514528 use opentelemetry_sdk:: logs:: { InMemoryLogExporter , LogProcessor } ;
515529 use opentelemetry_sdk:: logs:: { SdkLogRecord , SdkLoggerProvider } ;
@@ -831,6 +845,49 @@ mod tests {
831845 }
832846 }
833847
848+ #[ test]
849+ fn tracing_appender_with_custom_scope ( ) {
850+ let exporter: InMemoryLogExporter = InMemoryLogExporter :: default ( ) ;
851+ let logger_provider = SdkLoggerProvider :: builder ( )
852+ . with_simple_exporter ( exporter. clone ( ) )
853+ . build ( ) ;
854+
855+ let scope = InstrumentationScope :: builder ( "test.scope" )
856+ . with_version ( "1.2.3" )
857+ . with_schema_url ( "https://opentelemetry.io/schemas/1.0.0" )
858+ . with_attributes ( [ KeyValue :: new ( "scope-key" , "scope-value" ) ] )
859+ . build ( ) ;
860+
861+ let subscriber = tracing_subscriber:: registry ( ) . with (
862+ layer:: OpenTelemetryTracingBridge :: builder ( & logger_provider)
863+ . with_scope ( scope)
864+ . build ( ) ,
865+ ) ;
866+ let _guard = tracing:: subscriber:: set_default ( subscriber) ;
867+
868+ error ! ( name: "scoped-event" , target: "my-system" , event_id = 20 ) ;
869+ assert ! ( logger_provider. force_flush( ) . is_ok( ) ) ;
870+
871+ let exported_logs = exporter
872+ . get_emitted_logs ( )
873+ . expect ( "Logs are expected to be exported." ) ;
874+ assert_eq ! ( exported_logs. len( ) , 1 ) ;
875+ let log = exported_logs
876+ . first ( )
877+ . expect ( "At least one log is expected to be present." ) ;
878+
879+ let instrumentation_scope = & log. instrumentation ;
880+ assert_eq ! ( instrumentation_scope. name( ) , "test.scope" ) ;
881+ assert_eq ! ( instrumentation_scope. version( ) , Some ( "1.2.3" ) ) ;
882+ assert_eq ! (
883+ instrumentation_scope. schema_url( ) ,
884+ Some ( "https://opentelemetry.io/schemas/1.0.0" )
885+ ) ;
886+ assert ! ( instrumentation_scope
887+ . attributes( )
888+ . eq( [ KeyValue :: new( "scope-key" , "scope-value" ) ] . iter( ) ) ) ;
889+ }
890+
834891 #[ test]
835892 #[ ignore = "log tests set a global logger that cannot be unset and affects other tests" ]
836893 fn tracing_appender_standalone_with_tracing_log ( ) {
0 commit comments