Skip to content

Commit 5ff18ca

Browse files
authored
Merge branch 'main' into value-map-interface-change
2 parents 606d126 + 16c0e10 commit 5ff18ca

File tree

36 files changed

+625
-325
lines changed

36 files changed

+625
-325
lines changed

examples/metrics-advanced/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ publish = false
88
[dependencies]
99
opentelemetry = { path = "../../opentelemetry", features = ["metrics"] }
1010
opentelemetry_sdk = { path = "../../opentelemetry-sdk", features = ["metrics", "rt-tokio"] }
11-
opentelemetry-stdout = { path = "../../opentelemetry-stdout", features = ["metrics"]}
11+
opentelemetry-stdout = { path = "../../opentelemetry-stdout", features = ["metrics"] }
1212
tokio = { workspace = true, features = ["full"] }
1313
serde_json = { workspace = true }

examples/metrics-advanced/src/main.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use opentelemetry::global;
22
use opentelemetry::Key;
33
use opentelemetry::KeyValue;
4+
use opentelemetry_sdk::metrics::reader::DeltaTemporalitySelector;
45
use opentelemetry_sdk::metrics::{
56
Aggregation, Instrument, PeriodicReader, SdkMeterProvider, Stream,
67
};
@@ -44,7 +45,11 @@ fn init_meter_provider() -> opentelemetry_sdk::metrics::SdkMeterProvider {
4445
}
4546
};
4647

47-
let exporter = opentelemetry_stdout::MetricsExporterBuilder::default().build();
48+
// Build exporter using Delta Temporality.
49+
let exporter = opentelemetry_stdout::MetricsExporterBuilder::default()
50+
.with_temporality_selector(DeltaTemporalitySelector::new())
51+
.build();
52+
4853
let reader = PeriodicReader::builder(exporter, runtime::Tokio).build();
4954
let provider = SdkMeterProvider::builder()
5055
.with_reader(reader)

opentelemetry-appender-log/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## vNext
44

