diff --git a/.prometheus/prometheus.yml b/.prometheus/prometheus.yml new file mode 100644 index 0000000..86402d5 --- /dev/null +++ b/.prometheus/prometheus.yml @@ -0,0 +1,28 @@ +global: + scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. + evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. + # scrape_timeout is set to the global default (10s). + +# Alertmanager configuration +alerting: + alertmanagers: + - static_configs: + - targets: + # - alertmanager:9093 + +# Load rules once and periodically evaluate them according to the global 'evaluation_interval'. +rule_files: + # - "first_rules.yml" + # - "second_rules.yml" + +scrape_configs: + # The job name is added as a label `job=` to any timeseries scraped from this config. + - job_name: "prometheus" + # metrics_path defaults to '/metrics' + # scheme defaults to 'http'. + static_configs: + - targets: ["localhost:9090"] + + - job_name: veryrezsi_server + static_configs: + - targets: ["veryrezsi_server:3001"] diff --git a/client/Dockerfile b/client/Dockerfile index feaa32a..dc7563e 100644 --- a/client/Dockerfile +++ b/client/Dockerfile @@ -1,4 +1,4 @@ -ARG client_url=http://localhost:3000 +ARG client_url=http://localhost:4000 ARG backend_url=http://veryrezsi_server:8000/api # Stage BUILD @@ -29,5 +29,5 @@ COPY --from=builder /app/build ./ # clean install dependencies, no devDependencies, no prepare script RUN npm ci --omit=dev --ignore-scripts --no-audit -EXPOSE 3000 +EXPOSE 4000 CMD ["node", "./index.js"] diff --git a/docker-compose.yml b/docker-compose.yml index 1d5926a..4969845 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -26,6 +26,15 @@ services: - 1025:1025 # smtp server - 8025:8025 # web ui + prometheus: + container_name: veryrezsi_prometheus + image: prom/prometheus + volumes: + - ./.prometheus:/etc/prometheus + command: --config.file=/etc/prometheus/prometheus.yml + ports: + - 9090:9090 + server: container_name: veryrezsi_server build: @@ -33,6 +42,7 @@ services: dockerfile: Dockerfile ports: - "8000:8000" + - "3001:3001" depends_on: smtp: condition: service_started @@ -45,4 +55,4 @@ services: context: ./client dockerfile: Dockerfile ports: - - "3000:3000" + - "4000:3000" diff --git a/server/Cargo.lock b/server/Cargo.lock index 442a8e6..da91140 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -388,7 +388,7 @@ dependencies = [ "serde", "tokio", "tower", - "tower-http", + "tower-http 0.4.0", "tower-layer", "tower-service", ] @@ -525,7 +525,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" dependencies = [ "borsh-derive", - "hashbrown 0.13.2", + "hashbrown 0.12.3", ] [[package]] @@ -1318,9 +1318,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" dependencies = [ "ahash 0.8.3", ] @@ -1331,7 +1331,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0761a1b9491c4f2e3d66aa0f62d0fba0af9a0e2852e4d48ea506632a4b56e6aa" dependencies = [ - "hashbrown 0.13.2", + "hashbrown 0.13.1", ] [[package]] @@ -1549,6 +1549,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + [[package]] name = "is-terminal" version = "0.4.7" @@ -1702,6 +1708,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +[[package]] +name = "mach2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" +dependencies = [ + "libc", +] + [[package]] name = "markup5ever" version = "0.10.1" @@ -1763,6 +1778,61 @@ dependencies = [ "autocfg", ] +[[package]] +name = "metrics" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde3af1a009ed76a778cb84fdef9e7dbbdf5775ae3e4cc1f434a6a307f6f76c5" +dependencies = [ + "ahash 0.8.3", + "metrics-macros", + "portable-atomic", +] + +[[package]] +name = "metrics-exporter-prometheus" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a4964177ddfdab1e3a2b37aec7cf320e14169abb0ed73999f558136409178d5" +dependencies = [ + "base64", + "hyper", + "indexmap", + "ipnet", + "metrics", + "metrics-util", + "quanta", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "metrics-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddece26afd34c31585c74a4db0630c376df271c285d682d1e55012197830b6df" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "metrics-util" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4de2ed6e491ed114b40b732e4d1659a9d53992ebd87490c44a6ffe23739d973e" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "hashbrown 0.13.1", + "metrics", + "num_cpus", + "quanta", + "sketches-ddsketch", +] + [[package]] name = "migration" version = "0.3.0" @@ -2299,6 +2369,12 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "portable-atomic" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2404,6 +2480,22 @@ dependencies = [ "sha2 0.9.9", ] +[[package]] +name = "quanta" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" +dependencies = [ + "crossbeam-utils", + "libc", + "mach2", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi", +] + [[package]] name = "quote" version = "1.0.28" @@ -2506,6 +2598,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "raw-cpuid" +version = "10.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +dependencies = [ + "bitflags", +] + [[package]] name = "rayon" version = "1.7.0" @@ -3094,6 +3195,12 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +[[package]] +name = "sketches-ddsketch" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a406c1882ed7f29cd5e248c9848a80e7cb6ae0fea82346d2746f2f941c07e1" + [[package]] name = "slab" version = "0.4.8" @@ -3528,6 +3635,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-http" version = "0.4.0" @@ -3795,11 +3921,14 @@ dependencies = [ "axum", "axum-extra", "axum-macros", + "metrics", + "metrics-exporter-prometheus", "migration", "serde", "serde_json", "tokio", "tower", + "tower-http 0.3.5", "tracing", "tracing-subscriber", "validator", diff --git a/server/Cargo.toml b/server/Cargo.toml index 57f35fb..933e082 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -14,7 +14,7 @@ members = [ [workspace.package] authors = [ "Attila Szőke ", - # TODO dönisz was here + "Dénes Javorek " ] edition = "2021" license = "MIT" @@ -28,7 +28,7 @@ chrono = "0.4.26" sea-orm = "0.11.3" serde = "1.0.163" serde_json = "1.0.96" -tokio = "1.28.2" +tokio = "1.28.2" tracing = "0.1.37" tracing-subscriber = "0.3.17" pwhash = "1.0.0" diff --git a/server/api/Cargo.toml b/server/api/Cargo.toml index 1922b0e..c0b9e7e 100644 --- a/server/api/Cargo.toml +++ b/server/api/Cargo.toml @@ -23,4 +23,7 @@ validator = { workspace = true } axum = "0.6.18" axum-extra = { version = "0.7.4", features = ["cookie-private"] } axum-macros = "0.3.7" +metrics = "0.21.1" +metrics-exporter-prometheus = "0.12.1" tower = "0.4.13" +tower-http = { version = "0.3.4", features = ["trace"] } diff --git a/server/api/src/lib.rs b/server/api/src/lib.rs index 37c812b..92f529d 100644 --- a/server/api/src/lib.rs +++ b/server/api/src/lib.rs @@ -1,7 +1,8 @@ -use std::net::SocketAddr; +use std::{future::ready, net::SocketAddr}; -use axum::{Router, Server}; +use axum::{routing::get, Router, Server}; use axum_extra::extract::cookie::Key; +use metrics_exporter_prometheus::{Matcher, PrometheusBuilder, PrometheusHandle}; use tokio::signal; use tracing::info; use veryrezsi_core::config::AppConfig; @@ -11,7 +12,13 @@ pub mod routes; #[tokio::main] pub async fn start() { - let (server_address, router) = init().await; + let config = AppConfig::init(); + let (_main_server, _metrics_server) = + tokio::join!(start_main_server(&config), start_metrics_server(&config)); +} + +pub async fn start_main_server(config: &AppConfig) { + let (server_address, router) = init(config).await; info!("Server is listening on {}...", server_address); let _ = Server::bind(&server_address) .serve(router.into_make_service()) @@ -20,10 +27,18 @@ pub async fn start() { info!("Shutting down..."); } +pub async fn start_metrics_server(config: &AppConfig) { + let (metrics_address, metrics_router) = metrics_init(config); + info!("Metrics is listening on {}...", metrics_address); + axum::Server::bind(&metrics_address) + .serve(metrics_router.into_make_service()) + .await + .unwrap() +} + /// Initializes every part of the application. -async fn init() -> (SocketAddr, Router) { +async fn init(config: &AppConfig) -> (SocketAddr, Router) { print_logo(); - let config = AppConfig::init(); info!("Initializing logging..."); tracing_subscriber::fmt() @@ -32,7 +47,7 @@ async fn init() -> (SocketAddr, Router) { info!("Successfully initialized logging"); info!("Establishing database connection..."); - let conn = veryrezsi_core::database::init(&config).await; + let conn = veryrezsi_core::database::init(config).await; info!("Successfully established database connection"); info!( @@ -54,6 +69,28 @@ async fn init() -> (SocketAddr, Router) { (config.server_address, router) } +fn metrics_init(config: &AppConfig) -> (SocketAddr, Router) { + let recorder_handle = setup_metrics_recorder(); + let router = Router::new().route("/metrics", get(move || ready(recorder_handle.render()))); + + (config.metrics_config.metrics_address, router) +} + +fn setup_metrics_recorder() -> PrometheusHandle { + const EXPONENTIAL_SECONDS: &[f64] = &[ + 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, + ]; + + PrometheusBuilder::new() + .set_buckets_for_metric( + Matcher::Full("http_requests_duration_seconds".to_string()), + EXPONENTIAL_SECONDS, + ) + .unwrap() + .install_recorder() + .unwrap() +} + fn print_logo() { println!( r#" diff --git a/server/api/src/routes.rs b/server/api/src/routes.rs index 40f7adc..ab78be6 100644 --- a/server/api/src/routes.rs +++ b/server/api/src/routes.rs @@ -1,10 +1,16 @@ use axum::{ + extract::MatchedPath, + http::Request, + middleware::{self, Next}, + response::IntoResponse, routing::{delete, get, post}, Router, }; use axum_extra::extract::cookie::Key; use axum_macros::FromRef; -use std::sync::Arc; +use std::{sync::Arc, time::Instant}; +use tower_http::trace::{self, TraceLayer}; +use tracing::Level; use veryrezsi_core::DatabaseConnection; use veryrezsi_core::{config::AppConfig, email::MailTransport}; @@ -67,5 +73,39 @@ pub fn init( mail_transport: Arc::new(mail_transport), }; - Router::new().nest("/api", api).with_state(state) + Router::new() + .nest("/api", api) + .route_layer(middleware::from_fn(track_metrics)) + .layer( + TraceLayer::new_for_http() + .make_span_with(trace::DefaultMakeSpan::new().level(Level::INFO)) + .on_response(trace::DefaultOnResponse::new().level(Level::INFO)), + ) + .with_state(state) +} + +async fn track_metrics(req: Request, next: Next) -> impl IntoResponse { + let start = Instant::now(); + let path = if let Some(matched_path) = req.extensions().get::() { + matched_path.as_str().to_owned() + } else { + req.uri().path().to_owned() + }; + let method = req.method().clone(); + + let response = next.run(req).await; + + let latency = start.elapsed().as_secs_f64(); + let status = response.status().as_u16().to_string(); + + let labels = [ + ("method", method.to_string()), + ("path", path), + ("status", status), + ]; + + metrics::increment_counter!("http_requests_total", &labels); + metrics::histogram!("http_requests_duration_seconds", latency, &labels); + + response } diff --git a/server/core/src/config.rs b/server/core/src/config.rs index 8442dc2..307183b 100644 --- a/server/core/src/config.rs +++ b/server/core/src/config.rs @@ -1,67 +1,75 @@ -use confique::Config; -use serde::Deserialize; -use std::net::SocketAddr; -use tracing::metadata::LevelFilter; - -#[derive(Debug, Clone, Config)] -pub struct AppConfig { - #[config(env = "SERVER_ADDRESS")] - pub server_address: SocketAddr, - #[config(env = "DATABASE_URL")] - pub database_url: String, - #[config(env = "COOKIE_KEY")] - pub cookie_key: String, - #[config(env = "LOG_LEVEL")] - pub log_level: LogLevel, - #[config(nested)] - pub mail_config: MailConfig, -} - -#[derive(Debug, Clone, Config)] -pub struct MailConfig { - #[config(env = "SMTP_ADDRESS")] - pub smtp_address: String, - #[config(env = "SMTP_PORT")] - pub smtp_port: u16, - #[config(env = "SMTP_USERNAME")] - pub smtp_username: String, - #[config(env = "SMTP_PASSWORD")] - pub smtp_password: String, -} - -impl AppConfig { - #[must_use] - pub fn init() -> Self { - AppConfig::builder() - .env() - .file("resources/app-config.toml") - .load() - .expect("config loading failed") - } -} - -#[derive(Debug, Clone, Deserialize)] -pub enum LogLevel { - #[serde(alias = "trace", alias = "TRACE")] - Trace, - #[serde(alias = "debug", alias = "DEBUG")] - Debug, - #[serde(alias = "info", alias = "INFO")] - Info, - #[serde(alias = "warn", alias = "WARN")] - Warn, - #[serde(alias = "error", alias = "ERROR")] - Error, -} - -impl From<&LogLevel> for LevelFilter { - fn from(l: &LogLevel) -> Self { - match l { - LogLevel::Trace => LevelFilter::TRACE, - LogLevel::Debug => LevelFilter::DEBUG, - LogLevel::Info => LevelFilter::INFO, - LogLevel::Warn => LevelFilter::WARN, - LogLevel::Error => LevelFilter::ERROR, - } - } -} +use confique::Config; +use serde::Deserialize; +use std::net::SocketAddr; +use tracing::metadata::LevelFilter; + +#[derive(Debug, Clone, Config)] +pub struct AppConfig { + #[config(env = "SERVER_ADDRESS")] + pub server_address: SocketAddr, + #[config(env = "DATABASE_URL")] + pub database_url: String, + #[config(env = "COOKIE_KEY")] + pub cookie_key: String, + #[config(env = "LOG_LEVEL")] + pub log_level: LogLevel, + #[config(nested)] + pub mail_config: MailConfig, + #[config(nested)] + pub metrics_config: MetricsConfig, +} + +#[derive(Debug, Clone, Config)] +pub struct MailConfig { + #[config(env = "SMTP_ADDRESS")] + pub smtp_address: String, + #[config(env = "SMTP_PORT")] + pub smtp_port: u16, + #[config(env = "SMTP_USERNAME")] + pub smtp_username: String, + #[config(env = "SMTP_PASSWORD")] + pub smtp_password: String, +} + +#[derive(Debug, Clone, Config)] +pub struct MetricsConfig { + #[config(env = "METRICS_ADDRESS")] + pub metrics_address: SocketAddr, +} + +impl AppConfig { + #[must_use] + pub fn init() -> Self { + AppConfig::builder() + .env() + .file("resources/app-config.toml") + .load() + .expect("config loading failed") + } +} + +#[derive(Debug, Clone, Deserialize)] +pub enum LogLevel { + #[serde(alias = "trace", alias = "TRACE")] + Trace, + #[serde(alias = "debug", alias = "DEBUG")] + Debug, + #[serde(alias = "info", alias = "INFO")] + Info, + #[serde(alias = "warn", alias = "WARN")] + Warn, + #[serde(alias = "error", alias = "ERROR")] + Error, +} + +impl From<&LogLevel> for LevelFilter { + fn from(l: &LogLevel) -> Self { + match l { + LogLevel::Trace => LevelFilter::TRACE, + LogLevel::Debug => LevelFilter::DEBUG, + LogLevel::Info => LevelFilter::INFO, + LogLevel::Warn => LevelFilter::WARN, + LogLevel::Error => LevelFilter::ERROR, + } + } +} diff --git a/server/core/src/dto/users.rs b/server/core/src/dto/users.rs index 3ca022d..7dece8c 100644 --- a/server/core/src/dto/users.rs +++ b/server/core/src/dto/users.rs @@ -55,7 +55,9 @@ pub struct NewUserRequest { /// Password validation function supplied to `NewUserRequest`. fn validate_password(value: &str) -> Result<(), ValidationError> { let Ok(result) = PASSWORD_REGEX.is_match(value) else { - return Err(ValidationError::new("password cannot be matched against regex")); + return Err(ValidationError::new( + "password cannot be matched against regex", + )); }; if !result { return Err(ValidationError::new("password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number and one special character")); diff --git a/server/core/src/logic/common.rs b/server/core/src/logic/common.rs index 60a4c68..ac037a3 100644 --- a/server/core/src/logic/common.rs +++ b/server/core/src/logic/common.rs @@ -23,7 +23,7 @@ pub mod tests { use sea_orm::{DatabaseBackend, DeriveActiveModelBehavior, DeriveEntityModel, MockDatabase}; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - use crate::config::{AppConfig, MailConfig}; + use crate::config::{AppConfig, MailConfig, MetricsConfig}; use crate::logic::common::find_entity_by_id; pub const TEST_STR: &str = "test"; @@ -128,6 +128,9 @@ pub mod tests { smtp_username: TEST_STR.to_string(), smtp_password: TEST_STR.to_string(), }, + metrics_config: MetricsConfig { + metrics_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 3001), + }, }; } diff --git a/server/core/src/logic/expense_operations.rs b/server/core/src/logic/expense_operations.rs index eacaac8..d1631b5 100644 --- a/server/core/src/logic/expense_operations.rs +++ b/server/core/src/logic/expense_operations.rs @@ -48,7 +48,7 @@ pub async fn find_expenses_by_user_id( let recurrences = recurrences?; assert!( - vec![predefined_expenses.len(), grouped_transactions.len()] + [predefined_expenses.len(), grouped_transactions.len()] .iter() .all(|&x| x == expenses.len()), "the lengths of the fetched expense related lists should always be equal" @@ -141,7 +141,7 @@ pub async fn find_predefined_expenses( let mut recurrences: VecDeque = recurrences?.into_iter().flatten().collect(); assert!( - vec![currencies.len(), recurrences.len()] + [currencies.len(), recurrences.len()] .iter() .all(|&x| x == predefined_expenses.len()), "the lengths of the fetched predefined expense related lists should be equal" @@ -193,10 +193,10 @@ async fn validate_recurrence_and_currency( find_entity_by_id::(conn, currency_id) ); let Some(_) = referred_currency? else { - return Err(ValidateRecurrenceAndCurrencyError::InvalidCurrency) + return Err(ValidateRecurrenceAndCurrencyError::InvalidCurrency); }; let Some(_) = referred_recurrence? else { - return Err(ValidateRecurrenceAndCurrencyError::InvalidRecurrence) + return Err(ValidateRecurrenceAndCurrencyError::InvalidRecurrence); }; Ok(()) } diff --git a/server/core/src/logic/transaction_operations.rs b/server/core/src/logic/transaction_operations.rs index ba82e40..8589e02 100644 --- a/server/core/src/logic/transaction_operations.rs +++ b/server/core/src/logic/transaction_operations.rs @@ -47,10 +47,12 @@ pub async fn delete_transaction_by_id( user_id: Id, transaction_id: Id, ) -> Result<(), DeleteTransactionByIdError> { - let Some(transaction) = find_entity_by_id::(conn, transaction_id).await? else { + let Some(transaction) = find_entity_by_id::(conn, transaction_id).await? + else { return Err(DeleteTransactionByIdError::InvalidTransaction); }; - let Some(expense) = find_entity_by_id::(conn, transaction.expense_id).await? else { + let Some(expense) = find_entity_by_id::(conn, transaction.expense_id).await? + else { return Err(DeleteTransactionByIdError::InvalidTransaction); }; authorize_user(user_id, expense.user_id)?; diff --git a/server/core/src/logic/user_operations.rs b/server/core/src/logic/user_operations.rs index e6a946c..a3f01e7 100644 --- a/server/core/src/logic/user_operations.rs +++ b/server/core/src/logic/user_operations.rs @@ -37,9 +37,10 @@ pub async fn verify_login( let Some(user) = User::find() .filter(user::Column::Email.eq(&req.email)) .one(conn) - .await? else { - return Err( VerifyLoginError::IncorrectCredentials); - }; + .await? + else { + return Err(VerifyLoginError::IncorrectCredentials); + }; if !user.activated { return Err(VerifyLoginError::AccountNotActivated); }; @@ -62,9 +63,10 @@ where let None = User::find() .filter(user::Column::Email.eq(&req.email)) .one(conn) - .await? else { - return Err(SaveUserError::UserAlreadyExists) - }; + .await? + else { + return Err(SaveUserError::UserAlreadyExists); + }; let pw_hash = match bcrypt::hash(req.password) { Ok(hashed) => hashed, @@ -120,7 +122,8 @@ pub async fn activate_account( let Some(account_activation) = AccountActivation::find() .filter(account_activation::Column::Token.eq(token.clone())) .one(conn) - .await? else { + .await? + else { return Err(ActivateAccountError::InvalidToken); }; @@ -130,7 +133,8 @@ pub async fn activate_account( let Some(user) = User::find_by_id(account_activation.user_id) .one(conn) - .await? else { + .await? + else { return Err(ActivateAccountError::InvalidToken); }; diff --git a/server/docker/config/app-config.toml b/server/docker/config/app-config.toml index 390233f..f6c4fc8 100644 --- a/server/docker/config/app-config.toml +++ b/server/docker/config/app-config.toml @@ -8,3 +8,6 @@ smtp_address = "veryrezsi_smtp" smtp_port = 1025 smtp_username = "" smtp_password = "" + +[metrics_config] +metrics_address = "0.0.0.0:3001" diff --git a/server/resources/app-config.toml b/server/resources/app-config.toml index ae944bb..65c761c 100644 --- a/server/resources/app-config.toml +++ b/server/resources/app-config.toml @@ -9,3 +9,6 @@ smtp_port = 1025 # Credentials are not in use on dev environment smtp_username = "" smtp_password = "" + +[metrics_config] +metrics_address = "127.0.0.1:3001"