opentelemetry_sdk/logs/
logger.rs1#[cfg(feature = "trace")]
2use super::TraceContext;
3use super::{SdkLogRecord, SdkLoggerProvider};
4#[cfg(feature = "trace")]
5use opentelemetry::trace::TraceContextExt;
6use opentelemetry::{Context, InstrumentationScope};
7
8use opentelemetry::logs::Severity;
9use opentelemetry::time::now;
10
11#[derive(Debug, Clone)]
12pub struct SdkLogger {
16 scope: InstrumentationScope,
17 provider: SdkLoggerProvider,
18
19 #[cfg(feature = "experimental_metrics_bound_instruments")]
24 log_created_counter: opentelemetry::metrics::BoundCounter<u64>,
25}
26
27impl SdkLogger {
28 pub(crate) fn new(scope: InstrumentationScope, provider: SdkLoggerProvider) -> Self {
29 #[cfg(feature = "experimental_metrics_bound_instruments")]
30 let log_created_counter = opentelemetry::global::meter("otel.sdk")
31 .u64_counter("otel.sdk.log.created")
32 .with_description("The number of log records submitted to the SDK.")
33 .with_unit("{log_record}")
34 .build()
35 .bind(&[]);
36 SdkLogger {
37 scope,
38 provider,
39 #[cfg(feature = "experimental_metrics_bound_instruments")]
40 log_created_counter,
41 }
42 }
43}
44
45impl opentelemetry::logs::Logger for SdkLogger {
46 type LogRecord = SdkLogRecord;
47
48 fn create_log_record(&self) -> Self::LogRecord {
49 SdkLogRecord::new()
50 }
51
52 fn emit(&self, mut record: Self::LogRecord) {
54 if Context::is_current_telemetry_suppressed() {
60 return;
61 }
62
63 #[cfg(feature = "experimental_metrics_bound_instruments")]
67 self.log_created_counter.add(1);
68
69 let provider = &self.provider;
70 let processors = provider.log_processors();
71
72 if record.trace_context.is_none() {
74 #[cfg(feature = "trace")]
75 Context::map_current(|cx| {
76 cx.has_active_span().then(|| {
77 record.trace_context = Some(TraceContext::from(cx.span().span_context()))
78 })
79 });
80 }
81 if record.observed_timestamp.is_none() {
82 record.observed_timestamp = Some(now());
83 }
84
85 for p in processors {
86 p.emit(&mut record, &self.scope);
87 }
88 }
89
90 #[inline]
91 fn event_enabled(&self, level: Severity, target: &str, name: Option<&str>) -> bool {
92 if Context::is_current_telemetry_suppressed() {
93 return false;
94 }
95 self.provider
98 .log_processors()
99 .iter()
100 .any(|processor| processor.event_enabled(level, target, name))
101 }
102}
103
104#[cfg(all(test, feature = "experimental_metrics_bound_instruments"))]
105mod self_obs {
106 use crate::logs::SdkLoggerProvider;
107 use crate::metrics::data::{AggregatedMetrics, MetricData};
108 use crate::metrics::{InMemoryMetricExporter, SdkMeterProvider};
109 use opentelemetry::logs::{Logger, LoggerProvider};
110
111 fn sum_log_created(exporter: &InMemoryMetricExporter) -> u64 {
112 let metrics = exporter.get_finished_metrics().unwrap();
113 let mut total = 0u64;
114 for rm in &metrics {
115 for sm in &rm.scope_metrics {
116 for metric in &sm.metrics {
117 if metric.name == "otel.sdk.log.created" {
118 if let AggregatedMetrics::U64(MetricData::Sum(sum)) = &metric.data {
119 for dp in sum.data_points() {
120 total += dp.value();
121 }
122 }
123 }
124 }
125 }
126 }
127 total
128 }
129
130 #[test]
138 #[ignore]
139 fn log_created_counts_intake_without_processors() {
140 let metric_exporter = InMemoryMetricExporter::default();
141 let meter_provider = SdkMeterProvider::builder()
142 .with_periodic_exporter(metric_exporter.clone())
143 .build();
144 opentelemetry::global::set_meter_provider(meter_provider.clone());
145
146 let logger_provider = SdkLoggerProvider::builder().build();
148 let logger = logger_provider.logger("test");
149
150 for _ in 0..10 {
151 logger.emit(logger.create_log_record());
152 }
153
154 meter_provider.force_flush().unwrap();
155
156 assert_eq!(
157 sum_log_created(&metric_exporter),
158 10,
159 "expected 10 records counted at intake regardless of processors"
160 );
161
162 meter_provider.shutdown().unwrap();
163 }
164}