Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(encoding): implement UTF-8 support in metric and label names #236

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f25f0f4
WIP Quote non-legacy metric names in descriptor
fedetorres93 Oct 1, 2024
9d1e518
Quote non-legacy label names and put non-legacy quoted metric names i…
fedetorres93 Oct 4, 2024
378d0e4
Add quoted metric and label names tests for text encoding
fedetorres93 Oct 4, 2024
b7f6396
Refactor metric and label names validation
fedetorres93 Oct 10, 2024
2339769
[WIP] Add content negotiation for non-legacy characters in metric and…
fedetorres93 Oct 18, 2024
4dc8859
Fix text encoding tests
fedetorres93 Oct 25, 2024
ce522cd
Move name validation functions to encoding
fedetorres93 Oct 29, 2024
81cd210
Add getters for name_validation_scheme and escaping_scheme
fedetorres93 Oct 29, 2024
9eee74c
Add RegistryBuilder
fedetorres93 Oct 29, 2024
e25fceb
Add documentation
fedetorres93 Oct 31, 2024
37ca910
Remove name validation scheme and escaping scheme constructors
fedetorres93 Oct 31, 2024
68d9ae9
Fix metric and label name escaping when UTF-8 validation is enabled
fedetorres93 Nov 5, 2024
c0b0b41
Remove commented code
fedetorres93 Nov 5, 2024
8b85cdb
Remove unused structs in axum UTF-8 example
fedetorres93 Nov 5, 2024
4b1ce00
Remove unnecessary escape_name calls
fedetorres93 Nov 5, 2024
8749a9c
Merge remote-tracking branch 'upstream/master' into ftorres/utf-8
fedetorres93 Nov 7, 2024
b0d7ae2
Formatting
fedetorres93 Nov 7, 2024
e62a619
Merge branch 'master' into ftorres/utf-8
fedetorres93 Dec 13, 2024
598fe97
Add more test cases
fedetorres93 Jan 16, 2025
813b459
Merge branch 'master' into ftorres/utf-8
fedetorres93 Jan 16, 2025
ca92109
Additional tests
fedetorres93 Jan 20, 2025
1ff883d
perf: improve perf of encoding with new UTF-8 validation
sd2k Jan 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions examples/axum-utf-8.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use axum::body::Body;
use axum::extract::State;
use axum::http::header::CONTENT_TYPE;
use axum::http::{HeaderMap, StatusCode};
use axum::response::{IntoResponse, Response};
use axum::routing::get;
use axum::Router;
use prometheus_client::encoding::negotiate_escaping_scheme;
use prometheus_client::encoding::text::encode;
use prometheus_client::encoding::EscapingScheme::UnderscoreEscaping;
use prometheus_client::encoding::ValidationScheme::UTF8Validation;
use prometheus_client::metrics::counter::Counter;
use prometheus_client::metrics::family::Family;
use prometheus_client::registry::{Registry, RegistryBuilder};
use std::sync::Arc;
use tokio::sync::Mutex;

#[derive(Debug)]
pub struct Metrics {
requests: Family<Vec<(String, String)>, Counter>,
}

impl Metrics {
pub fn inc_requests(&self, method: String) {
self.requests
.get_or_create(&vec![("method.label".to_owned(), method)])
.inc();
}
}

#[derive(Debug)]
pub struct AppState {
pub registry: Registry,
}

pub async fn metrics_handler(
State(state): State<Arc<Mutex<AppState>>>,
headers: HeaderMap,
) -> impl IntoResponse {
let mut state = state.lock().await;
let mut buffer = String::new();
if let Some(accept) = headers.get("Accept") {
let escaping_scheme =
negotiate_escaping_scheme(accept.to_str().unwrap(), state.registry.escaping_scheme());
state.registry.set_escaping_scheme(escaping_scheme);
}
encode(&mut buffer, &state.registry).unwrap();

Response::builder()
.status(StatusCode::OK)
.header(
CONTENT_TYPE,
"application/openmetrics-text; version=1.0.0; charset=utf-8; escaping=".to_owned()
+ state.registry.escaping_scheme().as_str(),
)
.body(Body::from(buffer))
.unwrap()
}

pub async fn some_handler(State(metrics): State<Arc<Mutex<Metrics>>>) -> impl IntoResponse {
metrics.lock().await.inc_requests("Get".to_owned());
"okay".to_string()
}

#[tokio::main]
async fn main() {
let metrics = Metrics {
requests: Family::default(),
};
let mut state = AppState {
registry: RegistryBuilder::new()
.with_name_validation_scheme(UTF8Validation)
.with_escaping_scheme(UnderscoreEscaping)
.build(),
};
state.registry.register(
"requests.count",
"Count of requests",
metrics.requests.clone(),
);
let metrics = Arc::new(Mutex::new(metrics));
let state = Arc::new(Mutex::new(state));

let router = Router::new()
.route("/metrics", get(metrics_handler))
.with_state(state)
.route("/handler", get(some_handler))
.with_state(metrics);
let port = 8080;
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", port))
.await
.unwrap();

axum::serve(listener, router).await.unwrap();
}
Loading