Skip to content

Commit

Permalink
feat: add health checks, metrics, and service abstractions for databa…
Browse files Browse the repository at this point in the history
…se and keystore.
  • Loading branch information
Tekum-Emmanuella committed Nov 27, 2024
1 parent f893480 commit db689f6
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 4 deletions.
11 changes: 7 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ categories = ["cryptography", "decentralized-systems"]
edition = "2021"
readme = "README.md"



[workspace]
members = [
"crates/database",
Expand All @@ -26,7 +24,6 @@ members = [
"crates/web-plugins/didcomm-messaging/protocols/*",
]


[workspace.dependencies]
database = { path = "./crates/database", version = "0.1.0" }
filesystem = { path = "./crates/filesystem", version = "0.1.0" }
Expand All @@ -49,6 +46,10 @@ cfg-if = "0.1"
getrandom = "0.2"
hyper-tls = "0.5.0"
json-patch = "1.0.0"
actix-web = "4.0" # Add this line for actix_web
sysinfo = "0.21" # Add this line for sysinfo
actix-web-prom = "0.4" # Add this line for actix_web_pro
tower-http = { version = "0.4.3", features = ["trace", "catch-panic"] }
x25519-dalek = "2.0.0-rc.3"
multibase = "0.8.0"
json-canon = "0.1.3"
Expand Down Expand Up @@ -83,7 +84,6 @@ parking_lot = "0.12.0"
curve25519-dalek = "4.0.0-rc.3"
ed25519-dalek = "2.0.0-rc.3"
tracing-subscriber = "0.3.17"
tower-http = "0.4.3"
base64ct = { version = "1.6.0", default-features = false }
zeroize = { version = "1.6.0", default-features = false }

Expand Down Expand Up @@ -117,6 +117,9 @@ default = [
"plugin-didcomm_messaging",
]

stateless = []
stateful = []

plugin-index = ["dep:chrono"]
plugin-did_endpoint = ["dep:did-endpoint"]
plugin-oob_messages = ["dep:oob-messages"]
Expand Down
34 changes: 34 additions & 0 deletions crates/database/src/database.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use std::time::Duration;
use tokio::time::sleep;
use premetheus::{IntCounterVec, Opts};
use tracing::info;
use lazy_static::lazy_static;

// Simulated health metric for the database
lazy_static::lazy_static! {
pub static ref DB_HEALTH_COUNTER: IntCounterVec = IntCounterVec::new(
Opts::new("database_health", "Counts database health check results"),
&["status"]
).unwrap();
}

pub struct Database;

impl Database {
pub fn new() -> Self {
Database
}

// Simulated health check
pub async fn check_health(&self) -> bool {
sleep(Duration::from_secs(2)).await; // Simulate a delay
let status = "healthy"; // Assume the status is always healthy for now

// Increment health counter for monitoring

DB_HEALTH_COUNTER
.with_label_values(&[status]).inc();
info!("Database health check: {}", status);
true
}
}
2 changes: 2 additions & 0 deletions crates/database/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod database;

use async_trait::async_trait;
use mongodb::{
bson::{self, doc, oid::ObjectId, Bson, Document as BsonDocument},
Expand Down
28 changes: 28 additions & 0 deletions crates/keystore/keystore.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use prometheus::{IntCounterVec, Opts};

lazy_static::lazy_static! {
static ref KEYSTORE_HEALTH_COUNTER: IntCounterVec = IntCounterVec::new(
Opts::new("keystore_health", "Counts keystore health check results"),
&["status"]
).unwrap();
}

pub struct Keystore {
pub status: String,
}

impl Keystore {
pub fn new() -> Self {
Keystore {
status: "healthy".to_string(),
}
}

pub async fn check_health(&self) {
// Simulating a health check delay, e.g., checking key store access
tokio::time::sleep(std::time::Duration::from_secs(1)).await;

// Update the health status (in a real-world scenario, check the keystore service)
KEYSTORE_HEALTH_COUNTER.with_label_values(&[&self.status]).inc();
}
}
61 changes: 61 additions & 0 deletions crates/services.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use prometheus::{IntCounterVec, Opts, Registry, Encoder, TextEncoder};
use std::sync::{Arc, Mutex};
use axum::response::IntoResponse;
use axum::http::StatusCode;

lazy_static::lazy_static! {
static ref SERVICE_HEALTH_COUNTER: IntCounterVec = IntCounterVec::new(
Opts::new("service_health", "Counts the health check status of various services"),
&["service", "status"]
).unwrap();
}

pub struct ServiceHealth {
pub name: String,
pub status: String,
}

impl ServiceHealth {
pub fn new(name: String, status: String) -> Self {
ServiceHealth { name, status }
}
}

pub fn service_health_check() -> Vec<ServiceHealth> {
// Simulating health check for different services like database, messaging, etc.
let services = vec![
ServiceHealth::new("Database".to_string(), "healthy".to_string()),
ServiceHealth::new("Keystore".to_string(), "healthy".to_string()),
];

// Increment the health check counters for each service
for service in &services {
SERVICE_HEALTH_COUNTER
.with_label_values(&[&service.name, &service.status])
.inc();
}

services
}

pub async fn health_check() -> impl IntoResponse {
// Simulate the checking of service health status
let services = service_health_check();
let response = services.iter()
.map(|s| format!("{}: {}", s.name, s.status))
.collect::<Vec<String>>()
.join("\n");

(StatusCode::OK, response)
}

pub async fn metrics_handler() -> impl IntoResponse {
let registry = Arc::new(Mutex::new(prometheus::Registry::new()));
let encoder = TextEncoder::new();
let mut buffer = Vec::new();

registry.lock().unwrap().gather();
encoder.encode(&registry.lock().unwrap().gather(), &mut buffer).unwrap();

(StatusCode::OK, buffer)
}
32 changes: 32 additions & 0 deletions src/health.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use actix_web::{HttpResponse, Responder};
use sysinfo::{System, SystemExt};
use crate::tower_http::services::{database, keystore};
/// Health check endpoint
pub async fn health_check() -> impl Responder {
let mut sys = System::new_all();
sys.refresh_all();

let db_status = database::check_database_health();
let keystore_status = keystore::check_keystore_health();

let overall_status = if db_status == "healthy" && keystore_status == "healthy" {
"healthy"
} else {
"degraded"
};

let health_status = serde_json::json!({
"status": overall_status,
"components": {
"database": db_status,
"keystore": keystore_status,
},
"system_metrics": {
"cpu_usage": sys.global_processor_info().cpu_usage(),
"memory_used": sys.used_memory(),
"memory_total": sys.total_memory(),
}
});

HttpResponse::Ok().json(health_status)
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub mod plugins;
mod health;
mod metrics;

use axum::Router;
use plugins::handler::PluginContainer;
Expand Down
18 changes: 18 additions & 0 deletions src/metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use prometheus::{Encoder, TextEncoder, register_counter_vec};
use axum::response::IntoResponse;

lazy_static::lazy_static! {
static ref HTTP_COUNTER: prometheus::CounterVec = register_counter_vec!(
"http_requests_total",
"Number of HTTP requests",
&["method", "endpoint"]
).unwrap();
}

pub async fn metrics() -> impl IntoResponse {
let encoder = TextEncoder::new();
let mut buffer = Vec::new();
let metric_families = prometheus::gather();
encoder.encode(&metric_families, &mut buffer).unwrap();
(StatusCode::OK, buffer)
}
Empty file added src/tower_http.rs
Empty file.

0 comments on commit db689f6

Please sign in to comment.