Skip to content

Commit 5f101d8

Browse files
authored
Merge branch 'main' into otlp-exporter-env
2 parents ae15a91 + 06abe3d commit 5f101d8

File tree

5 files changed

+186
-28
lines changed

5 files changed

+186
-28
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,153 @@
1+
//! # OpenTelemetry-Appender-Tracing
2+
//!
3+
//! This crate provides a bridge between the [`tracing`](https://docs.rs/tracing/latest/tracing/) crate and OpenTelemetry logs.
4+
//! It converts `tracing` events into OpenTelemetry `LogRecords`, allowing applications using `tracing` to seamlessly integrate
5+
//! with OpenTelemetry logging backends.
6+
//!
7+
//! ## Background
8+
//!
9+
//! Unlike traces and metrics, OpenTelemetry does not provide a dedicated logging API for end-users. Instead, it recommends using
10+
//! existing logging libraries and bridging them to OpenTelemetry logs. This crate serves as such a bridge for `tracing` users.
11+
//!
12+
//! ## Features
13+
//!
14+
//! - Converts `tracing` events into OpenTelemetry [`LogRecords`](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#log-and-event-record-definition)
15+
//! - Integrates as a [`Layer`](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/trait.Layer.html)
16+
//! from [`tracing-subscriber`](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/), allowing
17+
//! to be used alongside other `tracing` layers, such as `fmt`
18+
//! - Automatically attaches OpenTelemetry trace context (`TraceId`, `SpanId`, `TraceFlags`) to logs
19+
//! - Automatically associates OpenTelemetry Resource to logs
20+
//! - Supports exporting logs to OpenTelemetry-compatible backends (OTLP, stdout, etc.)
21+
//!
22+
//! ## Getting Started
23+
//!
24+
//! ### 1. Install Dependencies
25+
//!
26+
//! Add the following dependencies to your `Cargo.toml`:
27+
//!
28+
//! ```toml
29+
//! [dependencies]
30+
//! tracing = ">=0.1.40"
31+
//! tracing-core = { version = ">=0.1.33" }
32+
//! tracing-subscriber = { version = "0.3", features = ["registry", "std", "fmt"] }
33+
//! opentelemetry = { version = "0.28", features = ["logs"] }
34+
//! opentelemetry-sdk = { version = "0.28", features = ["logs"] }
35+
//! opentelemetry-appender-tracing = { version = "0.28.1" }
36+
//! ```
37+
//!
38+
//! ### 2. Set Up the OpenTelemetry Logger Provider
39+
//!
40+
//! Before integrating with `tracing`, create an OpenTelemetry [`SdkLoggerProvider`](https://docs.rs/opentelemetry_sdk/latest/opentelemetry_sdk/logs/struct.SdkLoggerProvider.html):
41+
//!
42+
//! ```rust
43+
//! use opentelemetry_sdk::logs::SdkLoggerProvider;
44+
//! use opentelemetry_stdout::LogExporter;
45+
//!
46+
//! let exporter = LogExporter::default();
47+
//! let provider = SdkLoggerProvider::builder()
48+
//! .with_simple_exporter(exporter)
49+
//! .build();
50+
//! ```
51+
//!
52+
//! In this example, `SdkLoggerProvider` is configured to use the `opentelemetry_stdout` crate to export logs to stdout. You can replace it with any other OpenTelemetry-compatible exporter.
53+
//! Any additional OpenTelemetry configuration (e.g., setting up a resource, additional processors etc.) can be done at this stage.
54+
//!
55+
//! ### 3. Create the OpenTelemetry-Tracing Bridge
56+
//!
57+
//! ```rust
58+
//! # use opentelemetry_sdk::logs::SdkLoggerProvider;
59+
//! # use opentelemetry_stdout::LogExporter;
60+
//! # use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
61+
//! # let exporter = LogExporter::default();
62+
//! # let provider = SdkLoggerProvider::builder()
63+
//! .with_simple_exporter(exporter)
64+
//! .build();
65+
//! let otel_layer = OpenTelemetryTracingBridge::new(&provider);
66+
//! ```
67+
//!
68+
//! ### 4. Register the `tracing` Subscriber
69+
//!
70+
//! Since this crate provides a `Layer` for `tracing`, you can register it with the `tracing` subscriber as shown below.
71+
//!
72+
//! ```rust
73+
//! # use opentelemetry_sdk::logs::SdkLoggerProvider;
74+
//! # use opentelemetry_stdout::LogExporter;
75+
//! # let exporter = LogExporter::default();
76+
//! # let provider = SdkLoggerProvider::builder().with_simple_exporter(exporter).build();
77+
//! # use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
78+
//! # let otel_layer = OpenTelemetryTracingBridge::new(&provider);
79+
//! use tracing_subscriber::prelude::*;
80+
//!
81+
//! tracing_subscriber::registry()
82+
//! .with(otel_layer)
83+
//! .with(tracing_subscriber::fmt::layer())
84+
//! .init();
85+
//! ```
86+
//!
87+
//! ### 5. Log Events Using `tracing`
88+
//!
89+
//! ```rust
90+
//! use tracing::error;
91+
//! error!(name: "my-event-name1", target: "my-system", event_id = 10, user_name = "otel", user_email = "[email protected]", message = "This is an example message");
92+
//! ```
93+
//!
94+
//!
95+
//! ## Mapping details
96+
//!
97+
//! Since OpenTelemetry and `tracing` have their own data models, this bridge performs the following mappings:
98+
//!
99+
//! | `tracing` | OpenTelemetry | Notes |
100+
//! |-----------------------|-------------------------|-----------------------------------------------------------------------------------------|
101+
//! | name of the event | `EventName` | OpenTelemetry defines logs with name as Events, so every `tracing` Event is actually an OTel Event |
102+
//! | target | `target` | Groups logs from the same module/crate. At recording time, `target` is stored in a top-level field. But exporters treat this information as OpenTelemetry `InstrumentationScope` |
103+
//! | level of the event | `Severity`, `SeverityText` | |
104+
//! | Fields | `Attributes` | Converted into OpenTelemetry log attributes. Field with "message" as key is specially treated and stored as `LogRecord::Body` |
105+
//! | Message | `Body` | The body/message of the log. This is done only if body was not already populated from "message" field above |
106+
//!
107+
//! ### Data Type Mapping
108+
//!
109+
//! The data types supported by `tracing` and OpenTelemetry are different and the following conversions are applied:
110+
//!
111+
//! | `tracing` Type | OpenTelemetry `AnyValue` Type |
112+
//! |----------------|-------------------------------|
113+
//! | `i64` | `Int` |
114+
//! | `f32`, `f64` | `Double` |
115+
//! | `u64` | `Int` (if convertible without loss) else `String` |
116+
//! | `&str` | `String` |
117+
//! | `bool` | `Bool` |
118+
//! | `&[u8]` | `Bytes` |
119+
//! | `&dyn Debug` | `String` (via `Debug` formatting) |
120+
//! | `&dyn Error` | `String` (via `Debug` formatting). This is stored into an attribute with key "exception.message", following [OTel conventions](https://opentelemetry.io/docs/specs/semconv/attributes-registry/exception/) |
121+
//!
122+
//! In future, additional types may be supported.
123+
//!
124+
//! > **Note:** This crate does not support `tracing` Spans. One may use [`tracing-opentelemetry`](https://docs.rs/tracing-opentelemetry/latest/tracing_opentelemetry/) to
125+
//! > convert `tracing` spans into OpenTelemetry spans. This is a third-party crate
126+
//! > that is not maintained by the OpenTelemetry project.
127+
//! > `tracing-opentelemetry`:
128+
//! > - Converts `tracing` spans into OpenTelemetry spans
129+
//! > - Converts `tracing` events into OpenTelemetry `SpanEvents` rather than logs
130+
//! > Depending on the outcome of the
131+
//! > [discussion](https://github.com/open-telemetry/opentelemetry-rust/issues/1571),
132+
//! > the OpenTelemetry project may provide direct support to map `tracing`
133+
//! > spans to OpenTelemetry in the future.
134+
//!
135+
//! ## Feature Flags
136+
//! `spec_unstable_logs_enabled`: TODO
137+
//!
138+
//! `experimental_metadata_attributes`: TODO
139+
//!
140+
//! `experimental_use_tracing_span_context`: TODO
141+
//!
142+
//! ## Limitations
143+
//! 1. There is no support for `Valuable` crate. [2819](https://github.com/open-telemetry/opentelemetry-rust/issues/2819)
144+
//!
145+
//! ## Stability Guarantees
146+
//! // TODO
147+
//!
148+
//! ## Further Reading
149+
//!
150+
//! - OpenTelemetry Rust: [opentelemetry-rust](https://github.com/open-telemetry/opentelemetry-rust)
151+
//! - Tracing: [tracing](https://docs.rs/tracing/)
152+
//! - OpenTelemetry Logs: [OpenTelemetry Logging Specification](https://opentelemetry.io/docs/specs/otel/logs/)
1153
pub mod layer;

