mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-13 08:22:55 +00:00
## Problem `cargo +nightly doc` is giving a lot of warnings: broken links, naked URLs, etc. ## Summary of changes * update the `proc-macro2` dependency so that it can compile on latest Rust nightly, see https://github.com/dtolnay/proc-macro2/pull/391 and https://github.com/dtolnay/proc-macro2/issues/398 * allow the `private_intra_doc_links` lint, as linking to something that's private is always more useful than just mentioning it without a link: if the link breaks in the future, at least there is a warning due to that. Also, one might enable [`--document-private-items`](https://doc.rust-lang.org/cargo/commands/cargo-doc.html#documentation-options) in the future and make these links work in general. * fix all the remaining warnings given by `cargo +nightly doc` * make it possible to run `cargo doc` on stable Rust by updating `opentelemetry` and associated crates to version 0.19, pulling in a fix that previously broke `cargo doc` on stable: https://github.com/open-telemetry/opentelemetry-rust/pull/904 * Add `cargo doc` to CI to ensure that it won't get broken in the future. Fixes #2557 ## Future work * Potentially, it might make sense, for development purposes, to publish the generated rustdocs somewhere, like for example [how the rust compiler does it](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/index.html). I will file an issue for discussion.
97 lines
3.4 KiB
Rust
97 lines
3.4 KiB
Rust
//! Tracing wrapper for Hyper HTTP server
|
|
|
|
use hyper::HeaderMap;
|
|
use hyper::{Body, Request, Response};
|
|
use std::future::Future;
|
|
use tracing::Instrument;
|
|
use tracing_opentelemetry::OpenTelemetrySpanExt;
|
|
|
|
/// Configuration option for what to use as the "otel.name" field in the traces.
|
|
pub enum OtelName<'a> {
|
|
/// Use a constant string
|
|
Constant(&'a str),
|
|
|
|
/// Use the path from the request.
|
|
///
|
|
/// That's very useful information, but is not appropriate if the
|
|
/// path contains parameters that differ on ever request, or worse,
|
|
/// sensitive information like usernames or email addresses.
|
|
///
|
|
/// See <https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#name>
|
|
UriPath,
|
|
}
|
|
|
|
/// Handle an incoming HTTP request using the given handler function,
|
|
/// with OpenTelemetry tracing.
|
|
///
|
|
/// This runs 'handler' on the request in a new span, with fields filled in
|
|
/// from the request. Notably, if the request contains tracing information,
|
|
/// it is propagated to the span, so that this request is traced as part of
|
|
/// the same trace.
|
|
///
|
|
/// XXX: Usually, this is handled by existing libraries, or built
|
|
/// directly into HTTP servers. However, I couldn't find one for Hyper,
|
|
/// so I had to write our own. OpenTelemetry website has a registry of
|
|
/// instrumentation libraries at:
|
|
/// <https://opentelemetry.io/registry/?language=rust&component=instrumentation>
|
|
/// If a Hyper crate appears, consider switching to that.
|
|
pub async fn tracing_handler<F, R>(
|
|
req: Request<Body>,
|
|
handler: F,
|
|
otel_name: OtelName<'_>,
|
|
) -> Response<Body>
|
|
where
|
|
F: Fn(Request<Body>) -> R,
|
|
R: Future<Output = Response<Body>>,
|
|
{
|
|
// Create a tracing span, with context propagated from the incoming
|
|
// request if any.
|
|
//
|
|
// See list of standard fields defined for HTTP requests at
|
|
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md
|
|
// We only fill in a few of the most useful ones here.
|
|
let otel_name = match otel_name {
|
|
OtelName::Constant(s) => s,
|
|
OtelName::UriPath => req.uri().path(),
|
|
};
|
|
|
|
let span = tracing::info_span!(
|
|
"http request",
|
|
otel.name= %otel_name,
|
|
http.method = %req.method(),
|
|
http.status_code = tracing::field::Empty,
|
|
);
|
|
let parent_ctx = extract_remote_context(req.headers());
|
|
span.set_parent(parent_ctx);
|
|
|
|
// Handle the request within the span
|
|
let response = handler(req).instrument(span.clone()).await;
|
|
|
|
// Fill in the fields from the response code
|
|
let status = response.status();
|
|
span.record("http.status_code", status.as_str());
|
|
span.record(
|
|
"otel.status_code",
|
|
if status.is_success() { "OK" } else { "ERROR" },
|
|
);
|
|
|
|
response
|
|
}
|
|
|
|
// Extract remote tracing context from the HTTP headers
|
|
fn extract_remote_context(headers: &HeaderMap) -> opentelemetry::Context {
|
|
struct HeaderExtractor<'a>(&'a HeaderMap);
|
|
|
|
impl<'a> opentelemetry::propagation::Extractor for HeaderExtractor<'a> {
|
|
fn get(&self, key: &str) -> Option<&str> {
|
|
self.0.get(key).and_then(|value| value.to_str().ok())
|
|
}
|
|
|
|
fn keys(&self) -> Vec<&str> {
|
|
self.0.keys().map(|value| value.as_str()).collect()
|
|
}
|
|
}
|
|
let extractor = HeaderExtractor(headers);
|
|
opentelemetry::global::get_text_map_propagator(|propagator| propagator.extract(&extractor))
|
|
}
|