Skip to content

Commit

Permalink
Add prometheus support
Browse files Browse the repository at this point in the history
  • Loading branch information
Guilospanck committed Dec 20, 2024
1 parent 730995e commit 2132b54
Show file tree
Hide file tree
Showing 12 changed files with 524 additions and 10 deletions.
356 changes: 346 additions & 10 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ resolver = "2"
members = [
"florestad",
"fuzz",
"metrics",
"crates/floresta",
"crates/floresta-chain",
"crates/floresta-cli",
Expand All @@ -15,6 +16,7 @@ members = [

default-members = [
"florestad",
"metrics",
"crates/floresta",
"crates/floresta-chain",
"crates/floresta-cli",
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ COPY Cargo.* ./
COPY florestad/ florestad/
COPY crates/ crates/
COPY fuzz/ fuzz/
COPY metrics/ metrics/
RUN --mount=type=cache,target=/usr/local/cargo/registry \
cargo build --release

Expand All @@ -29,5 +30,6 @@ RUN chmod +x /usr/local/bin/florestad

EXPOSE 50001
EXPOSE 8332
EXPOSE 3333

CMD [ "florestad" ]
1 change: 1 addition & 0 deletions crates/floresta-chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ hashbrown = { version = "0.14.0", optional = true }
secp256k1 = { version = "*", features = ["alloc"], optional = true }
floresta-common = { path = "../floresta-common", default-features = false, features = ["std"] }
bitcoinconsensus = { version = "0.106.0", optional = true, default-features = false }
metrics = { path = "../../metrics" }

[dev-dependencies]
criterion = "0.5.1"
Expand Down
2 changes: 2 additions & 0 deletions crates/floresta-chain/src/pruned_utreexo/chain_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,8 @@ impl<PersistedState: ChainStore> UpdatableChainstate for ChainState<PersistedSta
block.txdata.len()
);

metrics::get_metrics().block_height.set(height.into());

if !self.is_in_idb() || height % 10_000 == 0 {
self.flush()?;
}
Expand Down
35 changes: 35 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
services:
floresta:
container_name: floresta
build:
context: .
ports:
- 50001:50001
- 8332:8332
- 3333:3333
restart: unless-stopped
deploy:
resources:
reservations:
memory: 16G
prometheus:
image: prom/prometheus
container_name: prometheus
command:
- "--config.file=/etc/prometheus/prometheus.yml"
ports:
- 9090:9090
restart: unless-stopped
volumes:
- ./metrics/prometheus:/etc/prometheus
grafana:
image: grafana/grafana
container_name: grafana
ports:
- 3000:3000
restart: unless-stopped
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=grafana
volumes:
- ./metrics/grafana:/etc/grafana/provisioning/datasources
1 change: 1 addition & 0 deletions florestad/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jsonrpc-core-client = { version = "18.0.0", features = [
], optional = true }
zmq = { version = "0.10.0", optional = true }
dns-lookup = "2.0.4"
metrics = { path = "../metrics" }

[target.'cfg(unix)'.dependencies]
daemonize = { version = "0.5.0" }
Expand Down
24 changes: 24 additions & 0 deletions florestad/src/florestad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::fmt::Arguments;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::net::Ipv4Addr;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::process::exit;
Expand Down Expand Up @@ -41,9 +42,12 @@ use log::error;
use log::info;
use log::warn;
use log::Record;
use metrics;
use tokio::net::TcpListener;
use tokio::sync::RwLock;
use tokio::task;
use tokio::time::Duration;
use tokio::time::{self};
use tokio_rustls::rustls::internal::pemfile::certs;
use tokio_rustls::rustls::internal::pemfile::pkcs8_private_keys;
use tokio_rustls::rustls::NoClientAuth;
Expand Down Expand Up @@ -525,6 +529,26 @@ impl Florestad {
*recv = Some(receiver);

task::spawn(chain_provider.run(kill_signal, sender));

// Metrics
let metrics_server_address =
SocketAddr::new(std::net::IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 3333);
task::spawn(metrics::metrics_server(metrics_server_address));
info!(
"Started metrics server on: {}",
metrics_server_address.to_string()
);

// Periodically update memory usage
tokio::spawn(async {
let interval = Duration::from_secs(5);
let mut ticker = time::interval(interval);

loop {
ticker.tick().await;
metrics::get_metrics().update_memory_usage();
}
});
}

fn setup_logger(
Expand Down
13 changes: 13 additions & 0 deletions metrics/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "metrics"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
sysinfo = "0.33"
axum = "0.7"
prometheus-client = "0.22.3"
tokio = { version = "1", features = ["full"] }

9 changes: 9 additions & 0 deletions metrics/grafana/datasource.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: 1

datasources:
- name: Prometheus
type: prometheus
url: http://prometheus:9090
isDefault: true
access: proxy
editable: true
14 changes: 14 additions & 0 deletions metrics/prometheus/prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
global:
scrape_interval: 15s
scrape_timeout: 10s
evaluation_interval: 15s
scrape_configs:
- job_name: prometheus
honor_timestamps: true
scrape_interval: 15s
scrape_timeout: 10s
metrics_path: /
scheme: http
static_configs:
- targets:
- floresta:3333
75 changes: 75 additions & 0 deletions metrics/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use std::net::SocketAddr;
use std::sync::atomic::AtomicU64;
use std::sync::OnceLock;

use axum::routing::get;
use axum::Router;
use prometheus_client::encoding::text::encode;
use prometheus_client::metrics::gauge::Gauge;
use prometheus_client::registry::Registry;
use sysinfo::System;

pub struct AppMetrics {
registry: Registry,
pub memory_usage: Gauge<f64, AtomicU64>,
pub block_height: Gauge,
}

impl AppMetrics {
pub fn new() -> Self {
let mut registry = <Registry>::default();
let memory_usage = Gauge::<f64, AtomicU64>::default();
let block_height = Gauge::default();

registry.register("block_height", "Current block height", block_height.clone());
registry.register(
"memory_usage_gigabytes",
"System memory usage in GB",
memory_usage.clone(),
);

Self {
registry,
block_height,
memory_usage,
}
}

/// Gets how much memory is being used by the system in which Floresta is
/// running on, not how much memory Floresta itself it's using.
pub fn update_memory_usage(&self) {
let mut system = System::new_all();
system.refresh_memory();

// get used memory in gigabytes / KB / MB / GB
let used_memory = system.used_memory() as f64 / 1024. / 1024. / 1024.;
self.memory_usage.set(used_memory);
}
}

impl Default for AppMetrics {
fn default() -> Self {
Self::new()
}
}

// Singleton to share metrics across crates
static METRICS: OnceLock<AppMetrics> = OnceLock::new();
pub fn get_metrics() -> &'static AppMetrics {
METRICS.get_or_init(AppMetrics::new)
}

async fn metrics_handler() -> String {
let mut buffer = String::new();
encode(&mut buffer, &get_metrics().registry).unwrap();

buffer
}

pub async fn metrics_server(metrics_server_address: SocketAddr) {
let app = Router::new().route("/", get(metrics_handler));
let listener = tokio::net::TcpListener::bind(metrics_server_address)
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
}

0 comments on commit 2132b54

Please sign in to comment.