metrics_basic/
metrics_basic.rs

1use autometrics::autometrics;
2use log::info;
3use rs_infras::logger::Logger;
4use rs_infras::metrics::{API_SLO, prometheus_init};
5use std::net::SocketAddr;
6use std::process;
7use std::time::Duration;
8// 引入axum相关包
9use axum::{Json, Router, http::StatusCode, response::IntoResponse, routing::get};
10use rs_infras::shutdown::graceful_shutdown;
11use serde::{Deserialize, Serialize};
12use tokio::net::TcpListener;
13
14// cargo run --example metrics_basic
15// 如果想在启动时改变日志级别,可以通过指定环境变量启动应用
16// 日志level 优先级  error > warn > info > debug > trace
17// 启动方式:RUST_LOG=info cargo run --example metrics_basic
18#[tokio::main]
19async fn main() {
20    Logger::new().init();
21    info!("current process pid:{}", process::id());
22    info!("service start...");
23
24    // build http /metrics endpoint
25    let metrics_port = 8090;
26    let metrics_server = prometheus_init(metrics_port);
27    let metrics_handler = tokio::spawn(metrics_server);
28
29    let app_port = 8080;
30    // http handler
31    let http_handler = tokio::spawn(async move {
32        let address: SocketAddr = format!("0.0.0.0:{}", app_port).parse().unwrap();
33
34        info!("http server run on:{}", address.to_string());
35
36        // Create axum router
37        let router = api_router();
38
39        // Create a `TcpListener` using tokio.
40        let listener = TcpListener::bind(address).await.unwrap();
41
42        // Run the server with graceful shutdown
43        let graceful_wait_time = 5;
44        axum::serve(listener, router)
45            .with_graceful_shutdown(graceful_shutdown(Duration::from_secs(graceful_wait_time)))
46            .await
47            .expect("failed to start gateway service");
48    });
49
50    // start http gateway and metrics service
51    let _ = tokio::try_join!(http_handler, metrics_handler)
52        .expect("failed to start http gateway and metrics service");
53}
54
55// create api router
56pub fn api_router() -> Router {
57    // set api group and not found handler for api/xxx
58    let api_routers = Router::new()
59        .route("/", get(root))
60        .route("/home", get(home))
61        .fallback(api_not_found);
62
63    let router = Router::new()
64        .nest("/api", api_routers)
65        .route("/", get(root))
66        .fallback(not_found_handler);
67
68    router
69}
70
71#[autometrics]
72pub async fn root() -> &'static str {
73    "Hello, World!"
74}
75
76#[autometrics(objective = API_SLO)]
77// 也可以使用下面的方式,简单处理
78// #[autometrics]
79pub async fn home() -> &'static str {
80    "Hello, home!"
81}
82
83#[derive(Deserialize, Serialize, Debug)]
84pub struct Reply<T> {
85    pub code: i32,
86    pub message: String,
87    pub data: Option<T>,
88}
89
90// empty object,like {}
91#[derive(Deserialize, Serialize, Debug)]
92pub struct EmptyObject {}
93
94// api handler not found
95async fn api_not_found() -> impl IntoResponse {
96    (
97        StatusCode::NOT_FOUND,
98        Json(Reply {
99            code: 404,
100            message: "api not found".to_string(),
101            data: Some(EmptyObject {}),
102        }),
103    )
104}
105
106// handler not found for global router not found
107async fn not_found_handler() -> impl IntoResponse {
108    (StatusCode::NOT_FOUND, "this page not found")
109}