diff --git a/linkerd/app/inbound/src/http/router/metrics.rs b/linkerd/app/inbound/src/http/router/metrics.rs index 3945eb0ae9..a472af43f7 100644 --- a/linkerd/app/inbound/src/http/router/metrics.rs +++ b/linkerd/app/inbound/src/http/router/metrics.rs @@ -18,6 +18,7 @@ use linkerd_http_prom::{ pub(super) fn layer( InboundMetrics { request_count, + request_body_data, response_body_data, .. }: &InboundMetrics, @@ -34,11 +35,16 @@ pub(super) fn layer( NewRecordResponseBodyData::layer_via(extract) }; - svc::layer::mk(move |inner| count.layer(body.layer(inner))) + let request = { + let extract = ExtractRequestBodyDataParams(request_body_data.clone()); + NewRecordRequestBodyData::new(extract) + }; + + svc::layer::mk(move |inner| count.layer(body.layer(request.layer(inner)))) } /// An `N`-typed service instrumented with metrics middleware. -type Instrumented = NewCountRequests>; +type Instrumented = NewCountRequests>>; /// An `N`-typed `NewService` instrumented with request counting metrics. type NewCountRequests = count_reqs::NewCountRequests; @@ -75,6 +81,30 @@ pub struct ResponseBodyDataLabels { #[derive(Clone, Debug)] pub struct ExtractResponseBodyDataMetrics(ResponseBodyFamilies); +/// An `N`-typed `NewService` instrumented with request body metrics. +type NewRecordRequestBodyData = body_data::request::NewRecordBodyData< + N, + ExtractRequestBodyDataParams, + ExtractRequestBodyDataMetrics, +>; + +#[derive(Clone, Debug)] +pub struct RequestBodyFamilies { + grpc: body_data::request::RequestBodyFamilies, + http: body_data::request::RequestBodyFamilies, +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub struct RequestBodyDataLabels { + route: RouteLabels, +} + +#[derive(Clone, Debug)] +pub struct ExtractRequestBodyDataParams(RequestBodyFamilies); + +#[derive(Clone, Debug)] +pub struct ExtractRequestBodyDataMetrics(BodyDataMetrics); + // === impl RequestCountFamilies === impl RequestCountFamilies { @@ -236,3 +266,95 @@ where family.metrics(&ResponseBodyDataLabels { route }) } } + +// === impl RequestBodyFamilies === + +impl RequestBodyFamilies { + /// Registers a new [`RequestBodyDataFamilies`] with the given registry. + pub fn register(reg: &mut prom::Registry) -> Self { + let grpc = { + let reg = reg.sub_registry_with_prefix("grpc"); + body_data::request::RequestBodyFamilies::register(reg) + }; + + let http = { + let reg = reg.sub_registry_with_prefix("http"); + body_data::request::RequestBodyFamilies::register(reg) + }; + + Self { grpc, http } + } + + /// Fetches the proper body frame metrics family, given a permitted target. + fn family( + &self, + variant: PermitVariant, + ) -> &body_data::request::RequestBodyFamilies { + let Self { grpc, http } = self; + match variant { + PermitVariant::Grpc => grpc, + PermitVariant::Http => http, + } + } +} + +// === impl RequestBodyDataLabels === + +impl EncodeLabelSetMut for RequestBodyDataLabels { + fn encode_label_set(&self, enc: &mut LabelSetEncoder<'_>) -> std::fmt::Result { + use encoding::EncodeLabel as _; + + let Self { + route: + RouteLabels { + server: ServerLabel(parent, port), + route, + }, + } = self; + + ("parent_group", parent.group()).encode(enc.encode_label())?; + ("parent_kind", parent.kind()).encode(enc.encode_label())?; + ("parent_name", parent.name()).encode(enc.encode_label())?; + ("parent_port", *port).encode(enc.encode_label())?; + + ("route_group", route.group()).encode(enc.encode_label())?; + ("route_kind", route.kind()).encode(enc.encode_label())?; + ("route_name", route.name()).encode(enc.encode_label())?; + + Ok(()) + } +} + +impl EncodeLabelSet for RequestBodyDataLabels { + fn encode(&self, mut enc: LabelSetEncoder<'_>) -> std::fmt::Result { + self.encode_label_set(&mut enc) + } +} + +// === impl ExtractRequestBodyDataParams === + +impl svc::ExtractParam for ExtractRequestBodyDataParams +where + T: svc::Param + svc::Param, +{ + fn extract_param(&self, target: &T) -> ExtractRequestBodyDataMetrics { + let Self(families) = self; + let variant = target.param(); + let route = target.param(); + + let family = families.family(variant); + let metrics = family.metrics(&RequestBodyDataLabels { route }); + + ExtractRequestBodyDataMetrics(metrics) + } +} + +// === impl ExtractRequestBodyDataMetrics === + +impl svc::ExtractParam for ExtractRequestBodyDataMetrics { + fn extract_param(&self, _: &T) -> BodyDataMetrics { + let Self(metrics) = self; + + metrics.clone() + } +} diff --git a/linkerd/app/inbound/src/metrics.rs b/linkerd/app/inbound/src/metrics.rs index 2bc567a9aa..1d55d8427e 100644 --- a/linkerd/app/inbound/src/metrics.rs +++ b/linkerd/app/inbound/src/metrics.rs @@ -11,7 +11,7 @@ pub(crate) mod authz; pub(crate) mod error; -use crate::http::router::{RequestCountFamilies, ResponseBodyFamilies}; +use crate::http::router::{RequestBodyFamilies, RequestCountFamilies, ResponseBodyFamilies}; pub use linkerd_app_core::metrics::*; /// Holds LEGACY inbound proxy metrics. @@ -30,6 +30,7 @@ pub struct InboundMetrics { pub detect: crate::detect::MetricsFamilies, pub direct: crate::direct::MetricsFamilies, pub request_count: RequestCountFamilies, + pub request_body_data: RequestBodyFamilies, pub response_body_data: ResponseBodyFamilies, } @@ -41,6 +42,7 @@ impl InboundMetrics { reg.sub_registry_with_prefix("tcp_transport_header"), ); let request_count = RequestCountFamilies::register(reg); + let request_body_data = RequestBodyFamilies::register(reg); let response_body_data = ResponseBodyFamilies::register(reg); Self { @@ -52,6 +54,7 @@ impl InboundMetrics { detect, direct, request_count, + request_body_data, response_body_data, } }