Skip to content

Commit

Permalink
Merge pull request #33 from Ptrskay3/experiment/http_body_size
Browse files Browse the repository at this point in the history
Fix Lifecycle::Callbacks semantics, implement response body size metrics
  • Loading branch information
Ptrskay3 authored Nov 24, 2023
2 parents e06cdde + ca67288 commit 7a80ab9
Show file tree
Hide file tree
Showing 14 changed files with 307 additions and 74 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

-
### Added

- Support for response body size metric, which can be turned on via `PrometheusMetricLayerBuilder::enable_response_body_size`.
- All metrics now are initialized via `metrics::describe_*` function by default, but can be turned off with `PrometheusMetricLayerBuilder::no_initialize_metrics`.

### Changed

- The lower-level Lifecycle API has changed: separated the `OnBodyChunk` trait, which is ran when a response body chunk has been generated.

# [0.4.0] - 2023-07-24

Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ By default three HTTP metrics are tracked
- `axum_http_requests_duration_seconds` (labels: endpoint, method, status): the request duration for all HTTP requests handled (histogram)
- `axum_http_requests_pending` (labels: endpoint, method): the number of currently in-flight requests (gauge)

Note that in the future request size metric is also planned to be implemented.
This crate also allows to track response body sizes as a histogram — see `PrometheusMetricLayerBuilder::enable_response_body_size`.

### Renaming Metrics

Expand All @@ -33,6 +33,7 @@ These metrics can be renamed by specifying environmental variables at compile ti
- `AXUM_HTTP_REQUESTS_TOTAL`
- `AXUM_HTTP_REQUESTS_DURATION_SECONDS`
- `AXUM_HTTP_REQUESTS_PENDING`
- `AXUM_HTTP_RESPONSE_BODY_SIZE` (if body size tracking is enabled)

These environmental variables can be set in your `.cargo/config.toml` since Cargo 1.56:

Expand All @@ -41,6 +42,7 @@ These environmental variables can be set in your `.cargo/config.toml` since Carg
AXUM_HTTP_REQUESTS_TOTAL = "my_app_requests_total"
AXUM_HTTP_REQUESTS_DURATION_SECONDS = "my_app_requests_duration_seconds"
AXUM_HTTP_REQUESTS_PENDING = "my_app_requests_pending"
AXUM_HTTP_RESPONSE_BODY_SIZE = "my_app_response_body_size"
```

..or optionally use `PrometheusMetricLayerBuilder::with_prefix` function.
Expand Down Expand Up @@ -133,6 +135,8 @@ struct Recorder;

// In order to use this with `axum_prometheus`, we must implement `MakeDefaultHandle`.
impl MakeDefaultHandle for Recorder {
// We don't need to return anything meaningful from here (unlike PrometheusHandle)
// Let's just return an empty tuple.
type Out = ();

fn make_default_handle() -> Self::Out {
Expand All @@ -144,9 +148,6 @@ impl MakeDefaultHandle for Recorder {
.expect("Could not create StatsdRecorder");

metrics::set_boxed_recorder(Box::new(recorder)).unwrap();
// We don't need to return anything meaningful from here (unlike PrometheusHandle)
// Let's just return an empty tuple.
()
}
}

Expand Down
2 changes: 1 addition & 1 deletion examples/builder-example/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async fn main() {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "builder-example=debug".into()),
.unwrap_or_else(|_| "builder_example=debug".into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
Expand Down
2 changes: 1 addition & 1 deletion examples/endpoint-type-example/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ async fn main() {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "endpoint-type-example=debug".into()),
.unwrap_or_else(|_| "endpoint_type_example=debug".into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
Expand Down
7 changes: 3 additions & 4 deletions examples/exporter-statsd-example/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ struct Recorder;

// In order to use this with `axum_prometheus`, we must implement `MakeDefaultHandle`.
impl MakeDefaultHandle for Recorder {
// We don't need to return anything meaningful from here (unlike PrometheusHandle)
// Let's just return an empty tuple.
type Out = ();

fn make_default_handle() -> Self::Out {
Expand All @@ -26,9 +28,6 @@ impl MakeDefaultHandle for Recorder {
.expect("Could not create StatsdRecorder");

metrics::set_boxed_recorder(Box::new(recorder)).unwrap();
// We don't need to return anything meaningful from here (unlike PrometheusHandle)
// Let's just return an empty tuple.
()
}
}

Expand All @@ -37,7 +36,7 @@ async fn main() {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "exporter-statsd-example=debug".into()),
.unwrap_or_else(|_| "exporter_statsd_example=debug".into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-example/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ async fn main() {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "simple-example=debug".into()),
.unwrap_or_else(|_| "simple_example=debug".into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
Expand Down
55 changes: 54 additions & 1 deletion src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ pub struct MetricLayerBuilder<'a, T, M, S: MetricBuilderState> {
pub(crate) traffic: Traffic<'a>,
pub(crate) metric_handle: Option<T>,
pub(crate) metric_prefix: Option<String>,
pub(crate) enable_body_size: bool,
pub(crate) no_initialize_metrics: bool,
pub(crate) _marker: PhantomData<(S, M)>,
}

Expand Down Expand Up @@ -144,6 +146,23 @@ where
self.traffic.with_endpoint_label_type(endpoint_label);
self
}

/// Enable response body size tracking.
///
/// #### Note:
/// This may introduce some performance overhead.
pub fn enable_response_body_size(mut self, enable: bool) -> Self {
self.enable_body_size = enable;
self
}

/// By default, all metrics are initialized via `metrics::describe_*` macros, setting descriptions and units.
///
/// This function disables this initialization.
pub fn no_initialize_metrics(mut self) -> Self {
self.no_initialize_metrics = true;
self
}
}

impl<'a, T, M> MetricLayerBuilder<'a, T, M, LayerOnly>
Expand All @@ -156,7 +175,9 @@ where
_marker: PhantomData,
traffic: Traffic::new(),
metric_handle: None,
no_initialize_metrics: false,
metric_prefix: None,
enable_body_size: false,
}
}

Expand All @@ -166,7 +187,9 @@ where
/// - `{prefix}_http_requests_pending`
/// - `{prefix}_http_requests_duration_seconds`
///
/// Note that this will take precedence over environment variables.
/// ..and will also use `{prefix}_http_response_body_size`, if response body size tracking is enabled.
///
/// This method will take precedence over environment variables.
///
/// ## Note
///
Expand Down Expand Up @@ -249,11 +272,16 @@ where
if let Some(prefix) = layer_only.metric_prefix.as_ref() {
set_prefix(prefix);
}
if !layer_only.no_initialize_metrics {
describe_metrics(layer_only.enable_body_size);
}
MetricLayerBuilder {
_marker: PhantomData,
traffic: layer_only.traffic,
metric_handle: layer_only.metric_handle,
no_initialize_metrics: layer_only.no_initialize_metrics,
metric_prefix: layer_only.metric_prefix,
enable_body_size: layer_only.enable_body_size,
}
}
}
Expand All @@ -273,3 +301,28 @@ where
/// A builder for [`crate::PrometheusMetricLayer`] that enables further customizations.
pub type PrometheusMetricLayerBuilder<'a, S> =
MetricLayerBuilder<'a, PrometheusHandle, crate::Handle, S>;

fn describe_metrics(enable_body_size: bool) {
metrics::describe_counter!(
crate::utils::requests_total_name(),
metrics::Unit::Count,
"The number of times a HTTP request was processed."
);
metrics::describe_gauge!(
crate::utils::requests_pending_name(),
metrics::Unit::Count,
"The number of currently in-flight requests."
);
metrics::describe_histogram!(
crate::utils::requests_duration_name(),
metrics::Unit::Seconds,
"The distribution of HTTP response times."
);
if enable_body_size {
metrics::describe_histogram!(
crate::utils::response_body_size_name(),
metrics::Unit::Count,
"The distribution of HTTP response body sizes."
);
}
}
Loading

0 comments on commit 7a80ab9

Please sign in to comment.