opentelemetry-otlp/tests/integration_test/src/test_utils.rs

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -72,32 +72,35 @@ pub async fn start_collector_container() -> Result<()> {
7272
upsert_empty_file(LOGS_FILE);
7373

7474
// Start a new container
75-
let container_instance = GenericImage::new("otel/opentelemetry-collector", "latest")
76-
.with_wait_for(WaitFor::http(
77-
HttpWaitStrategy::new("/")
78-
.with_expected_status_code(404u16)
79-
.with_port(ContainerPort::Tcp(4318)),
80-
))
81-
.with_mapped_port(4317, ContainerPort::Tcp(4317))
82-
.with_mapped_port(4318, ContainerPort::Tcp(4318))
83-
.with_mount(Mount::bind_mount(
84-
fs::canonicalize("./otel-collector-config.yaml")?.to_string_lossy(),
85-
"/etc/otelcol/config.yaml",
86-
))
87-
.with_mount(Mount::bind_mount(
88-
fs::canonicalize("./actual/logs.json")?.to_string_lossy(),
89-
"/testresults/logs.json",
90-
))
91-
.with_mount(Mount::bind_mount(
92-
fs::canonicalize("./actual/metrics.json")?.to_string_lossy(),
93-
"/testresults/metrics.json",
94-
))
95-
.with_mount(Mount::bind_mount(
96-
fs::canonicalize("./actual/traces.json")?.to_string_lossy(),
97-
"/testresults/traces.json",
98-
))
99-
.start()
100-
.await?;
75+
let container_instance = GenericImage::new(
76+
"ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector",
77+
"latest",
78+
)
79+
.with_wait_for(WaitFor::http(
80+
HttpWaitStrategy::new("/")
81+
.with_expected_status_code(404u16)
82+
.with_port(ContainerPort::Tcp(4318)),
83+
))
84+
.with_mapped_port(4317, ContainerPort::Tcp(4317))
85+
.with_mapped_port(4318, ContainerPort::Tcp(4318))
86+
.with_mount(Mount::bind_mount(
87+
fs::canonicalize("./otel-collector-config.yaml")?.to_string_lossy(),
88+
"/etc/otelcol/config.yaml",
89+
))
90+
.with_mount(Mount::bind_mount(
91+
fs::canonicalize("./actual/logs.json")?.to_string_lossy(),
92+
"/testresults/logs.json",
93+
))
94+
.with_mount(Mount::bind_mount(
95+
fs::canonicalize("./actual/metrics.json")?.to_string_lossy(),
96+
"/testresults/metrics.json",
97+
))
98+
.with_mount(Mount::bind_mount(
99+
fs::canonicalize("./actual/traces.json")?.to_string_lossy(),
100+
"/testresults/traces.json",
101+
))
102+
.start()
103+
.await?;
101104

102105
let container = Arc::new(container_instance);
103106
otel_info!(

opentelemetry-sdk/benches/log_enabled.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
Total Number of Cores:   14 (10 performance and 4 efficiency)
66
| Test | Average time|
77
|---------------------------------------------|-------------|
8-
| exporter_disabled_concurrent_processor | 1.0 ns |
9-
| exporter_disabled_simple_processor | 4.5 ns |
8+
| exporter_disabled_concurrent_processor | 980 ps |
9+
| exporter_disabled_simple_processor | 4.3 ns |
1010
*/
1111

1212
// cargo bench --bench log_enabled --features="spec_unstable_logs_enabled,experimental_logs_concurrent_log_processor"
@@ -33,6 +33,7 @@ impl LogExporter for NoopExporter {
3333
Ok(())
3434
}
3535

36+
#[inline]
3637
fn event_enabled(
3738
&self,
3839
_level: opentelemetry::logs::Severity,

opentelemetry-sdk/src/logs/concurrent_log_processor.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ impl<T: LogExporter> LogProcessor for SimpleConcurrentLogProcessor<T> {
4848
}
4949

5050
#[cfg(feature = "spec_unstable_logs_enabled")]
51+
#[inline]
5152
fn event_enabled(
5253
&self,
5354
level: opentelemetry::logs::Severity,

opentelemetry-sdk/src/logs/simple_log_processor.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ impl<T: LogExporter> LogProcessor for SimpleLogProcessor<T> {
134134
}
135135

136136
#[cfg(feature = "spec_unstable_logs_enabled")]
137+
#[inline]
137138
fn event_enabled(
138139
&self,
139140
level: opentelemetry::logs::Severity,

0 commit comments

Comments
 (0)