Skip to content

Commit f581c21

Browse files
feat(appender-tracing): add builder support for custom instrumentation scope (close #3415)
1 parent 4a3aa77 commit f581c21

2 files changed

Lines changed: 69 additions & 8 deletions

File tree

opentelemetry-appender-tracing/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## vNext
44

5+
- Add `OpenTelemetryTracingBridgeBuilder::with_scope()` to configure the
6+
OpenTelemetry `InstrumentationScope` used by the appender logger.
7+
[3415](https://github.com/open-telemetry/opentelemetry-rust/issues/3415)
8+
59
- New *experimental* feature to enrich log records with attributes from active
610
tracing spans (`experimental_span_attributes`). Use
711
`OpenTelemetryTracingBridge::builder()` with `with_span_attribute_allowlist`

opentelemetry-appender-tracing/src/layer.rs

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use opentelemetry::{
22
logs::{AnyValue, LogRecord, Logger, LoggerProvider, Severity},
3-
Key,
3+
InstrumentationScope, Key,
44
};
55
#[cfg(feature = "experimental_span_attributes")]
66
use 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>
345346
where
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>
356358
where
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

Comments
 (0)