Changed prometheus metrics feature as optional

This commit is contained in:
mohandasspat 2022-08-17 17:14:55 +05:30
parent 0b6ca73790
commit 2b8f3c26ec
4 changed files with 95 additions and 35 deletions

View File

@ -6,6 +6,7 @@ pub mod task;
#[macro_use] #[macro_use]
pub mod extractors; pub mod extractors;
pub mod option; pub mod option;
pub mod route_metrics;
pub mod routes; pub mod routes;
use std::sync::{atomic::AtomicBool, Arc}; use std::sync::{atomic::AtomicBool, Arc};
@ -140,56 +141,33 @@ pub fn dashboard(config: &mut web::ServiceConfig, _enable_frontend: bool) {
config.service(web::resource("/").route(web::get().to(routes::running))); config.service(web::resource("/").route(web::get().to(routes::running)));
} }
pub fn configure_metrics_route(config: &mut web::ServiceConfig, enable_metrics_route: bool) {
if enable_metrics_route {
config.service(web::resource("/metrics").route(web::get().to(routes::get_metrics)));
}
}
#[macro_export] #[macro_export]
macro_rules! create_app { macro_rules! create_app {
($data:expr, $auth:expr, $enable_frontend:expr, $opt:expr, $analytics:expr) => {{ ($data:expr, $auth:expr, $enable_frontend:expr, $opt:expr, $analytics:expr) => {{
use actix_cors::Cors; use actix_cors::Cors;
use actix_web::dev::Service; use actix_web::dev::Service;
use actix_web::middleware::Condition;
use actix_web::middleware::TrailingSlash; use actix_web::middleware::TrailingSlash;
use actix_web::App; use actix_web::App;
use actix_web::{middleware, web}; use actix_web::{middleware, web};
use meilisearch_http::error::MeilisearchHttpError; use meilisearch_http::error::MeilisearchHttpError;
use meilisearch_http::metrics; use meilisearch_http::metrics;
use meilisearch_http::route_metrics;
use meilisearch_http::routes; use meilisearch_http::routes;
use meilisearch_http::{configure_data, dashboard}; use meilisearch_http::{configure_data, configure_metrics_route, dashboard};
use meilisearch_types::error::ResponseError; use meilisearch_types::error::ResponseError;
use lazy_static::lazy_static;
use prometheus::{
opts, register_histogram_vec, register_int_counter_vec, register_int_gauge,
};
use prometheus::{HistogramTimer, HistogramVec, IntCounterVec, IntGauge};
App::new() App::new()
.configure(|s| configure_data(s, $data.clone(), $auth.clone(), &$opt, $analytics)) .configure(|s| configure_data(s, $data.clone(), $auth.clone(), &$opt, $analytics))
.configure(routes::configure) .configure(routes::configure)
.configure(|s| dashboard(s, $enable_frontend)) .configure(|s| dashboard(s, $enable_frontend))
.wrap_fn(|req, srv| { .configure(|s| configure_metrics_route(s, $opt.enable_metrics_route))
let mut histogram_timer: Option<HistogramTimer> = None;
let request_path = req.path();
let is_registered_resource = req.resource_map().has_resource(request_path);
if is_registered_resource {
let request_method = req.method().to_string();
histogram_timer = Some(
metrics::HTTP_RESPONSE_TIME_SECONDS
.with_label_values(&[&request_method, request_path])
.start_timer(),
);
metrics::HTTP_REQUESTS_TOTAL
.with_label_values(&[&request_method, request_path])
.inc();
}
let fut = srv.call(req);
async {
let res = fut.await?;
if let Some(histogram_timer) = histogram_timer {
histogram_timer.observe_duration();
};
Ok(res)
}
})
.wrap( .wrap(
Cors::default() Cors::default()
.send_wildcard() .send_wildcard()
@ -203,5 +181,9 @@ macro_rules! create_app {
.wrap(middleware::NormalizePath::new( .wrap(middleware::NormalizePath::new(
middleware::TrailingSlash::Trim, middleware::TrailingSlash::Trim,
)) ))
.wrap(Condition::new(
$opt.enable_metrics_route,
route_metrics::RouteMetrics,
))
}}; }};
} }

View File

@ -146,6 +146,10 @@ pub struct Opt {
#[clap(long, env = "MEILI_LOG_LEVEL", default_value = "info")] #[clap(long, env = "MEILI_LOG_LEVEL", default_value = "info")]
pub log_level: String, pub log_level: String,
// Enables Prometheus metrics and /metrics route.
#[clap(long, requires = "enable-metrics-route")]
pub enable_metrics_route: bool,
#[serde(flatten)] #[serde(flatten)]
#[clap(flatten)] #[clap(flatten)]
pub indexer_options: IndexerOpts, pub indexer_options: IndexerOpts,

View File

@ -0,0 +1,75 @@
use std::future::{ready, Ready};
use actix_web::{
dev::{self, Service, ServiceRequest, ServiceResponse, Transform},
Error,
};
use futures_util::future::LocalBoxFuture;
use prometheus::HistogramTimer;
pub struct RouteMetrics;
// Middleware factory is `Transform` trait from actix-service crate
// `S` - type of the next service
// `B` - type of response's body
impl<S, B> Transform<S, ServiceRequest> for RouteMetrics
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = RouteMetricsMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(RouteMetricsMiddleware { service }))
}
}
pub struct RouteMetricsMiddleware<S> {
service: S,
}
impl<S, B> Service<ServiceRequest> for RouteMetricsMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
dev::forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
let mut histogram_timer: Option<HistogramTimer> = None;
let request_path = req.path();
let is_registered_resource = req.resource_map().has_resource(request_path);
if is_registered_resource {
let request_method = req.method().to_string();
histogram_timer = Some(
crate::metrics::HTTP_RESPONSE_TIME_SECONDS
.with_label_values(&[&request_method, request_path])
.start_timer(),
);
crate::metrics::HTTP_REQUESTS_TOTAL
.with_label_values(&[&request_method, request_path])
.inc();
}
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
if let Some(histogram_timer) = histogram_timer {
histogram_timer.observe_duration();
};
Ok(res)
})
}
}

View File

@ -23,7 +23,6 @@ mod tasks;
pub fn configure(cfg: &mut web::ServiceConfig) { pub fn configure(cfg: &mut web::ServiceConfig) {
cfg.service(web::scope("/tasks").configure(tasks::configure)) cfg.service(web::scope("/tasks").configure(tasks::configure))
.service(web::resource("/health").route(web::get().to(get_health))) .service(web::resource("/health").route(web::get().to(get_health)))
.service(web::resource("/metrics").route(web::get().to(get_metrics)))
.service(web::scope("/keys").configure(api_key::configure)) .service(web::scope("/keys").configure(api_key::configure))
.service(web::scope("/dumps").configure(dump::configure)) .service(web::scope("/dumps").configure(dump::configure))
.service(web::resource("/stats").route(web::get().to(get_stats))) .service(web::resource("/stats").route(web::get().to(get_stats)))