opentelemetry_otlp/lib.rs
1//! # OpenTelemetry OTLP Exporter
2//!
3//! The OTLP Exporter enables exporting telemetry data (logs, metrics, and traces) in the
4//! OpenTelemetry Protocol (OTLP) format to compatible backends. These backends include:
5//!
6//! - OpenTelemetry Collector
7//! - Open-source observability tools (Prometheus, Jaeger, etc.)
8//! - Vendor-specific monitoring platforms
9//!
10//! This crate supports sending OTLP data via:
11//! - gRPC
12//! - HTTP (binary protobuf or JSON)
13//!
14//! ## Quickstart with OpenTelemetry Collector
15//!
16//! ### HTTP Transport (Port 4318)
17//!
18//! Run the OpenTelemetry Collector:
19//!
20//! ```shell
21//! $ docker run -p 4318:4318 otel/opentelemetry-collector:latest
22//! ```
23//!
24//! Configure your application to export traces via HTTP:
25//!
26//! ```no_run
27//! # #[cfg(all(feature = "trace", feature = "http-proto"))]
28//! # {
29//! use opentelemetry::global;
30//! use opentelemetry::trace::Tracer;
31//! use opentelemetry_otlp::Protocol;
32//! use opentelemetry_otlp::WithExportConfig;
33//!
34//! fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
35//! // Initialize OTLP exporter using HTTP binary protocol
36//! let otlp_exporter = opentelemetry_otlp::SpanExporter::builder()
37//! .with_http()
38//! .with_protocol(Protocol::HttpBinary)
39//! .build()?;
40//!
41//! // Create a tracer provider with the exporter
42//! let tracer_provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
43//! .with_batch_exporter(otlp_exporter)
44//! .build();
45//!
46//! // Set it as the global provider
47//! global::set_tracer_provider(tracer_provider);
48//!
49//! // Get a tracer and create spans
50//! let tracer = global::tracer("my_tracer");
51//! tracer.in_span("doing_work", |_cx| {
52//! // Your application logic here...
53//! });
54//!
55//! Ok(())
56//! # }
57//! }
58//! ```
59//!
60//! ### gRPC Transport (Port 4317)
61//!
62//! Run the OpenTelemetry Collector:
63//!
64//! ```shell
65//! $ docker run -p 4317:4317 otel/opentelemetry-collector:latest
66//! ```
67//!
68//! Configure your application to export traces via gRPC (the tonic client requires a Tokio runtime):
69//!
70//! - With `[tokio::main]`
71//!
72//! ```no_run
73//! # #[cfg(all(feature = "trace", feature = "grpc-tonic"))]
74//! # {
75//! use opentelemetry::{global, trace::Tracer};
76//!
77//! #[tokio::main]
78//! async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
79//! // Initialize OTLP exporter using gRPC (Tonic)
80//! let otlp_exporter = opentelemetry_otlp::SpanExporter::builder()
81//! .with_tonic()
82//! .build()?;
83//!
84//! // Create a tracer provider with the exporter
85//! let tracer_provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
86//! .with_batch_exporter(otlp_exporter)
87//! .build();
88//!
89//! // Set it as the global provider
90//! global::set_tracer_provider(tracer_provider);
91//!
92//! // Get a tracer and create spans
93//! let tracer = global::tracer("my_tracer");
94//! tracer.in_span("doing_work", |_cx| {
95//! // Your application logic here...
96//! });
97//!
98//! Ok(())
99//! # }
100//! }
101//! ```
102//!
103//! - Without `[tokio::main]`
104//!
105//! ```no_run
106//! # #[cfg(all(feature = "trace", feature = "grpc-tonic"))]
107//! # {
108//! use opentelemetry::{global, trace::Tracer};
109//!
110//! fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
111//! // Initialize OTLP exporter using gRPC (Tonic)
112//! let rt = tokio::runtime::Runtime::new()?;
113//! let tracer_provider = rt.block_on(async {
114//! let exporter = opentelemetry_otlp::SpanExporter::builder()
115//! .with_tonic()
116//! .build()
117//! .expect("Failed to create span exporter");
118//! opentelemetry_sdk::trace::SdkTracerProvider::builder()
119//! .with_batch_exporter(exporter)
120//! .build()
121//! });
122//!
123//! // Set it as the global provider
124//! global::set_tracer_provider(tracer_provider);
125//!
126//! // Get a tracer and create spans
127//! let tracer = global::tracer("my_tracer");
128//! tracer.in_span("doing_work", |_cx| {
129//! // Your application logic here...
130//! });
131//!
132//! // Ensure the runtime (`rt`) remains active until the program ends
133//! Ok(())
134//! # }
135//! }
136//! ```
137//!
138//! ## Using with Jaeger
139//!
140//! Jaeger natively supports the OTLP protocol, making it easy to send traces directly:
141//!
142//! ```shell
143//! $ docker run -p 16686:16686 -p 4317:4317 -e COLLECTOR_OTLP_ENABLED=true jaegertracing/all-in-one:latest
144//! ```
145//!
146//! After running your application configured with the OTLP exporter, view traces at:
147//! `http://localhost:16686`
148//!
149//! ## Using with Prometheus
150//!
151//! Prometheus natively supports accepting metrics via the OTLP protocol
152//! (HTTP/protobuf). You can [run
153//! Prometheus](https://prometheus.io/docs/prometheus/latest/installation/) with
154//! the following command:
155//!
156//! ```shell
157//! docker run -p 9090:9090 -v ./prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus --config.file=/etc/prometheus/prometheus.yml --web.enable-otlp-receiver
158//! ```
159//!
160//! (An empty prometheus.yml file is sufficient for this example.)
161//!
162//! Modify your application to export metrics via OTLP:
163//!
164//! ```no_run
165//! # #[cfg(all(feature = "metrics", feature = "http-proto"))]
166//! # {
167//! use opentelemetry::global;
168//! use opentelemetry::metrics::Meter;
169//! use opentelemetry::KeyValue;
170//! use opentelemetry_otlp::Protocol;
171//! use opentelemetry_otlp::WithExportConfig;
172//!
173//! fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
174//! // Initialize OTLP exporter using HTTP binary protocol
175//! let exporter = opentelemetry_otlp::MetricExporter::builder()
176//! .with_http()
177//! .with_protocol(Protocol::HttpBinary)
178//! .with_endpoint("http://localhost:9090/api/v1/otlp/v1/metrics")
179//! .build()?;
180//!
181//! // Create a meter provider with the OTLP Metric exporter
182//! let meter_provider = opentelemetry_sdk::metrics::SdkMeterProvider::builder()
183//! .with_periodic_exporter(exporter)
184//! .build();
185//! global::set_meter_provider(meter_provider.clone());
186//!
187//! // Get a meter
188//! let meter = global::meter("my_meter");
189//!
190//! // Create a metric
191//! let counter = meter.u64_counter("my_counter").build();
192//! counter.add(1, &[KeyValue::new("key", "value")]);
193//!
194//! // Shutdown the meter provider. This will trigger an export of all metrics.
195//! meter_provider.shutdown()?;
196//!
197//! Ok(())
198//! # }
199//! }
200//! ```
201//!
202//! After running your application configured with the OTLP exporter, view metrics at:
203//! `http://localhost:9090`
204//! ## Show Logs, Metrics too (TODO)
205//!
206//! [`tokio`]: https://tokio.rs
207//!
208//! # Feature Flags
209//! The following feature flags can enable exporters for different telemetry signals:
210//!
211//! * `trace`: Includes the trace exporters.
212//! * `metrics`: Includes the metrics exporters.
213//! * `logs`: Includes the logs exporters.
214//!
215//! The following feature flags generate additional code and types:
216//! * `serialize`: Enables serialization support for type defined in this crate via `serde`.
217//!
218//! The following feature flags offer additional configurations on gRPC:
219//!
220//! For users using `tonic` as grpc layer:
221//! * `grpc-tonic`: Use `tonic` as grpc layer.
222//! * `gzip-tonic`: Use gzip compression for `tonic` grpc layer.
223//! * `zstd-tonic`: Use zstd compression for `tonic` grpc layer.
224//! * `tls`: Enable rustls TLS support using ring for `tonic` (default TLS feature).
225//! * `tls-ring`: Enable rustls TLS support using ring for `tonic`.
226//! * `tls-aws-lc`: Enable rustls TLS support using aws-lc for `tonic`.
227//! * `tls-provider-agnostic`: Provider-agnostic TLS — enables TLS code paths without bundling a specific
228//! crypto provider. Use this when you install a `CryptoProvider` globally
229//! (e.g., via `rustls-openssl` for FIPS/OpenSSL environments).
230//! * `tls-roots`: Adds system trust roots to rustls-based gRPC clients using the rustls-native-certs crate
231//! * `tls-webpki-roots`: Embeds Mozilla's trust roots to rustls-based gRPC clients using the webpki-roots crate
232//!
233//! The following feature flags offer additional configurations on http:
234//!
235//! * `http-proto`: Use http as transport layer, protobuf as body format. This feature is enabled by default.
236//! * `gzip-http`: Use gzip compression for HTTP transport.
237//! * `zstd-http`: Use zstd compression for HTTP transport.
238//! * `reqwest-blocking-client`: Use reqwest blocking http client. This feature is enabled by default.
239//! * `reqwest-client`: Use reqwest http client.
240//! * `reqwest-rustls`: Use reqwest with TLS with system trust roots via `rustls-native-certs` crate.
241//! * `reqwest-rustls-webpki-roots`: Use reqwest with TLS with Mozilla's trust roots via `webpki-roots` crate.
242//!
243//! # Kitchen Sink Full Configuration
244//!
245//! Example showing how to override all configuration options.
246//!
247//! Generally there are two parts of configuration. One is the exporter, the other is the provider.
248//! Users can configure the exporter using [SpanExporter::builder()] for traces,
249//! and [MetricExporter::builder()] + [opentelemetry_sdk::metrics::PeriodicReader::builder()] for metrics.
250//! Once you have an exporter, you can add it to either a [opentelemetry_sdk::trace::SdkTracerProvider::builder()] for traces,
251//! or [opentelemetry_sdk::metrics::SdkMeterProvider::builder()] for metrics.
252//!
253//! ```no_run
254//! use opentelemetry::{global, KeyValue, trace::Tracer};
255//! use opentelemetry_sdk::{trace::{self, RandomIdGenerator, Sampler}, Resource};
256//! # #[cfg(feature = "metrics")]
257//! use opentelemetry_sdk::metrics::Temporality;
258//! use opentelemetry_otlp::{Protocol, WithExportConfig, Compression};
259//! # #[cfg(feature = "grpc-tonic")]
260//! use opentelemetry_otlp::WithTonicConfig;
261//! # #[cfg(any(feature = "http-proto", feature = "http-json"))]
262//! use opentelemetry_otlp::WithHttpConfig;
263//! use std::time::Duration;
264//! # #[cfg(feature = "grpc-tonic")]
265//! use tonic::metadata::*;
266//!
267//! fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
268//! # #[cfg(all(feature = "trace", feature = "grpc-tonic"))]
269//! # let tracer = {
270//! let mut map = MetadataMap::with_capacity(3);
271//!
272//! map.insert("x-host", "example.com".parse().unwrap());
273//! map.insert("x-number", "123".parse().unwrap());
274//! map.insert_bin("trace-proto-bin", MetadataValue::from_bytes(b"[binary data]"));
275//! let exporter = opentelemetry_otlp::SpanExporter::builder()
276//! .with_tonic()
277//! .with_endpoint("http://localhost:4317")
278//! .with_timeout(Duration::from_secs(3))
279//! .with_metadata(map)
280//! .build()?;
281//!
282//! let tracer_provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
283//! .with_batch_exporter(exporter)
284//! .with_sampler(Sampler::AlwaysOn)
285//! .with_id_generator(RandomIdGenerator::default())
286//! .with_max_events_per_span(64)
287//! .with_max_attributes_per_span(16)
288//! .with_resource(Resource::builder_empty().with_attributes([KeyValue::new("service.name", "example")]).build())
289//! .build();
290//! global::set_tracer_provider(tracer_provider.clone());
291//! let tracer = global::tracer("tracer-name");
292//! # tracer
293//! # };
294//!
295//! // HTTP exporter example with compression
296//! # #[cfg(all(feature = "trace", feature = "http-proto"))]
297//! # let _http_tracer = {
298//! let exporter = opentelemetry_otlp::SpanExporter::builder()
299//! .with_http()
300//! .with_endpoint("http://localhost:4318/v1/traces")
301//! .with_timeout(Duration::from_secs(3))
302//! .with_protocol(Protocol::HttpBinary)
303//! .with_compression(Compression::Gzip) // Requires gzip-http feature
304//! .build()?;
305//! # exporter
306//! # };
307//!
308//! # #[cfg(all(feature = "metrics", feature = "grpc-tonic"))]
309//! # {
310//! let exporter = opentelemetry_otlp::MetricExporter::builder()
311//! .with_tonic()
312//! .with_endpoint("http://localhost:4318/v1/metrics")
313//! .with_protocol(Protocol::Grpc)
314//! .with_timeout(Duration::from_secs(3))
315//! .build()
316//! .unwrap();
317//!
318//! let provider = opentelemetry_sdk::metrics::SdkMeterProvider::builder()
319//! .with_periodic_exporter(exporter)
320//! .with_resource(Resource::builder_empty().with_attributes([KeyValue::new("service.name", "example")]).build())
321//! .build();
322//! # }
323//!
324//! // HTTP metrics exporter example with compression
325//! # #[cfg(all(feature = "metrics", feature = "http-proto"))]
326//! # {
327//! let exporter = opentelemetry_otlp::MetricExporter::builder()
328//! .with_http()
329//! .with_endpoint("http://localhost:4318/v1/metrics")
330//! .with_protocol(Protocol::HttpBinary)
331//! .with_timeout(Duration::from_secs(3))
332//! .with_compression(Compression::Zstd) // Requires zstd-http feature
333//! .build()
334//! .unwrap();
335//! # }
336//!
337//! # #[cfg(all(feature = "trace", feature = "grpc-tonic"))]
338//! # {
339//! tracer.in_span("doing_work", |cx| {
340//! // Traced app logic here...
341//! });
342//! # }
343//!
344//! Ok(())
345//! }
346//! ```
347#![warn(
348 future_incompatible,
349 missing_debug_implementations,
350 missing_docs,
351 nonstandard_style,
352 rust_2018_idioms,
353 unreachable_pub,
354 unused
355)]
356#![allow(elided_lifetimes_in_paths)]
357#![cfg_attr(
358 docsrs,
359 feature(doc_cfg, doc_auto_cfg),
360 deny(rustdoc::broken_intra_doc_links)
361)]
362#![cfg_attr(test, deny(warnings))]
363
364mod exporter;
365#[cfg(feature = "logs")]
366#[cfg(any(feature = "http-proto", feature = "http-json", feature = "grpc-tonic"))]
367mod logs;
368#[cfg(feature = "metrics")]
369#[cfg(any(feature = "http-proto", feature = "http-json", feature = "grpc-tonic"))]
370mod metric;
371#[cfg(feature = "trace")]
372#[cfg(any(feature = "http-proto", feature = "http-json", feature = "grpc-tonic"))]
373mod span;
374
375pub use crate::exporter::Compression;
376pub use crate::exporter::ExportConfig;
377pub use crate::exporter::ExporterBuildError;
378#[cfg(feature = "trace")]
379#[cfg(any(feature = "http-proto", feature = "http-json", feature = "grpc-tonic"))]
380pub use crate::span::{
381 SpanExporter, SpanExporterBuilder, OTEL_EXPORTER_OTLP_TRACES_COMPRESSION,
382 OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_HEADERS,
383 OTEL_EXPORTER_OTLP_TRACES_TIMEOUT,
384};
385
386#[cfg(feature = "metrics")]
387#[cfg(any(feature = "http-proto", feature = "http-json", feature = "grpc-tonic"))]
388pub use crate::metric::{
389 MetricExporter, MetricExporterBuilder, OTEL_EXPORTER_OTLP_METRICS_COMPRESSION,
390 OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, OTEL_EXPORTER_OTLP_METRICS_HEADERS,
391 OTEL_EXPORTER_OTLP_METRICS_TIMEOUT,
392};
393
394#[cfg(feature = "logs")]
395#[cfg(any(feature = "http-proto", feature = "http-json", feature = "grpc-tonic"))]
396pub use crate::logs::{
397 LogExporter, LogExporterBuilder, OTEL_EXPORTER_OTLP_LOGS_COMPRESSION,
398 OTEL_EXPORTER_OTLP_LOGS_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_HEADERS,
399 OTEL_EXPORTER_OTLP_LOGS_TIMEOUT,
400};
401
402#[cfg(any(feature = "http-proto", feature = "http-json"))]
403pub use crate::exporter::http::{HasHttpConfig, WithHttpConfig};
404
405#[cfg(feature = "grpc-tonic")]
406pub use crate::exporter::tonic::{HasTonicConfig, WithTonicConfig};
407
408pub use crate::exporter::{
409 HasExportConfig, WithExportConfig, OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_ENDPOINT,
410 OTEL_EXPORTER_OTLP_ENDPOINT_DEFAULT, OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_PROTOCOL,
411 OTEL_EXPORTER_OTLP_PROTOCOL_DEFAULT, OTEL_EXPORTER_OTLP_TIMEOUT,
412 OTEL_EXPORTER_OTLP_TIMEOUT_DEFAULT,
413};
414
415/// Type to indicate the builder does not have a client set.
416#[derive(Debug, Default, Clone)]
417pub struct NoExporterBuilderSet;
418
419/// Type to hold the [TonicExporterBuilder] and indicate it has been set.
420///
421/// Allowing access to [TonicExporterBuilder] specific configuration methods.
422#[cfg(feature = "grpc-tonic")]
423// This is for clippy to work with only the grpc-tonic feature enabled
424#[allow(unused)]
425#[derive(Debug, Default)]
426pub struct TonicExporterBuilderSet(TonicExporterBuilder);
427
428/// Type to hold the [HttpExporterBuilder] and indicate it has been set.
429///
430/// Allowing access to [HttpExporterBuilder] specific configuration methods.
431#[cfg(any(feature = "http-proto", feature = "http-json"))]
432#[derive(Debug, Default)]
433pub struct HttpExporterBuilderSet(HttpExporterBuilder);
434
435#[cfg(any(feature = "http-proto", feature = "http-json"))]
436pub use crate::exporter::http::HttpExporterBuilder;
437
438#[cfg(feature = "grpc-tonic")]
439pub use crate::exporter::tonic::{TonicConfig, TonicExporterBuilder};
440
441#[cfg(feature = "serialize")]
442use serde::{Deserialize, Serialize};
443
444/// The communication protocol to use when exporting data.
445#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
446#[derive(Clone, Copy, Debug, Eq, PartialEq)]
447pub enum Protocol {
448 /// GRPC protocol
449 Grpc,
450 /// HTTP protocol with binary protobuf
451 HttpBinary,
452 /// HTTP protocol with JSON payload
453 HttpJson,
454}
455
456#[derive(Debug, Default)]
457#[doc(hidden)]
458/// Placeholder type when no exporter pipeline has been configured in telemetry pipeline.
459pub struct NoExporterConfig(());
460
461/// Re-exported types from the `tonic` crate.
462#[cfg(feature = "grpc-tonic")]
463pub mod tonic_types {
464 /// Re-exported types from `tonic::metadata`.
465 pub mod metadata {
466 #[doc(no_inline)]
467 pub use tonic::metadata::MetadataMap;
468 }
469
470 /// Re-exported types from `tonic::transport`.
471 #[cfg(any(
472 feature = "tls",
473 feature = "tls-ring",
474 feature = "tls-aws-lc",
475 feature = "tls-provider-agnostic"
476 ))]
477 pub mod transport {
478 #[doc(no_inline)]
479 pub use tonic::transport::{Certificate, ClientTlsConfig, Identity};
480 }
481}