Skip to content

Commit d8b6123

Browse files
committed
Merge torrust#1127: API: add support for Prometheus text format on stats API endpoint
52d3505 feat: [torrust#1126] add support for prometheus text format on stats API endpoint (Jose Celano) Pull request description: It adds support for Prometheus text format on the `stats` API endpoint: 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 ``` Needed to implement this: torrust/torrust-demo#20 ACKs for top commit: josecelano: ACK 52d3505 Tree-SHA512: bde180580f23f69f0ec846c1db6ef9c970e52e253399515650a1d0a9c39d8e2095e77521fbd7361c28c63e70d391071c1210c8292248e0ae668ae516ecd38564
2 parents b0af435 + 52d3505 commit d8b6123

File tree

2 files changed

+111
-9
lines changed

2 files changed

+111
-9
lines changed

src/servers/apis/v1/context/stats/handlers.rs

+33-6
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,46 @@
33
use std::sync::Arc;
44

55
use axum::extract::State;
6-
use axum::response::Json;
6+
use axum::response::Response;
7+
use axum_extra::extract::Query;
8+
use serde::Deserialize;
79

8-
use super::resources::Stats;
9-
use super::responses::stats_response;
10+
use super::responses::{metrics_response, stats_response};
1011
use crate::core::services::statistics::get_metrics;
1112
use crate::core::Tracker;
1213

14+
#[derive(Deserialize, Debug, Default)]
15+
#[serde(rename_all = "lowercase")]
16+
pub enum Format {
17+
#[default]
18+
Json,
19+
Prometheus,
20+
}
21+
22+
#[derive(Deserialize, Debug)]
23+
pub struct QueryParams {
24+
/// The [`Format`] of the stats.
25+
#[serde(default)]
26+
pub format: Option<Format>,
27+
}
28+
1329
/// It handles the request to get the tracker statistics.
1430
///
15-
/// It returns a `200` response with a json [`Stats`]
31+
/// By default it returns a `200` response with the stats in JSON format.
32+
///
33+
/// You can add the GET parameter `format=prometheus` to get the stats in
34+
/// Prometheus Text Exposition Format.
1635
///
1736
/// Refer to the [API endpoint documentation](crate::servers::apis::v1::context::stats#get-tracker-statistics)
1837
/// for more information about this endpoint.
19-
pub async fn get_stats_handler(State(tracker): State<Arc<Tracker>>) -> Json<Stats> {
20-
stats_response(get_metrics(tracker.clone()).await)
38+
pub async fn get_stats_handler(State(tracker): State<Arc<Tracker>>, params: Query<QueryParams>) -> Response {
39+
let metrics = get_metrics(tracker.clone()).await;
40+
41+
match params.0.format {
42+
Some(format) => match format {
43+
Format::Json => stats_response(metrics),
44+
Format::Prometheus => metrics_response(&metrics),
45+
},
46+
None => stats_response(metrics),
47+
}
2148
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,86 @@
11
//! API responses for the [`stats`](crate::servers::apis::v1::context::stats)
22
//! API context.
3-
use axum::response::Json;
3+
use axum::response::{IntoResponse, Json, Response};
44

55
use super::resources::Stats;
66
use crate::core::services::statistics::TrackerMetrics;
77

88
/// `200` response that contains the [`Stats`] resource as json.
9-
pub fn stats_response(tracker_metrics: TrackerMetrics) -> Json<Stats> {
10-
Json(Stats::from(tracker_metrics))
9+
#[must_use]
10+
pub fn stats_response(tracker_metrics: TrackerMetrics) -> Response {
11+
Json(Stats::from(tracker_metrics)).into_response()
12+
}
13+
14+
/// `200` response that contains the [`Stats`] resource in Prometheus Text Exposition Format .
15+
#[must_use]
16+
pub fn metrics_response(tracker_metrics: &TrackerMetrics) -> Response {
17+
let mut lines = vec![];
18+
19+
lines.push(format!("torrents {}", tracker_metrics.torrents_metrics.torrents));
20+
lines.push(format!("seeders {}", tracker_metrics.torrents_metrics.complete));
21+
lines.push(format!("completed {}", tracker_metrics.torrents_metrics.downloaded));
22+
lines.push(format!("leechers {}", tracker_metrics.torrents_metrics.incomplete));
23+
24+
lines.push(format!(
25+
"tcp4_connections_handled {}",
26+
tracker_metrics.protocol_metrics.tcp4_connections_handled
27+
));
28+
lines.push(format!(
29+
"tcp4_announces_handled {}",
30+
tracker_metrics.protocol_metrics.tcp4_announces_handled
31+
));
32+
lines.push(format!(
33+
"tcp4_scrapes_handled {}",
34+
tracker_metrics.protocol_metrics.tcp4_scrapes_handled
35+
));
36+
37+
lines.push(format!(
38+
"tcp6_connections_handled {}",
39+
tracker_metrics.protocol_metrics.tcp6_connections_handled
40+
));
41+
lines.push(format!(
42+
"tcp6_announces_handled {}",
43+
tracker_metrics.protocol_metrics.tcp6_announces_handled
44+
));
45+
lines.push(format!(
46+
"tcp6_scrapes_handled {}",
47+
tracker_metrics.protocol_metrics.tcp6_scrapes_handled
48+
));
49+
50+
lines.push(format!(
51+
"udp4_connections_handled {}",
52+
tracker_metrics.protocol_metrics.udp4_connections_handled
53+
));
54+
lines.push(format!(
55+
"udp4_announces_handled {}",
56+
tracker_metrics.protocol_metrics.udp4_announces_handled
57+
));
58+
lines.push(format!(
59+
"udp4_scrapes_handled {}",
60+
tracker_metrics.protocol_metrics.udp4_scrapes_handled
61+
));
62+
lines.push(format!(
63+
"udp4_errors_handled {}",
64+
tracker_metrics.protocol_metrics.udp4_errors_handled
65+
));
66+
67+
lines.push(format!(
68+
"udp6_connections_handled {}",
69+
tracker_metrics.protocol_metrics.udp6_connections_handled
70+
));
71+
lines.push(format!(
72+
"udp6_announces_handled {}",
73+
tracker_metrics.protocol_metrics.udp6_announces_handled
74+
));
75+
lines.push(format!(
76+
"udp6_scrapes_handled {}",
77+
tracker_metrics.protocol_metrics.udp6_scrapes_handled
78+
));
79+
lines.push(format!(
80+
"udp6_errors_handled {}",
81+
tracker_metrics.protocol_metrics.udp6_errors_handled
82+
));
83+
84+
// Return the plain text response
85+
lines.join("\n").into_response()
1186
}

0 commit comments

Comments
 (0)