1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-31 09:24:31 +03:00

Have the listeners names in the metrics and traces

Also refactors the OTEL layer to have a separate metrics logic
This commit is contained in:
Quentin Gliech
2022-10-05 13:19:21 +02:00
parent c548417752
commit 7e288c0c5d
9 changed files with 360 additions and 110 deletions

View File

@ -1,12 +1,15 @@
use std::sync::Arc;
use opentelemetry::metrics::{Counter, Histogram, UpDownCounter};
use opentelemetry::{
metrics::{Counter, Histogram, UpDownCounter},
KeyValue,
};
use tower::Layer;
use super::{
extract_context::DefaultExtractContext, inject_context::DefaultInjectContext,
make_span_builder::DefaultMakeSpanBuilder, on_error::DefaultOnError,
on_response::DefaultOnResponse, service::Trace,
make_metrics_labels::DefaultMakeMetricsLabels, make_span_builder::DefaultMakeSpanBuilder,
on_error::DefaultOnError, on_response::DefaultOnResponse, service::Trace,
};
#[derive(Debug, Clone)]
@ -14,6 +17,7 @@ pub struct TraceLayer<
ExtractContext = DefaultExtractContext,
InjectContext = DefaultInjectContext,
MakeSpanBuilder = DefaultMakeSpanBuilder,
MakeMetricsLabels = DefaultMakeMetricsLabels,
OnResponse = DefaultOnResponse,
OnError = DefaultOnError,
> {
@ -21,12 +25,14 @@ pub struct TraceLayer<
extract_context: ExtractContext,
inject_context: InjectContext,
make_span_builder: MakeSpanBuilder,
make_metrics_labels: MakeMetricsLabels,
on_response: OnResponse,
on_error: OnError,
inflight_requests: UpDownCounter<i64>,
request_counter: Counter<u64>,
request_histogram: Histogram<f64>,
static_attributes: Vec<KeyValue>,
}
impl Default for TraceLayer {
@ -63,8 +69,15 @@ impl TraceLayer {
}
}
impl<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError>
TraceLayer<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError>
impl<ExtractContext, InjectContext, MakeSpanBuilder, MakeMetricsLabels, OnResponse, OnError>
TraceLayer<
ExtractContext,
InjectContext,
MakeSpanBuilder,
MakeMetricsLabels,
OnResponse,
OnError,
>
{
#[must_use]
pub fn new(
@ -77,6 +90,7 @@ impl<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError>
ExtractContext: Default,
InjectContext: Default,
MakeSpanBuilder: Default,
MakeMetricsLabels: Default,
OnResponse: Default,
OnError: Default,
{
@ -85,29 +99,55 @@ impl<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError>
extract_context: ExtractContext::default(),
inject_context: InjectContext::default(),
make_span_builder: MakeSpanBuilder::default(),
make_metrics_labels: MakeMetricsLabels::default(),
on_response: OnResponse::default(),
on_error: OnError::default(),
inflight_requests,
request_counter,
request_histogram,
static_attributes: Vec::new(),
}
}
#[must_use]
pub fn with_static_attribute(mut self, attribute: KeyValue) -> Self {
self.static_attributes.push(attribute);
self
}
#[must_use]
pub fn with_static_attributes(
mut self,
attributes: impl IntoIterator<Item = KeyValue>,
) -> Self {
self.static_attributes.extend(attributes);
self
}
#[must_use]
pub fn extract_context<NewExtractContext>(
self,
extract_context: NewExtractContext,
) -> TraceLayer<NewExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError> {
) -> TraceLayer<
NewExtractContext,
InjectContext,
MakeSpanBuilder,
MakeMetricsLabels,
OnResponse,
OnError,
> {
TraceLayer {
tracer: self.tracer,
extract_context,
inject_context: self.inject_context,
make_span_builder: self.make_span_builder,
make_metrics_labels: self.make_metrics_labels,
on_response: self.on_response,
on_error: self.on_error,
inflight_requests: self.inflight_requests,
request_counter: self.request_counter,
request_histogram: self.request_histogram,
static_attributes: self.static_attributes,
}
}
@ -115,17 +155,26 @@ impl<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError>
pub fn inject_context<NewInjectContext>(
self,
inject_context: NewInjectContext,
) -> TraceLayer<ExtractContext, NewInjectContext, MakeSpanBuilder, OnResponse, OnError> {
) -> TraceLayer<
ExtractContext,
NewInjectContext,
MakeSpanBuilder,
MakeMetricsLabels,
OnResponse,
OnError,
> {
TraceLayer {
tracer: self.tracer,
extract_context: self.extract_context,
inject_context,
make_span_builder: self.make_span_builder,
make_metrics_labels: self.make_metrics_labels,
on_response: self.on_response,
on_error: self.on_error,
inflight_requests: self.inflight_requests,
request_counter: self.request_counter,
request_histogram: self.request_histogram,
static_attributes: self.static_attributes,
}
}
@ -133,17 +182,53 @@ impl<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError>
pub fn make_span_builder<NewMakeSpanBuilder>(
self,
make_span_builder: NewMakeSpanBuilder,
) -> TraceLayer<ExtractContext, InjectContext, NewMakeSpanBuilder, OnResponse, OnError> {
) -> TraceLayer<
ExtractContext,
InjectContext,
NewMakeSpanBuilder,
MakeMetricsLabels,
OnResponse,
OnError,
> {
TraceLayer {
tracer: self.tracer,
extract_context: self.extract_context,
inject_context: self.inject_context,
make_span_builder,
make_metrics_labels: self.make_metrics_labels,
on_response: self.on_response,
on_error: self.on_error,
inflight_requests: self.inflight_requests,
request_counter: self.request_counter,
request_histogram: self.request_histogram,
static_attributes: self.static_attributes,
}
}
#[must_use]
pub fn make_metrics_labels<NewMakeMetricsLabels>(
self,
make_metrics_labels: NewMakeMetricsLabels,
) -> TraceLayer<
ExtractContext,
InjectContext,
MakeSpanBuilder,
NewMakeMetricsLabels,
OnResponse,
OnError,
> {
TraceLayer {
tracer: self.tracer,
extract_context: self.extract_context,
inject_context: self.inject_context,
make_span_builder: self.make_span_builder,
make_metrics_labels,
on_response: self.on_response,
on_error: self.on_error,
inflight_requests: self.inflight_requests,
request_counter: self.request_counter,
request_histogram: self.request_histogram,
static_attributes: self.static_attributes,
}
}
@ -151,17 +236,26 @@ impl<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError>
pub fn on_response<NewOnResponse>(
self,
on_response: NewOnResponse,
) -> TraceLayer<ExtractContext, InjectContext, MakeSpanBuilder, NewOnResponse, OnError> {
) -> TraceLayer<
ExtractContext,
InjectContext,
MakeSpanBuilder,
MakeMetricsLabels,
NewOnResponse,
OnError,
> {
TraceLayer {
tracer: self.tracer,
extract_context: self.extract_context,
inject_context: self.inject_context,
make_span_builder: self.make_span_builder,
make_metrics_labels: self.make_metrics_labels,
on_response,
on_error: self.on_error,
inflight_requests: self.inflight_requests,
request_counter: self.request_counter,
request_histogram: self.request_histogram,
static_attributes: self.static_attributes,
}
}
@ -169,31 +263,57 @@ impl<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError>
pub fn on_error<NewOnError>(
self,
on_error: NewOnError,
) -> TraceLayer<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, NewOnError> {
) -> TraceLayer<
ExtractContext,
InjectContext,
MakeSpanBuilder,
MakeMetricsLabels,
OnResponse,
NewOnError,
> {
TraceLayer {
tracer: self.tracer,
extract_context: self.extract_context,
inject_context: self.inject_context,
make_span_builder: self.make_span_builder,
make_metrics_labels: self.make_metrics_labels,
on_response: self.on_response,
on_error,
inflight_requests: self.inflight_requests,
request_counter: self.request_counter,
request_histogram: self.request_histogram,
static_attributes: self.static_attributes,
}
}
}
impl<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError, S> Layer<S>
for TraceLayer<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError>
impl<ExtractContext, InjectContext, MakeSpanBuilder, MakeMetricsLabels, OnResponse, OnError, S>
Layer<S>
for TraceLayer<
ExtractContext,
InjectContext,
MakeSpanBuilder,
MakeMetricsLabels,
OnResponse,
OnError,
>
where
ExtractContext: Clone,
InjectContext: Clone,
MakeSpanBuilder: Clone,
MakeMetricsLabels: Clone,
OnResponse: Clone,
OnError: Clone,
{
type Service = Trace<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError, S>;
type Service = Trace<
ExtractContext,
InjectContext,
MakeSpanBuilder,
MakeMetricsLabels,
OnResponse,
OnError,
S,
>;
fn layer(&self, inner: S) -> Self::Service {
Trace::new(
@ -202,11 +322,13 @@ where
self.extract_context.clone(),
self.inject_context.clone(),
self.make_span_builder.clone(),
self.make_metrics_labels.clone(),
self.on_response.clone(),
self.on_error.clone(),
self.inflight_requests.clone(),
self.request_counter.clone(),
self.request_histogram.clone(),
self.static_attributes.clone(),
)
}
}

