Skip to content

Commit

Permalink
feat: [#1126] add support for prometheus text format on stats API end…
Browse files Browse the repository at this point in the history
…point

http://127.0.0.1:1212/api/v1/stats?token=MyAccessToken&format=prometheus

```text
torrents 0
seeders 0
completed 0
leechers 0
tcp4_connections_handled 0
tcp4_announces_handled 0
tcp4_scrapes_handled 0
tcp6_connections_handled 0
tcp6_announces_handled 0
tcp6_scrapes_handled 0
udp4_connections_handled 0
udp4_announces_handled 0
udp4_scrapes_handled 0
udp4_errors_handled 0
udp6_connections_handled 0
udp6_announces_handled 0
udp6_scrapes_handled 0
udp6_errors_handled 0
```
  • Loading branch information
josecelano committed Dec 10, 2024
1 parent b0af435 commit ff0fafc
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 8 deletions.
34 changes: 29 additions & 5 deletions src/servers/apis/v1/context/stats/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,43 @@
use std::sync::Arc;

use axum::extract::State;
use axum::response::Json;
use axum::response::Response;
use axum_extra::extract::Query;
use serde::Deserialize;

use super::resources::Stats;
use super::responses::stats_response;
use super::responses::{metrics_response, stats_response};
use crate::core::services::statistics::get_metrics;
use crate::core::Tracker;

#[derive(Deserialize, Debug, Default)]
#[serde(rename_all = "lowercase")]
pub enum Format {
#[default]
Json,
Prometheus,
}

#[derive(Deserialize, Debug)]
pub struct QueryParams {
/// The [`Format`] of the stats.
#[serde(default)]
pub format: Option<Format>,
}

/// It handles the request to get the tracker statistics.
///
/// It returns a `200` response with a json [`Stats`]
///
/// Refer to the [API endpoint documentation](crate::servers::apis::v1::context::stats#get-tracker-statistics)
/// for more information about this endpoint.
pub async fn get_stats_handler(State(tracker): State<Arc<Tracker>>) -> Json<Stats> {
stats_response(get_metrics(tracker.clone()).await)
pub async fn get_stats_handler(State(tracker): State<Arc<Tracker>>, params: Query<QueryParams>) -> Response {
let metrics = get_metrics(tracker.clone()).await;

match params.0.format {
Some(format) => match format {
Format::Json => stats_response(metrics),
Format::Prometheus => metrics_response(&metrics),
},
None => stats_response(metrics),
}
}
81 changes: 78 additions & 3 deletions src/servers/apis/v1/context/stats/responses.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,86 @@
//! API responses for the [`stats`](crate::servers::apis::v1::context::stats)
//! API context.
use axum::response::Json;
use axum::response::{IntoResponse, Json, Response};

use super::resources::Stats;
use crate::core::services::statistics::TrackerMetrics;

/// `200` response that contains the [`Stats`] resource as json.
pub fn stats_response(tracker_metrics: TrackerMetrics) -> Json<Stats> {
Json(Stats::from(tracker_metrics))
#[must_use]
pub fn stats_response(tracker_metrics: TrackerMetrics) -> Response {
Json(Stats::from(tracker_metrics)).into_response()
}

/// `200` response that contains the [`Stats`] resource in Prometheus Text Exposition Format .
#[must_use]
pub fn metrics_response(tracker_metrics: &TrackerMetrics) -> Response {
let mut lines = vec![];

lines.push(format!("torrents {}", tracker_metrics.torrents_metrics.torrents));
lines.push(format!("seeders {}", tracker_metrics.torrents_metrics.complete));
lines.push(format!("completed {}", tracker_metrics.torrents_metrics.downloaded));
lines.push(format!("leechers {}", tracker_metrics.torrents_metrics.incomplete));

lines.push(format!(
"tcp4_connections_handled {}",
tracker_metrics.protocol_metrics.tcp4_connections_handled
));
lines.push(format!(
"tcp4_announces_handled {}",
tracker_metrics.protocol_metrics.tcp4_announces_handled
));
lines.push(format!(
"tcp4_scrapes_handled {}",
tracker_metrics.protocol_metrics.tcp4_scrapes_handled
));

lines.push(format!(
"tcp6_connections_handled {}",
tracker_metrics.protocol_metrics.tcp6_connections_handled
));
lines.push(format!(
"tcp6_announces_handled {}",
tracker_metrics.protocol_metrics.tcp6_announces_handled
));
lines.push(format!(
"tcp6_scrapes_handled {}",
tracker_metrics.protocol_metrics.tcp6_scrapes_handled
));

lines.push(format!(
"udp4_connections_handled {}",
tracker_metrics.protocol_metrics.udp4_connections_handled
));
lines.push(format!(
"udp4_announces_handled {}",
tracker_metrics.protocol_metrics.udp4_announces_handled
));
lines.push(format!(
"udp4_scrapes_handled {}",
tracker_metrics.protocol_metrics.udp4_scrapes_handled
));
lines.push(format!(
"udp4_errors_handled {}",
tracker_metrics.protocol_metrics.udp4_errors_handled
));

lines.push(format!(
"udp6_connections_handled {}",
tracker_metrics.protocol_metrics.udp6_connections_handled
));
lines.push(format!(
"udp6_announces_handled {}",
tracker_metrics.protocol_metrics.udp6_announces_handled
));
lines.push(format!(
"udp6_scrapes_handled {}",
tracker_metrics.protocol_metrics.udp6_scrapes_handled
));
lines.push(format!(
"udp6_errors_handled {}",
tracker_metrics.protocol_metrics.udp6_errors_handled
));

// Return the plain text response
lines.join("\n").into_response()
}

0 comments on commit ff0fafc

Please sign in to comment.