1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
//! [OpenTelemetry] integration for [Actix Web].
//!
//! This crate allows you to easily instrument client and server requests.
//!
//! * Server requests can be traced by using the [`RequestTracing`] middleware.
//!
//! The `awc` feature allows you to instrument client requests made by the [awc] crate.
//!
//! * Client requests can be traced by using the [`ClientExt::trace_request`] method.
//!
//! The `metrics` feature allows you to expose request metrics to [Prometheus].
//!
//! * Metrics can be tracked using the [`RequestMetrics`] middleware.
//!
//! [OpenTelemetry]: https://opentelemetry.io
//! [Actix Web]: https://actix.rs
//! [awc]: https://docs.rs/awc
//! [Prometheus]: https://prometheus.io
//!
//! ### Client Request Examples:
//!
//! Note: this requires the `awc` feature to be enabled.
//!
//! ```no_run
//! # #[cfg(feature="awc")]
//! # {
//! use awc::{Client, error::SendRequestError};
//! use actix_web_opentelemetry::ClientExt;
//!
//! async fn execute_request(client: &Client) -> Result<(), SendRequestError> {
//! let res = client
//! .get("http://localhost:8080")
//! // Add `trace_request` before `send` to any awc request to add instrumentation
//! .trace_request()
//! .send()
//! .await?;
//!
//! println!("Response: {:?}", res);
//! Ok(())
//! }
//! # }
//! ```
//!
//! ### Server middleware examples:
//!
//! Tracing and metrics middleware can be used together or independently.
//!
//! Tracing server example:
//!
//! ```no_run
//! use actix_web::{web, App, HttpServer};
//! use actix_web_opentelemetry::RequestTracing;
//!
//! async fn index() -> &'static str {
//! "Hello world!"
//! }
//!
//! #[actix_web::main]
//! async fn main() -> std::io::Result<()> {
//! // Install an OpenTelemetry trace pipeline.
//! // Swap for https://docs.rs/opentelemetry-jaeger or other compatible
//! // exporter to send trace information to your collector.
//! opentelemetry::sdk::export::trace::stdout::new_pipeline().install_simple();
//!
//! HttpServer::new(|| {
//! App::new()
//! .wrap(RequestTracing::new())
//! .service(web::resource("/").to(index))
//! })
//! .bind("127.0.0.1:8080")?
//! .run()
//! .await
//! }
//! ```
//!
//! Request metrics middleware (requires the `metrics` feature):
//!
//! ```no_run
//! use actix_web::{dev, http, web, App, HttpRequest, HttpServer};
//! # #[cfg(feature = "metrics-prometheus")]
//! use actix_web_opentelemetry::{PrometheusMetricsHandler, RequestMetricsBuilder, RequestTracing};
//! use opentelemetry::{
//! global,
//! sdk::{
//! export::metrics::aggregation,
//! metrics::{controllers, processors, selectors},
//! propagation::TraceContextPropagator,
//! },
//! };
//!
//! # #[cfg(feature = "metrics-prometheus")]
//! #[actix_web::main]
//! async fn main() -> std::io::Result<()> {
//! let controller = controllers::basic(
//! processors::factory(
//! selectors::simple::histogram([1.0, 2.0, 5.0, 10.0, 20.0, 50.0]),
//! aggregation::cumulative_temporality_selector(),
//! )
//! .with_memory(true),
//! )
//! .build();
//! let exporter = opentelemetry_prometheus::exporter(controller).init();
//! let meter = global::meter("actix_web");
//!
//! // Request metrics middleware
//! let request_metrics = RequestMetricsBuilder::new().build(meter);
//!
//! // Run actix server, metrics are now available at http://localhost:8080/metrics
//! HttpServer::new(move || {
//! App::new()
//! .wrap(RequestTracing::new())
//! .wrap(request_metrics.clone())
//! .route("/metrics", web::get().to(PrometheusMetricsHandler::new(exporter.clone())))
//! })
//! .bind("localhost:8080")?
//! .run()
//! .await
//! }
//! # #[cfg(not(feature = "metrics-prometheus"))]
//! # fn main() {}
//! ```
//!
//! ### Exporter configuration
//!
//! [`actix-web`] uses [`tokio`] as the underlying executor, so exporters should be
//! configured to be non-blocking:
//!
//! ```toml
//! [dependencies]
//! ## if exporting to jaeger, use the `tokio` feature.
//! opentelemetry-jaeger = { version = "..", features = ["rt-tokio-current-thread"] }
//!
//! ## if exporting to zipkin, use the `tokio` based `reqwest-client` feature.
//! opentelemetry-zipkin = { version = "..", features = ["reqwest-client"], default-features = false }
//!
//! ## ... ensure the same same for any other exporters
//! ```
//!
//! [`actix-web`]: https://crates.io/crates/actix-web
//! [`tokio`]: https://crates.io/crates/tokio
#![deny(missing_docs, unreachable_pub, missing_debug_implementations)]
#![cfg_attr(test, deny(warnings))]
#![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))]
#[cfg(feature = "awc")]
mod client;
mod middleware;
pub(crate) mod util;
#[cfg(feature = "awc")]
#[cfg_attr(docsrs, doc(cfg(feature = "awc")))]
pub use client::{ClientExt, InstrumentedClientRequest};
#[cfg(feature = "metrics-prometheus")]
#[cfg_attr(docsrs, doc(cfg(feature = "metrics-prometheus")))]
pub use middleware::metrics::prometheus::PrometheusMetricsHandler;
#[cfg(feature = "metrics")]
#[cfg_attr(docsrs, doc(cfg(feature = "metrics")))]
pub use middleware::metrics::{RequestMetrics, RequestMetricsBuilder, RequestMetricsMiddleware};
pub use {
middleware::route_formatter::RouteFormatter,
middleware::trace::{RequestTracing, RequestTracingMiddleware},
};