View File

@ -0,0 +1,61 @@
// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::borrow::Cow;
use http::Request;
use opentelemetry::KeyValue;
use super::utils::http_method_str;
pub trait MakeMetricsLabels<R> {
fn make_metrics_labels(&self, request: &R) -> Vec<KeyValue>;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct DefaultMakeMetricsLabels;
impl<R> MakeMetricsLabels<R> for DefaultMakeMetricsLabels {
fn make_metrics_labels(&self, _request: &R) -> Vec<KeyValue> {
Vec::new()
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct MetricsLabelsFromHttpRequest;
impl<B> MakeMetricsLabels<Request<B>> for MetricsLabelsFromHttpRequest {
fn make_metrics_labels(&self, request: &Request<B>) -> Vec<KeyValue> {
vec![KeyValue::new("method", http_method_str(request.method()))]
}
}
#[cfg(feature = "axum")]
#[derive(Debug, Clone, Copy, Default)]
pub struct MetricsLabelsFromAxumRequest;
#[cfg(feature = "axum")]
impl<B> MakeMetricsLabels<Request<B>> for MetricsLabelsFromAxumRequest {
fn make_metrics_labels(&self, request: &Request<B>) -> Vec<KeyValue> {
let path: Cow<'static, str> = request
.extensions()
.get::<axum::extract::MatchedPath>()
.map_or("FALLBACK".into(), |path| path.as_str().to_owned().into());
vec![
KeyValue::new("method", http_method_str(request.method())),
KeyValue::new("route", path),
]
}
}

View File

@ -12,22 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::{borrow::Cow, vec::Vec};
use std::borrow::Cow;
#[cfg(feature = "axum")]
use axum::extract::{ConnectInfo, MatchedPath};
use headers::{ContentLength, HeaderMapExt, Host, UserAgent};
use http::{Method, Request, Version};
use http::Request;
#[cfg(feature = "client")]
use hyper::client::connect::dns::Name;
use opentelemetry::{
trace::{SpanBuilder, SpanKind},
KeyValue,
};
use opentelemetry::trace::{SpanBuilder, SpanKind};
use opentelemetry_semantic_conventions::trace as SC;
use super::utils::{http_flavor, http_method_str};
pub trait MakeSpanBuilder<R> {
fn make_span_builder(&self, request: &R) -> (SpanBuilder, Vec<KeyValue>);
fn make_span_builder(&self, request: &R) -> SpanBuilder;
}
#[derive(Debug, Clone, Copy)]
@ -51,36 +50,8 @@ impl Default for DefaultMakeSpanBuilder {
}
impl<R> MakeSpanBuilder<R> for DefaultMakeSpanBuilder {
fn make_span_builder(&self, _request: &R) -> (SpanBuilder, Vec<KeyValue>) {
(SpanBuilder::from_name(self.operation), Vec::new())
}
}
#[inline]
fn http_method_str(method: &Method) -> Cow<'static, str> {
match method {
&Method::OPTIONS => "OPTIONS".into(),
&Method::GET => "GET".into(),
&Method::POST => "POST".into(),
&Method::PUT => "PUT".into(),
&Method::DELETE => "DELETE".into(),
&Method::HEAD => "HEAD".into(),
&Method::TRACE => "TRACE".into(),
&Method::CONNECT => "CONNECT".into(),
&Method::PATCH => "PATCH".into(),
other => other.to_string().into(),
}
}
#[inline]
fn http_flavor(version: Version) -> Cow<'static, str> {
match version {
Version::HTTP_09 => "0.9".into(),
Version::HTTP_10 => "1.0".into(),
Version::HTTP_11 => "1.1".into(),
Version::HTTP_2 => "2.0".into(),
Version::HTTP_3 => "3.0".into(),
other => format!("{:?}", other).into(),
fn make_span_builder(&self, _request: &R) -> SpanBuilder {
SpanBuilder::from_name(self.operation)
}
}
@ -117,10 +88,9 @@ impl SpanFromHttpRequest {
}
impl<B> MakeSpanBuilder<Request<B>> for SpanFromHttpRequest {
fn make_span_builder(&self, request: &Request<B>) -> (SpanBuilder, Vec<KeyValue>) {
let method = SC::HTTP_METHOD.string(http_method_str(request.method()));
fn make_span_builder(&self, request: &Request<B>) -> SpanBuilder {
let mut attributes = vec![
method.clone(),
SC::HTTP_METHOD.string(http_method_str(request.method())),
SC::HTTP_FLAVOR.string(http_flavor(request.version())),
SC::HTTP_TARGET.string(request.uri().to_string()),
];
@ -141,12 +111,9 @@ impl<B> MakeSpanBuilder<Request<B>> for SpanFromHttpRequest {
}
}
let span_builder = SpanBuilder::from_name(self.operation)
SpanBuilder::from_name(self.operation)
.with_kind(self.span_kind.clone())
.with_attributes(attributes);
let metrics_labels = vec![method];
(span_builder, metrics_labels)
.with_attributes(attributes)
}
}
@ -156,15 +123,21 @@ pub struct SpanFromAxumRequest;
#[cfg(feature = "axum")]
impl<B> MakeSpanBuilder<Request<B>> for SpanFromAxumRequest {
fn make_span_builder(&self, request: &Request<B>) -> (SpanBuilder, Vec<KeyValue>) {
let method = SC::HTTP_METHOD.string(http_method_str(request.method()));
let mut metrics_labels = vec![method.clone()];
fn make_span_builder(&self, request: &Request<B>) -> SpanBuilder {
let (name, route): (String, Cow<'static, str>) =
if let Some(path) = request.extensions().get::<MatchedPath>() {
let path = path.as_str().to_owned();
let name = path.clone();
(name, path.into())
} else {
(request.uri().path().to_owned(), Cow::Borrowed("FALLBACK"))
};
let mut attributes = vec![
method,
SC::HTTP_METHOD.string(http_method_str(request.method())),
SC::HTTP_FLAVOR.string(http_flavor(request.version())),
SC::HTTP_TARGET.string(request.uri().to_string()),
SC::HTTP_ROUTE.string(route),
];
let headers = request.headers();
@ -192,23 +165,9 @@ impl<B> MakeSpanBuilder<Request<B>> for SpanFromAxumRequest {
attributes.push(SC::NET_PEER_PORT.i64(addr.port().into()));
}
let (name, route) = if let Some(path) = request.extensions().get::<MatchedPath>() {
let path = path.as_str();
(path, path)
} else {
(request.uri().path(), "FALLBACK")
};
let route = SC::HTTP_ROUTE.string(route.to_owned());
attributes.push(route.clone());
metrics_labels.push(route);
(
SpanBuilder::from_name(name.to_owned())
.with_kind(SpanKind::Server)
.with_attributes(attributes),
metrics_labels,
)
SpanBuilder::from_name(name)
.with_kind(SpanKind::Server)
.with_attributes(attributes)
}
}
@ -218,14 +177,11 @@ pub struct SpanFromDnsRequest;
#[cfg(feature = "client")]
impl MakeSpanBuilder<Name> for SpanFromDnsRequest {
fn make_span_builder(&self, request: &Name) -> (SpanBuilder, Vec<KeyValue>) {
fn make_span_builder(&self, request: &Name) -> SpanBuilder {
let attributes = vec![SC::NET_HOST_NAME.string(request.as_str().to_owned())];
(
SpanBuilder::from_name("resolve")
.with_kind(SpanKind::Client)
.with_attributes(attributes.clone()),
attributes,
)
SpanBuilder::from_name("resolve")
.with_kind(SpanKind::Client)
.with_attributes(attributes)
}
}

View File

@ -15,15 +15,18 @@
mod extract_context;
mod inject_context;
mod layer;
mod make_metrics_labels;
mod make_span_builder;
mod on_error;
mod on_response;
mod service;
mod utils;
pub type TraceHttpServerLayer = TraceLayer<
ExtractFromHttpRequest,
DefaultInjectContext,
SpanFromHttpRequest,
MetricsLabelsFromHttpRequest,
OnHttpResponse,
DefaultOnError,
>;
@ -32,6 +35,7 @@ pub type TraceHttpServer<S> = Trace<
ExtractFromHttpRequest,
DefaultInjectContext,
SpanFromHttpRequest,
MetricsLabelsFromHttpRequest,
OnHttpResponse,
DefaultOnError,
S,
@ -42,6 +46,7 @@ pub type TraceAxumServerLayer = TraceLayer<
ExtractFromHttpRequest,
DefaultInjectContext,
SpanFromAxumRequest,
MetricsLabelsFromAxumRequest,
OnHttpResponse,
DefaultOnError,
>;
@ -51,6 +56,7 @@ pub type TraceAxumServer<S> = Trace<
ExtractFromHttpRequest,
DefaultInjectContext,
SpanFromAxumRequest,
MetricsLabelsFromAxumRequest,
OnHttpResponse,
DefaultOnError,
S,
@ -60,6 +66,7 @@ pub type TraceHttpClientLayer = TraceLayer<
DefaultExtractContext,
InjectInHttpRequest,
SpanFromHttpRequest,
MetricsLabelsFromHttpRequest,
OnHttpResponse,
DefaultOnError,
>;
@ -68,6 +75,7 @@ pub type TraceHttpClient<S> = Trace<
DefaultExtractContext,
InjectInHttpRequest,
SpanFromHttpRequest,
MetricsLabelsFromHttpRequest,
OnHttpResponse,
DefaultOnError,
S,
@ -78,6 +86,7 @@ pub type TraceDnsLayer = TraceLayer<
DefaultExtractContext,
DefaultInjectContext,
SpanFromDnsRequest,
DefaultMakeMetricsLabels,
DefaultOnResponse,
DefaultOnError,
>;
@ -87,6 +96,7 @@ pub type TraceDns<S> = Trace<
DefaultExtractContext,
DefaultInjectContext,
SpanFromDnsRequest,
DefaultMakeMetricsLabels,
DefaultOnResponse,
DefaultOnError,
S,
@ -97,6 +107,7 @@ impl TraceHttpServerLayer {
pub fn http_server() -> Self {
TraceLayer::with_namespace("http_server")
.make_span_builder(SpanFromHttpRequest::server())
.make_metrics_labels(MetricsLabelsFromHttpRequest::default())
.on_response(OnHttpResponse)
.extract_context(ExtractFromHttpRequest)
}
@ -108,6 +119,7 @@ impl TraceAxumServerLayer {
pub fn axum() -> Self {
TraceLayer::with_namespace("http_server")
.make_span_builder(SpanFromAxumRequest)
.make_metrics_labels(MetricsLabelsFromAxumRequest::default())
.on_response(OnHttpResponse)
.extract_context(ExtractFromHttpRequest)
}
@ -118,6 +130,7 @@ impl TraceHttpClientLayer {
pub fn http_client(operation: &'static str) -> Self {
TraceLayer::with_namespace("http_client")
.make_span_builder(SpanFromHttpRequest::client(operation))
.make_metrics_labels(MetricsLabelsFromHttpRequest::default())
.on_response(OnHttpResponse)
.inject_context(InjectInHttpRequest)
}
@ -126,6 +139,7 @@ impl TraceHttpClientLayer {
pub fn inner_http_client() -> Self {
TraceLayer::with_namespace("inner_http_client")
.make_span_builder(SpanFromHttpRequest::inner_client())
.make_metrics_labels(MetricsLabelsFromHttpRequest::default())
.on_response(OnHttpResponse)
.inject_context(InjectInHttpRequest)
}
@ -139,6 +153,9 @@ impl TraceDnsLayer {
}
}
use self::make_metrics_labels::{
DefaultMakeMetricsLabels, MetricsLabelsFromAxumRequest, MetricsLabelsFromHttpRequest,
};
pub use self::{
extract_context::*, inject_context::*, layer::*, make_span_builder::*, on_error::*,
on_response::*, service::*,

View File

@ -16,7 +16,7 @@ use opentelemetry::{trace::SpanRef, KeyValue};
use opentelemetry_semantic_conventions::trace::EXCEPTION_MESSAGE;
pub trait OnError<E> {
fn on_error(&self, span: &SpanRef<'_>, err: &E) -> Vec<KeyValue>;
fn on_error(&self, span: &SpanRef<'_>, metrics_labels: &mut Vec<KeyValue>, err: &E);
}
#[derive(Debug, Clone, Copy, Default)]
@ -26,10 +26,8 @@ impl<E> OnError<E> for DefaultOnError
where
E: std::fmt::Display,
{
fn on_error(&self, span: &SpanRef<'_>, err: &E) -> Vec<KeyValue> {
fn on_error(&self, span: &SpanRef<'_>, _metrics_labels: &mut Vec<KeyValue>, err: &E) {
let attributes = vec![EXCEPTION_MESSAGE.string(err.to_string())];
span.add_event("exception".to_owned(), attributes);
Vec::new()
}
}

View File

@ -20,15 +20,14 @@ use opentelemetry::{trace::SpanRef, KeyValue};
use opentelemetry_semantic_conventions::trace as SC;
pub trait OnResponse<R> {
fn on_response(&self, span: &SpanRef<'_>, response: &R) -> Vec<KeyValue>;
fn on_response(&self, span: &SpanRef<'_>, metrics_labels: &mut Vec<KeyValue>, response: &R);
}
#[derive(Debug, Clone, Copy, Default)]
pub struct DefaultOnResponse;
impl<R> OnResponse<R> for DefaultOnResponse {
fn on_response(&self, _span: &SpanRef<'_>, _response: &R) -> Vec<KeyValue> {
Vec::new()
fn on_response(&self, _span: &SpanRef<'_>, _metrics_labels: &mut Vec<KeyValue>, _response: &R) {
}
}
@ -36,9 +35,15 @@ impl<R> OnResponse<R> for DefaultOnResponse {
pub struct OnHttpResponse;
impl<B> OnResponse<Response<B>> for OnHttpResponse {
fn on_response(&self, span: &SpanRef<'_>, response: &Response<B>) -> Vec<KeyValue> {
fn on_response(
&self,
span: &SpanRef<'_>,
metrics_labels: &mut Vec<KeyValue>,
response: &Response<B>,
) {
let status_code = i64::from(response.status().as_u16());
span.set_attribute(SC::HTTP_STATUS_CODE.i64(status_code));
metrics_labels.push(KeyValue::new("status_code", status_code));
if let Some(ContentLength(content_length)) = response.headers().typed_get() {
if let Ok(content_length) = content_length.try_into() {
@ -55,7 +60,5 @@ impl<B> OnResponse<Response<B>> for OnHttpResponse {
span.set_attribute(SC::NET_HOST_IP.string(info.local_addr().ip().to_string()));
span.set_attribute(SC::NET_HOST_PORT.i64(info.local_addr().port().into()));
}
vec![KeyValue::new("status_code", status_code)]
}
}

View File

@ -24,26 +24,37 @@ use tower::Service;
use super::{
extract_context::ExtractContext, inject_context::InjectContext,
make_span_builder::MakeSpanBuilder, on_error::OnError, on_response::OnResponse,
make_metrics_labels::MakeMetricsLabels, make_span_builder::MakeSpanBuilder, on_error::OnError,
on_response::OnResponse,
};
#[derive(Debug, Clone)]
pub struct Trace<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError, S> {
pub struct Trace<
ExtractContext,
InjectContext,
MakeSpanBuilder,
MakeMetricsLabels,
OnResponse,
OnError,
S,
> {
inner: S,
tracer: Arc<opentelemetry::global::BoxedTracer>,
extract_context: ExtractContext,
inject_context: InjectContext,
make_span_builder: MakeSpanBuilder,
make_metrics_labels: MakeMetricsLabels,
on_response: OnResponse,
on_error: OnError,
inflight_requests: UpDownCounter<i64>,
request_counter: Counter<u64>,
request_histogram: Histogram<f64>,
static_attributes: Vec<KeyValue>,
}
impl<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError, S>
Trace<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError, S>
impl<ExtractContext, InjectContext, MakeSpanBuilder, MakeMetricsLabels, OnResponse, OnError, S>
Trace<ExtractContext, InjectContext, MakeSpanBuilder, MakeMetricsLabels, OnResponse, OnError, S>
{
#[allow(clippy::too_many_arguments)]
pub fn new(
@ -52,11 +63,13 @@ impl<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError, S>
extract_context: ExtractContext,
inject_context: InjectContext,
make_span_builder: MakeSpanBuilder,
make_metrics_labels: MakeMetricsLabels,
on_response: OnResponse,
on_error: OnError,
inflight_requests: UpDownCounter<i64>,
request_counter: Counter<u64>,
request_histogram: Histogram<f64>,
static_attributes: Vec<KeyValue>,
) -> Self {
Self {
inner: service,
@ -65,12 +78,14 @@ impl<ExtractContext, InjectContext, MakeSpanBuilder, OnResponse, OnError, S>
extract_context,
inject_context,
make_span_builder,
make_metrics_labels,
on_response,
on_error,
inflight_requests,
request_counter,
request_histogram,
static_attributes,
}
}
}
@ -98,8 +113,25 @@ impl Drop for InFlightGuard {
}
}
impl<Req, S, ExtractContextT, InjectContextT, MakeSpanBuilderT, OnResponseT, OnErrorT> Service<Req>
for Trace<ExtractContextT, InjectContextT, MakeSpanBuilderT, OnResponseT, OnErrorT, S>
impl<
Req,
S,
ExtractContextT,
InjectContextT,
MakeSpanBuilderT,
MakeMetricsLabelsT,
OnResponseT,
OnErrorT,
> Service<Req>
for Trace<
ExtractContextT,
InjectContextT,
MakeSpanBuilderT,
MakeMetricsLabelsT,
OnResponseT,
OnErrorT,
S,
>
where
ExtractContextT: ExtractContext<Req> + Send,
InjectContextT: InjectContext<Req> + Send,
@ -107,6 +139,7 @@ where
OnResponseT: OnResponse<S::Response> + Send + Clone + 'static,
OnErrorT: OnError<S::Error> + Send + Clone + 'static,
MakeSpanBuilderT: MakeSpanBuilder<Req> + Send,
MakeMetricsLabelsT: MakeMetricsLabels<Req> + Send,
S::Future: Send + 'static,
{
type Response = S::Response;
@ -123,7 +156,15 @@ where
let start_time = SystemTime::now();
let cx = self.extract_context.extract_context(&request);
let (span_builder, mut metrics_labels) = self.make_span_builder.make_span_builder(&request);
let mut span_builder = self.make_span_builder.make_span_builder(&request);
let mut metrics_labels = self.make_metrics_labels.make_metrics_labels(&request);
// Add the static attributes to the metrics and the span
metrics_labels.extend_from_slice(&self.static_attributes[..]);
let mut span_attributes = span_builder.attributes.unwrap_or_default();
span_attributes.extend(self.static_attributes.iter().cloned());
span_builder.attributes = Some(span_attributes);
let span = span_builder.start_with_context(self.tracer.as_ref(), &cx);
let cx = cx.with_span(span);
@ -144,11 +185,10 @@ where
let _guard = guard;
let span = cx.span();
let extra_labels = match r {
Ok(response) => on_response.on_response(&span, response),
Err(err) => on_error.on_error(&span, err),
match r {
Ok(response) => on_response.on_response(&span, &mut metrics_labels, response),
Err(err) => on_error.on_error(&span, &mut metrics_labels, err),
};
metrics_labels.extend_from_slice(&extra_labels);
request_counter.add(&cx, 1, &metrics_labels);
request_histogram.record(

View File

@ -0,0 +1,45 @@
// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::borrow::Cow;
use http::{Method, Version};
#[inline]
pub(super) fn http_method_str(method: &Method) -> Cow<'static, str> {
match method {
&Method::OPTIONS => "OPTIONS".into(),
&Method::GET => "GET".into(),
&Method::POST => "POST".into(),
&Method::PUT => "PUT".into(),
&Method::DELETE => "DELETE".into(),
&Method::HEAD => "HEAD".into(),
&Method::TRACE => "TRACE".into(),
&Method::CONNECT => "CONNECT".into(),
&Method::PATCH => "PATCH".into(),
other => other.to_string().into(),
}
}
#[inline]
pub(super) fn http_flavor(version: Version) -> Cow<'static, str> {
match version {
Version::HTTP_09 => "0.9".into(),
Version::HTTP_10 => "1.0".into(),
Version::HTTP_11 => "1.1".into(),
Version::HTTP_2 => "2.0".into(),
Version::HTTP_3 => "3.0".into(),
other => format!("{:?}", other).into(),
}
}

View File

@ -15,6 +15,7 @@
use std::marker::PhantomData;
use http::{Request, Response};
use opentelemetry::KeyValue;
use tower::{util::BoxCloneService, Layer, Service, ServiceBuilder, ServiceExt};
use tower_http::{compression::CompressionBody, ServiceBuilderExt};
@ -51,10 +52,17 @@ where
let builder = ServiceBuilder::new().compression();
#[cfg(feature = "axum")]
let builder = builder.layer(TraceLayer::axum());
let mut trace_layer = TraceLayer::axum();
#[cfg(not(feature = "axum"))]
let builder = builder.layer(TraceLayer::http_server());
let mut trace_layer = TraceLayer::http_server();
if let Some(name) = &self.listener_name {
trace_layer =
trace_layer.with_static_attribute(KeyValue::new("listener", name.clone()));
}
let builder = builder.layer(trace_layer);
builder.service(inner).boxed_clone()
}