Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OTLP Exporter builder to return more specific Error type #2654

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/logs-basic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ opentelemetry_sdk = { path = "../../opentelemetry-sdk", features = ["logs"] }
opentelemetry-stdout = { path = "../../opentelemetry-stdout", features = ["logs"]}
opentelemetry-appender-tracing = { path = "../../opentelemetry-appender-tracing", default-features = false}
tracing = { workspace = true, features = ["std"]}
tracing-subscriber = { workspace = true, features = ["registry", "std"] }
tracing-subscriber = { workspace = true, features = ["env-filter","registry", "std", "fmt"] }
35 changes: 32 additions & 3 deletions examples/logs-basic/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use opentelemetry_appender_tracing::layer;
use opentelemetry_sdk::logs::SdkLoggerProvider;
use opentelemetry_sdk::Resource;
use tracing::error;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{prelude::*, EnvFilter};

fn main() {
let exporter = opentelemetry_stdout::LogExporter::default();
Expand All @@ -14,8 +14,37 @@ fn main() {
)
.with_simple_exporter(exporter)
.build();
let layer = layer::OpenTelemetryTracingBridge::new(&provider);
tracing_subscriber::registry().with(layer).init();

// For the OpenTelemetry layer, add a tracing filter to filter events from
// OpenTelemetry and its dependent crates (opentelemetry-otlp uses crates
// like reqwest/tonic etc.) from being sent back to OTel itself, thus
// preventing infinite telemetry generation. The filter levels are set as
// follows:
// - Allow `info` level and above by default.
// - Restrict `opentelemetry`, `hyper`, `tonic`, and `reqwest` completely.
// Note: This will also drop events from crates like `tonic` etc. even when
// they are used outside the OTLP Exporter. For more details, see:
// https://github.com/open-telemetry/opentelemetry-rust/issues/761
let filter_otel = EnvFilter::new("info")
.add_directive("hyper=off".parse().unwrap())
.add_directive("opentelemetry=off".parse().unwrap())
.add_directive("tonic=off".parse().unwrap())
.add_directive("h2=off".parse().unwrap())
.add_directive("reqwest=off".parse().unwrap());
let otel_layer = layer::OpenTelemetryTracingBridge::new(&provider).with_filter(filter_otel);

// Create a new tracing::Fmt layer to print the logs to stdout. It has a
// default filter of `info` level and above, and `debug` and above for logs
// from OpenTelemetry crates. The filter levels can be customized as needed.
let filter_fmt = EnvFilter::new("info").add_directive("opentelemetry=debug".parse().unwrap());
let fmt_layer = tracing_subscriber::fmt::layer()
.with_thread_names(true)
.with_filter(filter_fmt);

tracing_subscriber::registry()
.with(otel_layer)
.with(fmt_layer)
.init();

error!(name: "my-event-name", target: "my-system", event_id = 20, user_name = "otel", user_email = "otel@opentelemetry.io", message = "This is an example message");
let _ = provider.shutdown();
Expand Down
2 changes: 1 addition & 1 deletion examples/tracing-grpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ opentelemetry_sdk = { path = "../../opentelemetry-sdk", features = ["rt-tokio"]
opentelemetry-stdout = { path = "../../opentelemetry-stdout", features = ["trace"] }
prost = { workspace = true }
tokio = { workspace = true, features = ["full"] }
tonic = { workspace = true }
tonic = { workspace = true, features = ["server"] }

[build-dependencies]
tonic-build = { workspace = true }
6 changes: 4 additions & 2 deletions examples/tracing-jaeger/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use opentelemetry::{
global,
trace::{TraceContextExt, TraceError, Tracer},
trace::{TraceContextExt, Tracer},
KeyValue,
};
use opentelemetry_otlp::ExporterBuildError;
use opentelemetry_sdk::trace::SdkTracerProvider;
use opentelemetry_sdk::Resource;

use std::error::Error;

fn init_tracer_provider() -> Result<opentelemetry_sdk::trace::SdkTracerProvider, TraceError> {
fn init_tracer_provider() -> Result<opentelemetry_sdk::trace::SdkTracerProvider, ExporterBuildError>
{
let exporter = opentelemetry_otlp::SpanExporter::builder()
.with_tonic()
.build()?;
Expand Down
10 changes: 6 additions & 4 deletions opentelemetry-appender-tracing/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

## vNext

Fixes [1682](https://github.com/open-telemetry/opentelemetry-rust/issues/1682).
"spec_unstable_logs_enabled" feature now do not suppress logs for other layers.

## 0.28.1

Released 2025-Feb-12

- Bump `tracing-opentelemetry` to 0.29
- New experimental feature to use trace\_id & span\_id from spans created through the [tracing](https://crates.io/crates/tracing) crate (experimental_use_tracing_span_context) [#2438](https://github.com/open-telemetry/opentelemetry-rust/pull/2438)

- New *experimental* feature to use trace_id & span_id from spans created through the [tracing](https://crates.io/crates/tracing) crate (experimental_use_tracing_span_context) [#2438](https://github.com/open-telemetry/opentelemetry-rust/pull/2438)

## 0.28.0

Expand All @@ -27,6 +28,7 @@ Released 2024-Nov-11
- **Breaking** [2291](https://github.com/open-telemetry/opentelemetry-rust/pull/2291) Rename `logs_level_enabled flag` to `spec_unstable_logs_enabled`. Please enable this updated flag if the feature is needed. This flag will be removed once the feature is stabilized in the specifications.

## v0.26.0

Released 2024-Sep-30

- Update `opentelemetry` dependency version to 0.26
Expand All @@ -45,7 +47,7 @@ Released 2024-Sep-30
Exporters might use the target to override the instrumentation scope, which previously contained "opentelemetry-appender-tracing".

- **Breaking** [1928](https://github.com/open-telemetry/opentelemetry-rust/pull/1928) Insert tracing event name into LogRecord::event_name instead of attributes.
- If using a custom exporter, then they must serialize this field directly from LogRecord::event_name instead of iterating over the attributes. OTLP Exporter is modified to handle this.
- If using a custom exporter, then they must serialize this field directly from LogRecord::event_name instead of iterating over the attributes. OTLP Exporter is modified to handle this.
- Update `opentelemetry` dependency version to 0.24

## v0.4.0
Expand Down
4 changes: 2 additions & 2 deletions opentelemetry-appender-tracing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ tracing-opentelemetry = { version = "0.29", optional = true }
log = { workspace = true }
opentelemetry-stdout = { path = "../opentelemetry-stdout", features = ["logs"] }
opentelemetry_sdk = { path = "../opentelemetry-sdk", features = ["logs", "testing"] }
tracing-subscriber = { workspace = true, features = ["registry", "std", "env-filter"] }
tracing = { workspace = true, features = ["std"]}
tracing-subscriber = { workspace = true, features = ["env-filter","registry", "std", "fmt"] }
tracing-log = "0.2"
criterion = { workspace = true }
tokio = { workspace = true, features = ["full"]}
Expand All @@ -35,7 +36,6 @@ pprof = { version = "0.14", features = ["flamegraph", "criterion"] }
default = []
experimental_metadata_attributes = ["dep:tracing-log"]
spec_unstable_logs_enabled = ["opentelemetry/spec_unstable_logs_enabled"]
# TODO - Enable this in 0.28.1 (once tracing-opentelemetry v0.29 is released)
experimental_use_tracing_span_context = ["tracing-opentelemetry"]


Expand Down
47 changes: 12 additions & 35 deletions opentelemetry-appender-tracing/benches/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use criterion::{criterion_group, criterion_main, Criterion};
use opentelemetry::InstrumentationScope;
use opentelemetry_appender_tracing::layer as tracing_layer;
use opentelemetry_sdk::error::OTelSdkResult;
use opentelemetry_sdk::logs::{LogBatch, LogExporter};
use opentelemetry_sdk::logs::{LogProcessor, SdkLogRecord, SdkLoggerProvider};
use opentelemetry_sdk::Resource;
#[cfg(not(target_os = "windows"))]
Expand All @@ -27,40 +26,19 @@ use tracing_subscriber::prelude::*;
use tracing_subscriber::Layer;
use tracing_subscriber::Registry;

#[derive(Debug, Clone)]
struct NoopExporter {
enabled: bool,
}

impl LogExporter for NoopExporter {
#[allow(clippy::manual_async_fn)]
fn export(
&self,
_batch: LogBatch<'_>,
) -> impl std::future::Future<Output = OTelSdkResult> + Send {
async { OTelSdkResult::Ok(()) }
}

fn event_enabled(&self, _: opentelemetry::logs::Severity, _: &str, _: &str) -> bool {
self.enabled
}
}

#[derive(Debug)]
struct NoopProcessor<E: LogExporter> {
exporter: E,
struct NoopProcessor {
enabled: bool,
}

impl<E: LogExporter> NoopProcessor<E> {
fn new(exporter: E) -> Self {
Self { exporter }
impl NoopProcessor {
fn new(enabled: bool) -> Self {
Self { enabled }
}
}

impl<E: LogExporter> LogProcessor for NoopProcessor<E> {
fn emit(&self, _: &mut SdkLogRecord, _: &InstrumentationScope) {
// no-op
}
impl LogProcessor for NoopProcessor {
fn emit(&self, _: &mut SdkLogRecord, _: &InstrumentationScope) {}

fn force_flush(&self) -> OTelSdkResult {
Ok(())
Expand All @@ -72,11 +50,11 @@ impl<E: LogExporter> LogProcessor for NoopProcessor<E> {

fn event_enabled(
&self,
level: opentelemetry::logs::Severity,
target: &str,
name: &str,
_level: opentelemetry::logs::Severity,
_target: &str,
_name: &str,
) -> bool {
self.exporter.event_enabled(level, target, name)
self.enabled
}
}

Expand Down Expand Up @@ -126,8 +104,7 @@ fn benchmark_no_subscriber(c: &mut Criterion) {
}

fn benchmark_with_ot_layer(c: &mut Criterion, enabled: bool, bench_name: &str) {
let exporter = NoopExporter { enabled };
let processor = NoopProcessor::new(exporter);
let processor = NoopProcessor::new(enabled);
let provider = SdkLoggerProvider::builder()
.with_resource(
Resource::builder_empty()
Expand Down
35 changes: 32 additions & 3 deletions opentelemetry-appender-tracing/examples/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use opentelemetry_appender_tracing::layer;
use opentelemetry_sdk::{logs::SdkLoggerProvider, Resource};
use tracing::error;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{prelude::*, EnvFilter};

fn main() {
let exporter = opentelemetry_stdout::LogExporter::default();
Expand All @@ -15,8 +15,37 @@ fn main() {
)
.with_simple_exporter(exporter)
.build();
let layer = layer::OpenTelemetryTracingBridge::new(&provider);
tracing_subscriber::registry().with(layer).init();

// For the OpenTelemetry layer, add a tracing filter to filter events from
// OpenTelemetry and its dependent crates (opentelemetry-otlp uses crates
// like reqwest/tonic etc.) from being sent back to OTel itself, thus
// preventing infinite telemetry generation. The filter levels are set as
// follows:
// - Allow `info` level and above by default.
// - Restrict `opentelemetry`, `hyper`, `tonic`, and `reqwest` completely.
// Note: This will also drop events from crates like `tonic` etc. even when
// they are used outside the OTLP Exporter. For more details, see:
// https://github.com/open-telemetry/opentelemetry-rust/issues/761
let filter_otel = EnvFilter::new("info")
.add_directive("hyper=off".parse().unwrap())
.add_directive("opentelemetry=off".parse().unwrap())
.add_directive("tonic=off".parse().unwrap())
.add_directive("h2=off".parse().unwrap())
.add_directive("reqwest=off".parse().unwrap());
let otel_layer = layer::OpenTelemetryTracingBridge::new(&provider).with_filter(filter_otel);

// Create a new tracing::Fmt layer to print the logs to stdout. It has a
// default filter of `info` level and above, and `debug` and above for logs
// from OpenTelemetry crates. The filter levels can be customized as needed.
let filter_fmt = EnvFilter::new("info").add_directive("opentelemetry=debug".parse().unwrap());
let fmt_layer = tracing_subscriber::fmt::layer()
.with_thread_names(true)
.with_filter(filter_fmt);

tracing_subscriber::registry()
.with(otel_layer)
.with(fmt_layer)
.init();

error!(name: "my-event-name", target: "my-system", event_id = 20, user_name = "otel", user_email = "otel@opentelemetry.io", message = "This is an example message");
let _ = provider.shutdown();
Expand Down
39 changes: 15 additions & 24 deletions opentelemetry-appender-tracing/src/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ where
event: &tracing::Event<'_>,
_ctx: tracing_subscriber::layer::Context<'_, S>,
) {
let severity = severity_of_level(event.metadata().level());
let target = event.metadata().target();
#[cfg(feature = "spec_unstable_logs_enabled")]
if !self.logger.event_enabled(severity, target) {
// TODO: See if we need internal logs or track the count.
return;
}

#[cfg(feature = "experimental_metadata_attributes")]
let normalized_meta = event.normalized_metadata();

Expand All @@ -170,9 +178,9 @@ where
let mut log_record = self.logger.create_log_record();

// TODO: Fix heap allocation
log_record.set_target(meta.target().to_string());
log_record.set_target(target.to_string());
log_record.set_event_name(meta.name());
log_record.set_severity_number(severity_of_level(meta.level()));
log_record.set_severity_number(severity);
log_record.set_severity_text(meta.level().as_str());
let mut visitor = EventVisitor::new(&mut log_record);
#[cfg(feature = "experimental_metadata_attributes")]
Expand Down Expand Up @@ -203,17 +211,6 @@ where
//emit record
self.logger.emit(log_record);
}

#[cfg(feature = "spec_unstable_logs_enabled")]
fn event_enabled(
&self,
_event: &tracing_core::Event<'_>,
_ctx: tracing_subscriber::layer::Context<'_, S>,
) -> bool {
let severity = severity_of_level(_event.metadata().level());
self.logger
.event_enabled(severity, _event.metadata().target())
}
}

const fn severity_of_level(level: &Level) -> Severity {
Expand Down Expand Up @@ -266,17 +263,11 @@ mod tests {
struct ReentrantLogExporter;

impl LogExporter for ReentrantLogExporter {
#[allow(clippy::manual_async_fn)]
fn export(
&self,
_batch: LogBatch<'_>,
) -> impl std::future::Future<Output = OTelSdkResult> + Send {
async {
// This will cause a deadlock as the export itself creates a log
// while still within the lock of the SimpleLogProcessor.
warn!(name: "my-event-name", target: "reentrant", event_id = 20, user_name = "otel", user_email = "otel@opentelemetry.io");
Ok(())
}
async fn export(&self, _batch: LogBatch<'_>) -> OTelSdkResult {
// This will cause a deadlock as the export itself creates a log
// while still within the lock of the SimpleLogProcessor.
warn!(name: "my-event-name", target: "reentrant", event_id = 20, user_name = "otel", user_email = "otel@opentelemetry.io");
Ok(())
}
}

Expand Down
13 changes: 13 additions & 0 deletions opentelemetry-otlp/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

## vNext

- The `OTEL_EXPORTER_OTLP_TIMEOUT`, `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT`, `OTEL_EXPORTER_OTLP_METRICS_TIMEOUT` and `OTEL_EXPORTER_OTLP_LOGS_TIMEOUT` are changed from seconds to miliseconds.

- *Breaking*

ExporterBuilder's build() method now Result with `ExporterBuildError` being the
Error variant. Previously it returned signal specific errors like `LogError`
from the `opentelemetry_sdk`, which are no longer part of the sdk. No changes
required if you were using unwrap/expect. If you were matching on the returning
Error enum, replace with the enum `ExporterBuildError`. Unlike the previous
`Error` which contained many variants unrelated to building an exporter, the
new one returns specific variants applicable to building an exporter. Some
variants might be applicable only on select features.

## 0.28.0

Released 2025-Feb-10
Expand Down
2 changes: 1 addition & 1 deletion opentelemetry-otlp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
async-trait = { workspace = true }
futures-core = { workspace = true }
opentelemetry = { version = "0.28", default-features = false, path = "../opentelemetry" }
opentelemetry_sdk = { version = "0.28", default-features = false, path = "../opentelemetry-sdk" }
Expand All @@ -51,6 +50,7 @@ opentelemetry_sdk = { features = ["trace", "rt-tokio", "testing"], path = "../op
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
futures-util = { workspace = true }
temp-env = { workspace = true }
tonic = { workspace = true, features = ["server"] }

[features]
# telemetry pillars and functions
Expand Down
Loading