1#![forbid(unsafe_code)]
4
5use jerrycan_core::{App, Extension, IntoResponse, Response, get};
6use std::sync::Arc;
7
8pub mod access_log;
9pub mod metrics;
10
11pub use metrics::Metrics;
12
13pub struct Observe {
16 metrics: Arc<Metrics>,
17}
18
19impl Observe {
20 pub fn new() -> Self {
21 Self {
22 metrics: Arc::new(Metrics::new()),
23 }
24 }
25}
26
27impl Default for Observe {
28 fn default() -> Self {
29 Self::new()
30 }
31}
32
33impl Extension for Observe {
34 fn register(self, app: App) -> App {
35 let metrics_for_mw = self.metrics.clone();
36 let metrics_for_route = self.metrics.clone();
37 app.middleware(access_log::AccessLog {
38 metrics: metrics_for_mw,
39 })
40 .route("/healthz", get(|| async { "ok" }))
41 .route(
42 "/metrics",
43 get(move || {
44 let metrics = metrics_for_route.clone();
45 async move { prometheus_response(metrics.render()) }
46 }),
47 )
48 }
49}
50
51pub fn init_logging() {
54 use tracing_subscriber::{EnvFilter, fmt};
55 let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
56 let _ = fmt().json().with_env_filter(filter).try_init();
57}
58
59fn prometheus_response(body: String) -> Response {
60 let mut response = body.into_response();
61 response.headers_mut().insert(
62 jerrycan_core::http::header::CONTENT_TYPE,
63 jerrycan_core::http::HeaderValue::from_static("text/plain; version=0.0.4"),
64 );
65 response
66}