55
- Bump MSRV to 1.70 [#2179](https://github.com/open-telemetry/opentelemetry-rust/pull/2179)
6+
- [2193](https://github.com/open-telemetry/opentelemetry-rust/pull/2193) `opentelemetry-appender-log`: Output experimental code attributes
67

78
## v0.26.0
89
Released 2024-Sep-30

opentelemetry-appender-log/Cargo.toml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,26 @@ rust-version = "1.70"
1111
edition = "2021"
1212

1313
[dependencies]
14-
opentelemetry = { version = "0.26", path = "../opentelemetry", features = ["logs"]}
15-
log = { workspace = true, features = ["kv", "std"]}
14+
opentelemetry = { version = "0.26", path = "../opentelemetry", features = [
15+
"logs",
16+
] }
17+
log = { workspace = true, features = ["kv", "std"] }
1618
serde = { workspace = true, optional = true, features = ["std"] }
19+
opentelemetry-semantic-conventions = { path = "../opentelemetry-semantic-conventions", optional = true, features = [
20+
"semconv_experimental",
21+
] }
1722

1823
[features]
1924
logs_level_enabled = ["opentelemetry/logs_level_enabled"]
2025
with-serde = ["log/kv_serde", "serde"]
26+
experimental_metadata_attributes = ["dep:opentelemetry-semantic-conventions"]
2127

2228
[dev-dependencies]
23-
opentelemetry_sdk = { path = "../opentelemetry-sdk", features = [ "testing", "logs_level_enabled" ] }
24-
opentelemetry-stdout = { path = "../opentelemetry-stdout", features = ["logs"]}
29+
opentelemetry_sdk = { path = "../opentelemetry-sdk", features = [
30+
"testing",
31+
"logs_level_enabled",
32+
] }
33+
opentelemetry-stdout = { path = "../opentelemetry-stdout", features = ["logs"] }
2534
log = { workspace = true, features = ["kv_serde"] }
2635
tokio = { workspace = true }
2736
serde = { workspace = true, features = ["std", "derive"] }

opentelemetry-appender-log/src/lib.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ use opentelemetry::{
9999
logs::{AnyValue, LogRecord, Logger, LoggerProvider, Severity},
100100
Key,
101101
};
102+
#[cfg(feature = "experimental_metadata_attributes")]
103+
use opentelemetry_semantic_conventions::attribute::{CODE_FILEPATH, CODE_LINENO, CODE_NAMESPACE};
102104
use std::borrow::Cow;
103105

104106
pub struct OpenTelemetryLogBridge<P, L>
@@ -130,6 +132,28 @@ where
130132
log_record.set_severity_number(severity_of_level(record.level()));
131133
log_record.set_severity_text(record.level().as_str());
132134
log_record.set_body(AnyValue::from(record.args().to_string()));
135+
136+
#[cfg(feature = "experimental_metadata_attributes")]
137+
{
138+
if let Some(filepath) = record.file() {
139+
log_record.add_attribute(
140+
Key::new(CODE_FILEPATH),
141+
AnyValue::from(filepath.to_string()),
142+
);
143+
}
144+
145+
if let Some(line_no) = record.line() {
146+
log_record.add_attribute(Key::new(CODE_LINENO), AnyValue::from(line_no));
147+
}
148+
149+
if let Some(module) = record.module_path() {
150+
log_record.add_attribute(
151+
Key::new(CODE_NAMESPACE),
152+
AnyValue::from(module.to_string()),
153+
);
154+
}
155+
}
156+
133157
log_record.add_attributes(log_attributes(record.key_values()));
134158
log_record.set_target(record.metadata().target().to_string());
135159

@@ -1127,6 +1151,54 @@ mod tests {
11271151
}
11281152
}
11291153

1154+
#[cfg(feature = "experimental_metadata_attributes")]
1155+
#[test]
1156+
fn logbridge_code_attributes() {
1157+
use opentelemetry_semantic_conventions::attribute::{
1158+
CODE_FILEPATH, CODE_LINENO, CODE_NAMESPACE,
1159+
};
1160+
1161+
let exporter = InMemoryLogsExporter::default();
1162+
1163+
let logger_provider = LoggerProvider::builder()
1164+
.with_simple_exporter(exporter.clone())
1165+
.build();
1166+
1167+
let otel_log_appender = OpenTelemetryLogBridge::new(&logger_provider);
1168+
1169+
otel_log_appender.log(
1170+
&log::RecordBuilder::new()
1171+
.level(log::Level::Warn)
1172+
.args(format_args!("WARN"))
1173+
.file(Some("src/main.rs"))
1174+
.module_path(Some("service"))
1175+
.line(Some(101))
1176+
.build(),
1177+
);
1178+
1179+
let logs = exporter.get_emitted_logs().unwrap();
1180+
1181+
let get = |needle: &str| -> Option<AnyValue> {
1182+
logs[0].record.attributes_iter().find_map(|(k, v)| {
1183+
if k.as_str() == needle {
1184+
Some(v.clone())
1185+
} else {
1186+
None
1187+
}
1188+
})
1189+
};
1190+
1191+
assert_eq!(
1192+
Some(AnyValue::String(StringValue::from("src/main.rs"))),
1193+
get(CODE_FILEPATH)
1194+
);
1195+
assert_eq!(
1196+
Some(AnyValue::String(StringValue::from("service"))),
1197+
get(CODE_NAMESPACE)
1198+
);
1199+
assert_eq!(Some(AnyValue::Int(101)), get(CODE_LINENO));
1200+
}
1201+
11301202
#[test]
11311203
fn test_flush() {
11321204
let exporter = InMemoryLogsExporter::default();

opentelemetry-appender-tracing/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ tracing-subscriber = { workspace = true, features = ["registry", "std", "env-fil
2626
tracing-log = "0.2"
2727
async-trait = { workspace = true }
2828
criterion = { workspace = true }
29+
tokio = { workspace = true, features = ["full"]}
2930

3031
[target.'cfg(not(target_os = "windows"))'.dev-dependencies]
3132
pprof = { version = "0.13", features = ["flamegraph", "criterion"] }

opentelemetry-appender-tracing/src/layer.rs

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,17 +208,20 @@ const fn severity_of_level(level: &Level) -> Severity {
208208
#[cfg(test)]
209209
mod tests {
210210
use crate::layer;
211-
use opentelemetry::logs::Severity;
211+
use async_trait::async_trait;
212+
use opentelemetry::logs::{LogResult, Severity};
212213
use opentelemetry::trace::TracerProvider as _;
213214
use opentelemetry::trace::{TraceContextExt, TraceFlags, Tracer};
214215
use opentelemetry::{logs::AnyValue, Key};
216+
use opentelemetry_sdk::export::logs::{LogBatch, LogExporter};
215217
use opentelemetry_sdk::logs::{LogRecord, LoggerProvider};
216218
use opentelemetry_sdk::testing::logs::InMemoryLogsExporter;
217219
use opentelemetry_sdk::trace;
218220
use opentelemetry_sdk::trace::{Sampler, TracerProvider};
219-
use tracing::error;
221+
use tracing::{error, warn};
220222
use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt;
221-
use tracing_subscriber::Layer;
223+
use tracing_subscriber::util::SubscriberInitExt;
224+
use tracing_subscriber::{EnvFilter, Layer};
222225

223226
pub fn attributes_contains(log_record: &LogRecord, key: &Key, value: &AnyValue) -> bool {
224227
log_record
@@ -238,6 +241,70 @@ mod tests {
238241
}
239242

240243
// cargo test --features=testing
244+
245+
#[derive(Clone, Debug, Default)]
246+
struct ReentrantLogExporter;
247+
248+
#[async_trait]
249+
impl LogExporter for ReentrantLogExporter {
250+
async fn export(&mut self, _batch: LogBatch<'_>) -> LogResult<()> {
251+
// This will cause a deadlock as the export itself creates a log
252+
// while still within the lock of the SimpleLogProcessor.
253+
warn!(name: "my-event-name", target: "reentrant", event_id = 20, user_name = "otel", user_email = "[email protected]");
254+
Ok(())
255+
}
256+
}
257+
258+
#[test]
259+
#[ignore = "See issue: https://github.com/open-telemetry/opentelemetry-rust/issues/1745"]
260+
fn simple_processor_deadlock() {
261+
let exporter: ReentrantLogExporter = ReentrantLogExporter;
262+
let logger_provider = LoggerProvider::builder()
263+
.with_simple_exporter(exporter.clone())
264+
.build();
265+
266+
let layer = layer::OpenTelemetryTracingBridge::new(&logger_provider);
267+
268+
// Setting subscriber as global as that is the only way to test this scenario.
269+
tracing_subscriber::registry().with(layer).init();
270+
warn!(name: "my-event-name", target: "my-system", event_id = 20, user_name = "otel", user_email = "[email protected]");
271+
}
272+
273+
#[test]
274+
#[ignore = "While this test runs fine, this uses global subscriber and does not play well with other tests."]
275+
fn simple_processor_no_deadlock() {
276+
let exporter: ReentrantLogExporter = ReentrantLogExporter;
277+
let logger_provider = LoggerProvider::builder()
278+
.with_simple_exporter(exporter.clone())
279+
.build();
280+
281+
let layer = layer::OpenTelemetryTracingBridge::new(&logger_provider);
282+
283+
// This filter will prevent the deadlock as the reentrant log will be
284+
// ignored.
285+
let filter = EnvFilter::new("debug").add_directive("reentrant=error".parse().unwrap());
286+
// Setting subscriber as global as that is the only way to test this scenario.
287+
tracing_subscriber::registry()
288+
.with(filter)
289+
.with(layer)
290+
.init();
291+
warn!(name: "my-event-name", target: "my-system", event_id = 20, user_name = "otel", user_email = "[email protected]");
292+
}
293+
294+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
295+
#[ignore = "While this test runs fine, this uses global subscriber and does not play well with other tests."]
296+
async fn batch_processor_no_deadlock() {
297+
let exporter: ReentrantLogExporter = ReentrantLogExporter;
298+
let logger_provider = LoggerProvider::builder()
299+
.with_batch_exporter(exporter.clone(), opentelemetry_sdk::runtime::Tokio)
300+
.build();
301+
302+
let layer = layer::OpenTelemetryTracingBridge::new(&logger_provider);
303+
304+
tracing_subscriber::registry().with(layer).init();
305+
warn!(name: "my-event-name", target: "my-system", event_id = 20, user_name = "otel", user_email = "[email protected]");
306+
}
307+
241308
#[test]
242309
fn tracing_appender_standalone() {
243310
// Arrange

opentelemetry-otlp/src/metric.rs

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use opentelemetry_sdk::{
1414
metrics::{
1515
data::{ResourceMetrics, Temporality},
1616
exporter::PushMetricsExporter,
17-
reader::{DefaultTemporalitySelector, TemporalitySelector},
17+
reader::{DefaultTemporalitySelector, DeltaTemporalitySelector, TemporalitySelector},
1818
InstrumentKind, PeriodicReader, SdkMeterProvider,
1919
},
2020
runtime::Runtime,
@@ -169,7 +169,7 @@ where
169169
///
170170
/// [exporter-docs]: https://github.com/open-telemetry/opentelemetry-specification/blob/a1c13d59bb7d0fb086df2b3e1eaec9df9efef6cc/specification/metrics/sdk_exporters/otlp.md#additional-configuration
171171
pub fn with_delta_temporality(self) -> Self {
172-
self.with_temporality_selector(DeltaTemporalitySelector)
172+
self.with_temporality_selector(DeltaTemporalitySelector::new())
173173
}
174174
}
175175

@@ -237,35 +237,6 @@ impl<RT, EB: Debug> Debug for OtlpMetricPipeline<RT, EB> {
237237
}
238238
}
239239

240-
/// A temporality selector that returns [`Delta`][Temporality::Delta] for all
241-
/// instruments except `UpDownCounter` and `ObservableUpDownCounter`.
242-
///
243-
/// This temporality selector is equivalent to OTLP Metrics Exporter's
244-
/// `Delta` temporality preference (see [its documentation][exporter-docs]).
245-
///
246-
/// [exporter-docs]: https://github.com/open-telemetry/opentelemetry-specification/blob/a1c13d59bb7d0fb086df2b3e1eaec9df9efef6cc/specification/metrics/sdk_exporters/otlp.md#additional-configuration
247-
#[derive(Debug)]
248-
struct DeltaTemporalitySelector;
249-
250-
impl TemporalitySelector for DeltaTemporalitySelector {
251-
#[rustfmt::skip]
252-
fn temporality(&self, kind: InstrumentKind) -> Temporality {
253-
match kind {
254-
InstrumentKind::Counter
255-
| InstrumentKind::Histogram
256-
| InstrumentKind::ObservableCounter
257-
| InstrumentKind::Gauge
258-
| InstrumentKind::ObservableGauge => {
259-
Temporality::Delta
260-
}
261-
InstrumentKind::UpDownCounter
262-
| InstrumentKind::ObservableUpDownCounter => {
263-
Temporality::Cumulative
264-
}
265-
}
266-
}
267-
}
268-
269240
/// An interface for OTLP metrics clients
270241
#[async_trait]
271242
pub trait MetricsClient: fmt::Debug + Send + Sync + 'static {

0 commit comments

Comments
 (0)