opentelemetry_instrumentation_actix_web/lib.rs
1//! [OpenTelemetry] instrumentation for [Actix Web].
2//!
3//! This crate allows you to easily instrument client and server requests.
4//!
5//! * Server requests can be traced by using the [`RequestTracing`] middleware.
6//!
7//! The `awc` feature allows you to instrument client requests made by the [awc] crate.
8//!
9//! * Client requests can be traced by using the [`ClientExt::trace_request`] method.
10//!
11//! The `metrics` feature allows you to export request metrics to any OTLP supported
12//! backend like [Prometheus].
13//!
14//! * Metrics can be tracked using the [`RequestMetrics`] middleware.
15//!
16//! [OpenTelemetry]: https://opentelemetry.io
17//! [Actix Web]: https://actix.rs
18//! [awc]: https://docs.rs/awc
19//! [Prometheus]: https://prometheus.io
20//!
21//! ### Client Request Examples:
22//!
23//! Note: this requires the `awc` feature to be enabled.
24//!
25//! ```no_run
26//! # #[cfg(feature="awc")]
27//! # {
28//! use awc::{Client, error::SendRequestError};
29//! use opentelemetry_instrumentation_actix_web::ClientExt;
30//!
31//! async fn execute_request(client: &Client) -> Result<(), SendRequestError> {
32//! let res = client
33//! .get("http://localhost:8080")
34//! // Add `trace_request` before `send` to any awc request to add instrumentation
35//! .trace_request()
36//! .send()
37//! .await?;
38//!
39//! println!("Response: {:?}", res);
40//! Ok(())
41//! }
42//! # }
43//! ```
44//!
45//! ### Server middleware examples:
46//!
47//! Tracing and metrics middleware can be used together or independently.
48//!
49//! Tracing server example:
50//!
51//! ```no_run
52//! use actix_web::{web, App, HttpServer};
53//! use opentelemetry::global;
54//! use opentelemetry_instrumentation_actix_web::RequestTracing;
55//! use opentelemetry_sdk::trace::SdkTracerProvider;
56//!
57//! async fn index() -> &'static str {
58//! "Hello world!"
59//! }
60//!
61//! #[actix_web::main]
62//! async fn main() -> std::io::Result<()> {
63//! // Swap for `opentelemetry_otlp` or any other compatible
64//! // exporter to send metrics to your collector.
65//! let exporter = opentelemetry_stdout::SpanExporter::default();
66//!
67//! // Configure your tracer provider with your exporter(s)
68//! let provider = SdkTracerProvider::builder()
69//! .with_simple_exporter(exporter)
70//! .build();
71//! global::set_tracer_provider(provider);
72//!
73//! // add the request tracing middleware to create spans for each request
74//! HttpServer::new(|| {
75//! App::new()
76//! .wrap(RequestTracing::new())
77//! .service(web::resource("/").to(index))
78//! })
79//! .bind("127.0.0.1:8080")?
80//! .run()
81//! .await
82//! }
83//! ```
84//!
85//! Request metrics middleware (requires the `metrics` feature):
86//!
87//! ```no_run
88//! use actix_web::{dev, http, web, App, HttpRequest, HttpServer};
89//! use opentelemetry::{global, KeyValue};
90//! # #[cfg(feature = "metrics")]
91//! use opentelemetry_instrumentation_actix_web::{RequestMetrics, RequestTracing};
92//! use opentelemetry_sdk::{metrics::SdkMeterProvider, Resource};
93//!
94//! async fn index() -> &'static str {
95//! "Hello world!"
96//! }
97//!
98//! # #[cfg(feature = "metrics")]
99//! #[actix_web::main]
100//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
101//! // Swap for `opentelemetry_otlp` or any other compatible
102//! // exporter to send metrics to your collector.
103//! let exporter = opentelemetry_stdout::MetricExporter::default();
104//!
105//! // set up your meter provider with your exporter(s)
106//! let provider = SdkMeterProvider::builder()
107//! .with_periodic_exporter(exporter)
108//! .with_resource(
109//! Resource::builder_empty()
110//! .with_attribute(KeyValue::new("service.name", "my_app"))
111//! .build(),
112//! )
113//! .build();
114//! global::set_meter_provider(provider.clone());
115//!
116//! // Run actix server, metrics are now available at http://localhost:8080/metrics
117//! HttpServer::new(move || {
118//! App::new()
119//! .wrap(RequestTracing::new())
120//! .wrap(RequestMetrics::default())
121//! .service(web::resource("/").to(index))
122//! })
123//! .bind("localhost:8080")?
124//! .run()
125//! .await;
126//!
127//! //Shutdown the meter provider. This will trigger an export of all metrics.
128//! provider.shutdown()?;
129//!
130//! Ok(())
131//! }
132//! # #[cfg(not(feature = "metrics"))]
133//! # fn main() {}
134//! ```
135//!
136//! For more information on how to configure Prometheus with [OTLP](https://prometheus.io/docs/guides/opentelemetry)
137//!
138//! ### Exporter configuration
139//!
140//! [`actix-web`] uses [`tokio`] as the underlying executor, so exporters should be
141//! configured to be non-blocking:
142//!
143//! ```toml
144//! [dependencies]
145//! ## if exporting to jaeger, use the `tokio` feature.
146//! opentelemetry-jaeger = { version = "..", features = ["rt-tokio-current-thread"] }
147//!
148//! ## if exporting to zipkin, use the `tokio` based `reqwest-client` feature.
149//! opentelemetry-zipkin = { version = "..", features = ["reqwest-client"], default-features = false }
150//!
151//! ## ... ensure the same same for any other exporters
152//! ```
153//!
154//! [`actix-web`]: https://crates.io/crates/actix-web
155//! [`tokio`]: https://crates.io/crates/tokio
156#![deny(missing_docs, unreachable_pub, missing_debug_implementations)]
157#![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))]
158
159#[cfg(feature = "awc")]
160mod client;
161mod middleware;
162mod util;
163
164#[cfg(feature = "awc")]
165#[cfg_attr(docsrs, doc(cfg(feature = "awc")))]
166pub use client::{ClientExt, InstrumentedClientRequest};
167
168#[cfg(feature = "metrics")]
169#[cfg_attr(docsrs, doc(cfg(feature = "metrics")))]
170pub use middleware::metrics::{RequestMetrics, RequestMetricsBuilder, RequestMetricsMiddleware};
171#[cfg(feature = "metrics")]
172#[cfg_attr(docsrs, doc(cfg(feature = "metrics")))]
173pub use util::metrics_attributes_from_request;
174
175pub use {
176 middleware::route_formatter::RouteFormatter,
177 middleware::trace::{RequestTracing, RequestTracingMiddleware},
178};