reqwest_datadog_tracing/
lib.rs

1// MIT License
2//
3// Copyright (c) 2021 TrueLayer
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23//! Opentracing middleware implementation for [`reqwest_middleware`].
24//!
25//! Attach [`TracingMiddleware`] to your client to automatically trace HTTP requests.
26//!
27//! The simplest possible usage:
28//! ```no_run
29//! # use reqwest_middleware::Result;
30//! use reqwest_middleware::{ClientBuilder};
31//! use reqwest_datadog_tracing::TracingMiddleware;
32//!
33//! # async fn example() -> Result<()> {
34//! let reqwest_client = reqwest::Client::builder().build().unwrap();
35//! let client = ClientBuilder::new(reqwest_client)
36//!    // Insert the tracing middleware
37//!    .with(TracingMiddleware::default())
38//!    .build();
39//!
40//! let resp = client.get("https://truelayer.com").send().await.unwrap();
41//! # Ok(())
42//! # }
43//! ```
44//!
45//! To customise the span names use [`OtelName`].
46//! ```no_run
47//! # use reqwest_middleware::Result;
48//! use reqwest_middleware::{ClientBuilder, Extension};
49//! use reqwest_datadog_tracing::{
50//!     TracingMiddleware, OtelName
51//! };
52//! # async fn example() -> Result<()> {
53//! let reqwest_client = reqwest::Client::builder().build().unwrap();
54//! let client = ClientBuilder::new(reqwest_client)
55//!    // Inserts the extension before the request is started
56//!    .with_init(Extension(OtelName("my-client".into())))
57//!    // Makes use of that extension to specify the otel name
58//!    .with(TracingMiddleware::default())
59//!    .build();
60//!
61//! let resp = client.get("https://truelayer.com").send().await.unwrap();
62//!
63//! // Or specify it on the individual request (will take priority)
64//! let resp = client.post("https://api.truelayer.com/payment")
65//!     .with_extension(OtelName("POST /payment".into()))
66//!    .send()
67//!    .await
68//!    .unwrap();
69//! # Ok(())
70//! # }
71//! ```
72//!
73//! In this example we define a custom span builder to calculate the request time elapsed and we register the [`TracingMiddleware`].
74//!
75//! Note that Opentelemetry tracks start and stop already, there is no need to have a custom builder like this.
76//! ```rust
77//! use reqwest_middleware::Result;
78//! use http::Extensions;
79//! use reqwest::{Request, Response};
80//! use reqwest_middleware::ClientBuilder;
81//! use reqwest_datadog_tracing::{
82//!     default_on_request_end, reqwest_otel_span, ReqwestOtelSpanBackend, TracingMiddleware
83//! };
84//! use tracing::Span;
85//! use std::time::{Duration, Instant};
86//!
87//! pub struct TimeTrace;
88//!
89//! impl ReqwestOtelSpanBackend for TimeTrace {
90//!     fn on_request_start(req: &Request, extension: &mut Extensions) -> Span {
91//!         extension.insert(Instant::now());
92//!         reqwest_otel_span!(name="example-request", req, time_elapsed = tracing::field::Empty)
93//!     }
94//!
95//!     fn on_request_end(span: &Span, outcome: &Result<Response>, extension: &mut Extensions) {
96//!         let time_elapsed = extension.get::<Instant>().unwrap().elapsed().as_millis() as i64;
97//!         default_on_request_end(span, outcome);
98//!         span.record("time_elapsed", &time_elapsed);
99//!     }
100//! }
101//!
102//! let http = ClientBuilder::new(reqwest::Client::new())
103//!     .with(TracingMiddleware::<TimeTrace>::new())
104//!     .build();
105//! ```
106
107mod middleware;
108#[cfg(any(feature = "opentelemetry_0_30",))]
109mod otel;
110mod reqwest_otel_span_builder;
111pub use middleware::TracingMiddleware;
112pub use reqwest_otel_span_builder::{
113    DefaultSpanBackend, DisableOtelPropagation, ERROR_CAUSE_CHAIN, ERROR_MESSAGE,
114    HTTP_REQUEST_METHOD, HTTP_RESPONSE_STATUS_CODE, OTEL_KIND, OTEL_NAME, OTEL_STATUS_CODE,
115    OtelName, OtelPathNames, ReqwestOtelSpanBackend, SERVER_ADDRESS, SERVER_PORT,
116    SpanBackendWithUrl, URL_FULL, URL_SCHEME, USER_AGENT_ORIGINAL, default_on_request_end,
117    default_on_request_failure, default_on_request_success, default_span_name,
118};
119
120#[cfg(feature = "deprecated_attributes")]
121pub use reqwest_otel_span_builder::{
122    HTTP_HOST, HTTP_METHOD, HTTP_SCHEME, HTTP_STATUS_CODE, HTTP_URL, HTTP_USER_AGENT, NET_HOST_PORT,
123};
124
125#[doc(hidden)]
126pub mod reqwest_otel_span_macro;