Use trace-request for dropshot instrumentation

This commit is contained in:
Daniel Lundin 2024-12-16 23:36:33 +01:00
parent da210ffc16
commit 31c8921aca
Signed by: dln
SSH key fingerprint: SHA256:dQy1Xj3UiqJYpKR5ggQ2bxgz4jCH8IF+k3AB8o0kmdI
13 changed files with 246 additions and 36 deletions
trace-request

18
trace-request/Cargo.toml Normal file
View file

@ -0,0 +1,18 @@
[package]
name = "trace-request"
version = "0.1.0"
edition = "2021"
license = "MPL-2.0"
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "1"
quote = "1"
syn = { version = "2.0", features = ["full"] }
[dev-dependencies]
dropshot = { workspace = true }
http = { workspace = true }
tracing = { workspace = true }

79
trace-request/src/lib.rs Normal file
View file

@ -0,0 +1,79 @@
// Original source: https://github.com/oxidecomputer/rfd-api/blob/main/trace-request/src/lib.rs
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
#![allow(dead_code, unused_imports)]
extern crate proc_macro;
#[macro_use]
extern crate quote;
use std::result::Iter;
use proc_macro::TokenStream;
use proc_macro2::{Delimiter, Group, Span, TokenTree};
use quote::ToTokens;
use syn::{
bracketed,
parse::{Parse, ParseStream, Parser},
parse_macro_input,
punctuated::Punctuated,
Block, DeriveInput, Ident, ItemFn, LitStr, Result, Token, Type,
};
#[proc_macro_attribute]
pub fn trace_request(_attr: TokenStream, input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as ItemFn);
let body_block = input.block;
let fn_name = &input.sig.ident;
let token_stream = quote! {
{
use tracing::Instrument;
fn get_status<T>(res: &Result<T, HttpError>) -> http::StatusCode where T: dropshot::HttpCodedResponse {
match res {
Ok(_) => T::STATUS_CODE,
Err(err) => err.status_code.as_status(),
}
}
let request_id = &rqctx.request_id;
let req = &rqctx.request;
async {
let result = async #body_block.await;
let status = get_status(&result);
let span = tracing::Span::current();
span.record("http.status", &status.as_str());
if let Err(err) = &result {
span.record("error.external", &err.external_message);
span.record("error.internal", &err.internal_message);
}
result
}.instrument(
tracing::info_span!(
stringify!(handler.#fn_name),
"request.id" = request_id,
"http.method" = req.method().as_str(),
"http.uri" = req.uri().to_string(),
"http.status" = tracing::field::Empty,
"error.external" = tracing::field::Empty,
"error.internal" = tracing::field::Empty
)
).await
}
};
let wrapped_body_block: TokenStream = token_stream.into();
input.block = Box::new(parse_macro_input!(wrapped_body_block as Block));
quote! {
#input
}
.into()
}