From bb559402a8f170865dc44bcf8c0d62ee4acdc35f Mon Sep 17 00:00:00 2001 From: Paul Tagliamonte Date: Tue, 8 Oct 2024 21:53:20 -0400 Subject: [PATCH] export prom metrics from the printer (#121) add in prom metrics to export machine information where available --- Cargo.lock | 109 ++++++++++++++++++------------- Cargo.toml | 1 + moonraker/src/lib.rs | 1 + openapi/api-tags.txt | 4 ++ openapi/api.json | 35 ++++++++++ openapi/tag-config.json | 6 ++ src/bin/machine-api/cmd_serve.rs | 102 +++++++++++++++++++++++++++-- src/moonraker/mod.rs | 6 ++ src/server/context.rs | 7 +- src/server/endpoints.rs | 18 ++++- src/server/mod.rs | 25 +++++-- src/server/raw.rs | 22 +++++++ src/tests.rs | 12 ++-- 13 files changed, 285 insertions(+), 63 deletions(-) create mode 100644 src/server/raw.rs diff --git a/Cargo.lock b/Cargo.lock index 76b341d..1755b6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -297,9 +297,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.24" +version = "1.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" +checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" dependencies = [ "shlex", ] @@ -325,9 +325,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.19" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -335,9 +335,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.19" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -627,6 +627,12 @@ dependencies = [ "syn", ] +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + [[package]] name = "dyn-clone" version = "1.0.17" @@ -756,9 +762,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -787,9 +793,9 @@ checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -866,9 +872,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -1049,7 +1055,7 @@ dependencies = [ "http", "hyper", "hyper-util", - "rustls 0.23.13", + "rustls 0.23.14", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -1181,9 +1187,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is-terminal" @@ -1345,6 +1351,7 @@ dependencies = [ "opentelemetry_sdk", "portpicker", "pretty_assertions", + "prometheus-client", "rand", "reqwest", "schemars", @@ -1624,21 +1631,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.20.1" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" -dependencies = [ - "portable-atomic", -] +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openapiv3" @@ -1828,18 +1832,18 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", @@ -1864,12 +1868,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" -[[package]] -name = "portable-atomic" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" - [[package]] name = "portpicker" version = "0.1.1" @@ -1906,13 +1904,36 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] +[[package]] +name = "prometheus-client" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" +dependencies = [ + "dtoa", + "itoa", + "parking_lot", + "prometheus-client-derive-encode", +] + +[[package]] +name = "prometheus-client-derive-encode" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "prost" version = "0.13.3" @@ -1956,7 +1977,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.13", + "rustls 0.23.14", "socket2", "thiserror", "tokio", @@ -1973,7 +1994,7 @@ dependencies = [ "rand", "ring", "rustc-hash", - "rustls 0.23.13", + "rustls 0.23.14", "slab", "thiserror", "tinyvec", @@ -2125,7 +2146,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.13", + "rustls 0.23.14", "rustls-pemfile", "rustls-pki-types", "serde", @@ -2219,9 +2240,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.13" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" dependencies = [ "once_cell", "ring", @@ -2284,9 +2305,9 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schannel" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ "windows-sys 0.59.0", ] @@ -2867,7 +2888,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.13", + "rustls 0.23.14", "rustls-pki-types", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index e5f62a3..3c5acd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ multer = { version = "3.1.0", features = ["json"] } opentelemetry = "0.25.0" opentelemetry-otlp = "0.25.0" opentelemetry_sdk = { version = "0.25.0", features = ["rt-tokio"] } +prometheus-client = "0.22.3" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } schemars = { version = "0.8", features = ["chrono", "uuid1", "bigdecimal"] } serde = { version = "1.0", features = ["derive"] } diff --git a/moonraker/src/lib.rs b/moonraker/src/lib.rs index 538fa1e..be6ba11 100644 --- a/moonraker/src/lib.rs +++ b/moonraker/src/lib.rs @@ -21,6 +21,7 @@ pub use print::InfoResponse; pub use upload::{DeleteResponse, DeleteResponseItem, UploadResponse, UploadResponseItem}; /// Client is a moonraker instance which can accept gcode for printing. +#[derive(Clone, Debug, PartialEq)] pub struct Client { pub(crate) url_base: String, } diff --git a/openapi/api-tags.txt b/openapi/api-tags.txt index 84b9544..fef1ee4 100644 --- a/openapi/api-tags.txt +++ b/openapi/api-tags.txt @@ -1,3 +1,7 @@ +API operations found with tag "hidden" +OPERATION ID URL PATH +get_metrics /metrics + API operations found with tag "machines" OPERATION ID URL PATH get_machine /machines/{id} diff --git a/openapi/api.json b/openapi/api.json index f960588..8b7295b 100644 --- a/openapi/api.json +++ b/openapi/api.json @@ -425,6 +425,34 @@ ] } }, + "/metrics": { + "get": { + "operationId": "get_metrics", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "title": "String", + "type": "string" + } + } + }, + "description": "successful operation" + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + }, + "summary": "List available machines and their statuses", + "tags": [ + "hidden" + ] + } + }, "/ping": { "get": { "operationId": "ping", @@ -492,6 +520,13 @@ } }, "tags": [ + { + "description": "Hidden API endpoints that should not show up in the docs.", + "externalDocs": { + "url": "https://docs.zoo.dev/api/machines" + }, + "name": "hidden" + }, { "description": "Utilities for making parts and discovering machines.", "externalDocs": { diff --git a/openapi/tag-config.json b/openapi/tag-config.json index 7127ec6..32d7c54 100644 --- a/openapi/tag-config.json +++ b/openapi/tag-config.json @@ -13,6 +13,12 @@ "external_docs": { "url": "https://docs.zoo.dev/api/machines" } + }, + "hidden": { + "description": "Hidden API endpoints that should not show up in the docs.", + "external_docs": { + "url": "https://docs.zoo.dev/api/machines" + } } } } diff --git a/src/bin/machine-api/cmd_serve.rs b/src/bin/machine-api/cmd_serve.rs index 75030ce..31c03ad 100644 --- a/src/bin/machine-api/cmd_serve.rs +++ b/src/bin/machine-api/cmd_serve.rs @@ -1,10 +1,89 @@ -use std::{collections::HashMap, net::SocketAddr, sync::Arc}; - +use super::{Cli, Config}; use anyhow::Result; -use machine_api::server; +use machine_api::{moonraker, server, AnyMachine}; +use prometheus_client::{ + metrics::gauge::Gauge, + registry::{Registry, Unit}, +}; +use std::{ + collections::HashMap, + net::SocketAddr, + sync::{atomic::AtomicU64, Arc}, +}; use tokio::sync::RwLock; -use super::{Cli, Config}; +/// Long-term this should get a new trait, and a MachineT: Metrics / generic +/// param on this function. +/// +/// For now we can just do this for moonraker (and maybe one or two others) +/// before we refine the API. +async fn spawn_metrics_moonraker(registry: &mut Registry, key: &str, machine: &moonraker::Client) { + let registry = registry.sub_registry_with_label(("id".into(), key.to_owned().into())); + + let machine = machine.clone(); + + let extruder_temperature = Gauge::::default(); + registry.register_with_unit( + "extruder_temperature", + "Last temp of the extruder", + Unit::Celsius, + extruder_temperature.clone(), + ); + + let extruder_temperature_target = Gauge::::default(); + registry.register_with_unit( + "extruder_temperature_target", + "Target temp of the extruder", + Unit::Celsius, + extruder_temperature_target.clone(), + ); + + let bed_temperature = Gauge::::default(); + registry.register_with_unit( + "bed_temperature", + "Last temp of the bed", + Unit::Celsius, + bed_temperature.clone(), + ); + + let bed_temperature_target = Gauge::::default(); + registry.register_with_unit( + "bed_temperature_target", + "Target temp of the bed", + Unit::Celsius, + bed_temperature_target.clone(), + ); + + let key = key.to_owned(); + tokio::spawn(async move { + let key = key; + let machine = machine; + let extruder_temperature = extruder_temperature; + let extruder_temperature_target = extruder_temperature_target; + let bed_temperature = bed_temperature; + let bed_temperature_target = bed_temperature_target; + + loop { + let Ok(readings) = machine.get_client().temperatures().await else { + tracing::warn!("failed to collect temperatures from {}", key); + continue; + }; + tracing::trace!("metrics collected from {}", key); + + // TODO: collect last N values and avg? + + extruder_temperature.set(*readings.extruder.temperatures.last().unwrap_or(&0.0)); + extruder_temperature_target.set(*readings.extruder.targets.last().unwrap_or(&0.0)); + + if let Some(heater_bed) = readings.heater_bed { + bed_temperature.set(*heater_bed.temperatures.last().unwrap_or(&0.0)); + bed_temperature_target.set(*heater_bed.targets.last().unwrap_or(&0.0)); + } + + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + } + }); +} pub async fn main(_cli: &Cli, cfg: &Config, bind: &str) -> Result<()> { let machines = Arc::new(RwLock::new(HashMap::new())); @@ -14,6 +93,19 @@ pub async fn main(_cli: &Cli, cfg: &Config, bind: &str) -> Result<()> { cfg.create_noop(machines.clone()).await?; cfg.create_moonraker(machines.clone()).await?; + let mut registry = Registry::default(); + for (key, machine) in machines.read().await.iter() { + let machine = machine.read().await; + let any_machine = machine.get_machine(); + + match &any_machine { + AnyMachine::Moonraker(moonraker) => { + spawn_metrics_moonraker(&mut registry, key, moonraker).await; + } + _ => { /* Nothing to do here! */ } + } + } + let bind_addr: SocketAddr = bind.parse()?; tokio::spawn(async move { let bind_addr = bind_addr; @@ -31,6 +123,6 @@ pub async fn main(_cli: &Cli, cfg: &Config, bind: &str) -> Result<()> { ); }); - server::serve(bind, machines).await?; + server::serve(bind, machines, registry).await?; Ok(()) } diff --git a/src/moonraker/mod.rs b/src/moonraker/mod.rs index 4f2ad9e..991294b 100644 --- a/src/moonraker/mod.rs +++ b/src/moonraker/mod.rs @@ -25,6 +25,7 @@ pub struct Config { } /// Client is a connection to a Moonraker instance. +#[derive(Clone)] pub struct Client { client: MoonrakerClient, make_model: MachineMakeModel, @@ -41,4 +42,9 @@ impl Client { client: MoonrakerClient::new(base_url)?, }) } + + /// Return the underling [MoonrakerClient]. + pub fn get_client(&self) -> &MoonrakerClient { + &self.client + } } diff --git a/src/server/context.rs b/src/server/context.rs index 1b6533d..cb2877e 100644 --- a/src/server/context.rs +++ b/src/server/context.rs @@ -1,8 +1,8 @@ use std::{collections::HashMap, sync::Arc}; -use tokio::sync::RwLock; - use crate::Machine; +use prometheus_client::registry::Registry; +use tokio::sync::RwLock; /// Context for a given server -- this contains all the informatio required /// to serve a Machine-API request. @@ -13,4 +13,7 @@ pub struct Context { /// List of [Machine] objects to serve via the Machine API. pub machines: Arc>>>, + + /// Prom registry for metrics + pub registry: Registry, } diff --git a/src/server/endpoints.rs b/src/server/endpoints.rs index 27a16bf..951e675 100644 --- a/src/server/endpoints.rs +++ b/src/server/endpoints.rs @@ -4,7 +4,7 @@ use dropshot::{endpoint, HttpError, Path, RequestContext}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use super::{Context, CorsResponseOk}; +use super::{Context, CorsResponseOk, RawResponseOk}; use crate::{ AnyMachine, Control, DesignFile, MachineInfo, MachineMakeModel, MachineState, MachineType, TemporaryFile, Volume, }; @@ -131,6 +131,22 @@ pub async fn get_machines( Ok(CorsResponseOk(machines)) } +/// List available machines and their statuses +#[endpoint { + method = GET, + path = "/metrics", + tags = ["hidden"], +}] +pub async fn get_metrics(rqctx: RequestContext>) -> Result { + let ctx = rqctx.context(); + let mut response = String::new(); + + prometheus_client::encoding::text::encode(&mut response, &ctx.registry) + .map_err(|e| HttpError::for_internal_error(format!("{:?}", e)))?; + + Ok(RawResponseOk(response)) +} + /// The path parameters for performing operations on an machine. #[derive(Deserialize, Debug, JsonSchema, Serialize)] pub struct MachinePathParams { diff --git a/src/server/mod.rs b/src/server/mod.rs index b9cc32d..09af22f 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -3,17 +3,20 @@ mod context; mod cors; mod endpoints; +mod raw; -use std::{collections::HashMap, env, net::SocketAddr, sync::Arc}; - -use anyhow::{anyhow, Result}; pub use context::Context; pub use cors::CorsResponseOk; +pub use raw::RawResponseOk; + +use anyhow::{anyhow, Result}; use dropshot::{ApiDescription, ConfigDropshot, HttpServerStarter}; +use prometheus_client::registry::Registry; use signal_hook::{ consts::{SIGINT, SIGTERM}, iterator::Signals, }; +use std::{collections::HashMap, env, net::SocketAddr, sync::Arc}; use tokio::sync::RwLock; use crate::Machine; @@ -26,6 +29,7 @@ pub fn create_api_description() -> Result>> { api.register(endpoints::print_file).unwrap(); api.register(endpoints::get_machines).unwrap(); api.register(endpoints::get_machine).unwrap(); + api.register(endpoints::get_metrics).unwrap(); // YOUR ENDPOINTS HERE! @@ -47,6 +51,7 @@ pub fn create_api_description() -> Result>> { pub async fn create_server( bind: &str, machines: Arc>>>, + registry: Registry, ) -> Result<(dropshot::HttpServer>, Arc)> { let mut api = create_api_description()?; let schema = get_openapi(&mut api)?; @@ -58,7 +63,11 @@ pub async fn create_server( log_headers: Default::default(), }; - let api_context = Arc::new(Context { schema, machines }); + let api_context = Arc::new(Context { + schema, + machines, + registry, + }); let server = HttpServerStarter::new( &config_dropshot, @@ -85,8 +94,12 @@ pub fn get_openapi(api: &mut ApiDescription>) -> Result>>>) -> Result<()> { - let (server, _api_context) = create_server(bind, machines).await?; +pub async fn serve( + bind: &str, + machines: Arc>>>, + registry: Registry, +) -> Result<()> { + let (server, _api_context) = create_server(bind, machines, registry).await?; let addr: SocketAddr = bind.parse()?; let responder = libmdns::Responder::new().unwrap(); diff --git a/src/server/raw.rs b/src/server/raw.rs new file mode 100644 index 0000000..e026213 --- /dev/null +++ b/src/server/raw.rs @@ -0,0 +1,22 @@ +use dropshot::{Body, HttpCodedResponse, HttpError}; +use http::{Response, StatusCode}; + +/// Return an HTTP Response OK, but with CORS. +pub struct RawResponseOk(pub String); + +impl HttpCodedResponse for RawResponseOk { + type Body = String; + + const STATUS_CODE: StatusCode = StatusCode::OK; + const DESCRIPTION: &'static str = "successful operation"; +} + +impl From for Result, HttpError> { + fn from(rrok: RawResponseOk) -> Result, HttpError> { + Ok(Response::builder() + .status(StatusCode::OK) + .header(http::header::CONTENT_TYPE, "text/plain") + .header("access-control-allow-origin", "*") + .body(Body::from(rrok.0))?) + } +} diff --git a/src/tests.rs b/src/tests.rs index 7d2c33a..914c279 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,11 +1,11 @@ +use anyhow::{Context, Result}; +use expectorate::assert_contents; +use pretty_assertions::assert_eq; +use prometheus_client::registry::Registry; use std::{ collections::{BTreeMap, HashMap}, sync::Arc, }; - -use anyhow::{Context, Result}; -use expectorate::assert_contents; -use pretty_assertions::assert_eq; use test_context::{test_context, AsyncTestContext}; use testresult::TestResult; use tokio::sync::RwLock; @@ -21,9 +21,11 @@ impl ServerContext { // Find an unused port. let port = portpicker::pick_unused_port().ok_or_else(|| anyhow::anyhow!("no port available"))?; let bind = format!("127.0.0.1:{}", port); + let registry = Registry::default(); // Create the server in debug mode. - let (server, _context) = crate::server::create_server(&bind, Arc::new(RwLock::new(HashMap::new()))).await?; + let (server, _context) = + crate::server::create_server(&bind, Arc::new(RwLock::new(HashMap::new())), registry).await?; // Sleep for 5 seconds while the server is comes up. std::thread::sleep(std::time::Duration::from_secs(5));