From 0591f5b3ab45022e84273d7140a49d1d900f8289 Mon Sep 17 00:00:00 2001 From: Riordan Panayides Date: Mon, 29 May 2023 18:37:03 +0100 Subject: [PATCH] Add request metrics to server --- Cargo.lock | 35 +++++++++++++++++++++ Cargo.toml | 4 ++- src/server/main.rs | 77 ++++++++++++++++++++++++++++++++++++---------- 3 files changed, 98 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99f3efb..2093321 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -191,6 +191,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "actix-web-prom" +version = "0.6.0" +source = "git+https://github.com/riordanp/actix-web-prom.git?branch=exclude-paths#614434270cbcfdffa2b3a854aff4c1e49c4973fd" +dependencies = [ + "actix-web", + "futures-core", + "pin-project-lite", + "prometheus", + "regex", +] + [[package]] name = "adler" version = "1.0.2" @@ -3423,6 +3435,7 @@ name = "openbook-candles" version = "0.1.0" dependencies = [ "actix-web", + "actix-web-prom", "anchor-client", "anchor-lang", "anyhow", @@ -3443,6 +3456,7 @@ dependencies = [ "num-traits", "num_enum 0.6.1", "postgres-native-tls", + "prometheus", "serde", "serde_derive", "serde_json", @@ -3966,6 +3980,21 @@ dependencies = [ "yansi", ] +[[package]] +name = "prometheus" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +dependencies = [ + "cfg-if 1.0.0", + "fnv", + "lazy_static", + "memchr", + "parking_lot 0.12.1", + "protobuf", + "thiserror", +] + [[package]] name = "prost" version = "0.11.6" @@ -4021,6 +4050,12 @@ dependencies = [ "prost", ] +[[package]] +name = "protobuf" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" + [[package]] name = "protobuf-src" version = "1.1.0+21.5" diff --git a/Cargo.toml b/Cargo.toml index 002d5fc..cf5ef4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,9 +62,11 @@ serum_dex = { version = "0.5.10", git = "https://github.com/openbook-dex/program anchor-lang = ">=0.25.0" actix-web = "4" +actix-web-prom = { version = "0.6.0", git = "https://github.com/riordanp/actix-web-prom.git", branch = "exclude-paths" } arrayref = "0.3.6" bytemuck = "1.12.3" num_enum = "0.6.1" -config = "0.13.1" \ No newline at end of file +config = "0.13.1" +prometheus = "0.13.3" diff --git a/src/server/main.rs b/src/server/main.rs index d319727..a940956 100644 --- a/src/server/main.rs +++ b/src/server/main.rs @@ -1,9 +1,12 @@ use actix_web::{ middleware::Logger, + rt::System, web::{self, Data}, - App, HttpServer, + App, HttpServer, http::StatusCode, }; +use actix_web_prom::PrometheusMetricsBuilder; use candles::get_candles; +use prometheus::Registry; use markets::get_markets; use openbook_candles::{ @@ -12,6 +15,7 @@ use openbook_candles::{ utils::{Config, WebContext}, }; use std::env; +use std::thread; use traders::{get_top_traders_by_base_volume, get_top_traders_by_quote_volume}; mod candles; @@ -39,6 +43,22 @@ async fn main() -> std::io::Result<()> { let market_infos = fetch_market_infos(&config, markets).await.unwrap(); let pool = connect_to_database().await.unwrap(); + let registry = Registry::new(); + // For serving metrics on a private port + let private_metrics = PrometheusMetricsBuilder::new("openbook_candles_server_private") + .registry(registry.clone()) + .exclude("/metrics") + .exclude_status(StatusCode::NOT_FOUND) + .endpoint("/metrics") + .build() + .unwrap(); + // For collecting metrics on the public api, excluding 404s + let public_metrics = PrometheusMetricsBuilder::new("openbook_candles_server") + .registry(registry.clone()) + .exclude_status(StatusCode::NOT_FOUND) + .build() + .unwrap(); + let context = Data::new(WebContext { rpc_url, pool, @@ -46,20 +66,43 @@ async fn main() -> std::io::Result<()> { }); println!("Starting server"); - HttpServer::new(move || { - App::new() - .wrap(Logger::default()) - .app_data(context.clone()) - .service( - web::scope("/api") - .service(get_candles) - .service(get_top_traders_by_base_volume) - .service(get_top_traders_by_quote_volume) - .service(get_markets) - .service(coingecko::service()), - ) - }) - .bind(&bind_addr)? - .run() - .await + // Thread to serve public API + let public_server = thread::spawn(move || { + let sys = System::new(); + let srv = HttpServer::new(move || { + App::new() + .wrap(Logger::default()) + .wrap(public_metrics.clone()) + .app_data(context.clone()) + .service( + web::scope("/api") + .service(get_candles) + .service(get_top_traders_by_base_volume) + .service(get_top_traders_by_quote_volume) + .service(get_markets) + .service(coingecko::service()), + ) + }) + .bind(&bind_addr) + .unwrap() + .run(); + sys.block_on(srv).unwrap(); + }); + + // Thread to serve metrics endpoint privately + let private_server = thread::spawn(move || { + let sys = System::new(); + let srv = HttpServer::new(move || { + App::new() + .wrap(private_metrics.clone()) + }) + .bind("0.0.0.0:9091") + .unwrap() + .run(); + sys.block_on(srv).unwrap(); + }); + + private_server.join().unwrap(); + public_server.join().unwrap(); + Ok(()) }