Skip to content

Commit

Permalink
feat: memory metrics envar
Browse files Browse the repository at this point in the history
  • Loading branch information
apskhem committed Jan 14, 2025
1 parent d08852c commit 5575800
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 21 deletions.
9 changes: 3 additions & 6 deletions catalyst-gateway/bin/src/metrics/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ use std::{
Arc, LazyLock, RwLock,
},
thread,
time::Duration,
};

use memory_stats::memory_stats;
use stats_alloc::{Region, Stats, StatsAlloc, INSTRUMENTED_SYSTEM};
use tracing::log::error;

use crate::settings::Settings;

/// Use the instrumented allocator for gathering allocation statistics.
/// Note: This wraps the global allocator.
/// All structs that use the global allocator can be tracked.
Expand All @@ -27,9 +28,6 @@ static GLOBAL_METRICS: LazyLock<Arc<RwLock<MemoryMetrics>>> =
/// This is to prevent the init function from accidentally being called multiple times.
static IS_INITIALIZED: AtomicBool = AtomicBool::new(false);

/// Interval for updating memory metrics, in milliseconds.
const UPDATE_INTERVAL_MILLI: u64 = 1000;

/// A structure for storing memory metrics, including allocator statistics
/// and physical/virtual memory usage.
#[derive(Debug, Default, Clone)]
Expand Down Expand Up @@ -72,7 +70,6 @@ impl MemoryMetrics {
let stats = Region::new(GLOBAL);

thread::spawn(move || {
let interval = Duration::from_millis(UPDATE_INTERVAL_MILLI);
loop {
let allocator_stats = stats.change();
match GLOBAL_METRICS.read() {
Expand All @@ -90,7 +87,7 @@ impl MemoryMetrics {
error!("Failed to read memory usage metrics: {:?}", err);
},
}
thread::sleep(interval);
thread::sleep(Settings::metrics_memory_interval());
}
});
}
Expand Down
34 changes: 19 additions & 15 deletions catalyst-gateway/bin/src/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use anyhow::anyhow;
use cardano_chain_follower::Network;
use clap::Args;
use dotenvy::dotenv;
use duration_string::DurationString;
use str_env_var::StringEnvVar;
use tracing::error;
use url::Url;
Expand Down Expand Up @@ -52,6 +51,9 @@ const API_URL_PREFIX_DEFAULT: &str = "/api";
/// Default `CHECK_CONFIG_TICK` used in development.
const CHECK_CONFIG_TICK_DEFAULT: &str = "5s";

/// Default `METRICS_MEMORY_INTERVAL`.
const METRICS_MEMORY_INTERVAL_DEFAULT: &str = "1s";

/// Default Event DB URL.
const EVENT_DB_URL_DEFAULT: &str =
"postgresql://postgres:postgres@localhost/catalyst_events?sslmode=disable";
Expand Down Expand Up @@ -144,6 +146,9 @@ struct EnvVars {
/// Tick every N seconds until config exists in db
#[allow(unused)]
check_config_tick: Duration,

/// Interval for updating and sending memory metrics.
metrics_memory_interval: Duration,
}

// Lazy initialization of all env vars which are not command line parameters.
Expand All @@ -157,19 +162,6 @@ static ENV_VARS: LazyLock<EnvVars> = LazyLock::new(|| {
// Support env vars in a `.env` file, doesn't need to exist.
dotenv().ok();

let check_interval = StringEnvVar::new("CHECK_CONFIG_TICK", CHECK_CONFIG_TICK_DEFAULT.into());
let check_config_tick = match DurationString::try_from(check_interval.as_string()) {
Ok(duration) => duration.into(),
Err(error) => {
error!(
"Invalid Check Config Tick Duration: {} : {}. Defaulting to 5 seconds.",
check_interval.as_str(),
error
);
Duration::from_secs(5)
},
};

EnvVars {
github_repo_owner: StringEnvVar::new("GITHUB_REPO_OWNER", GITHUB_REPO_OWNER_DEFAULT.into()),
github_repo_name: StringEnvVar::new("GITHUB_REPO_NAME", GITHUB_REPO_NAME_DEFAULT.into()),
Expand All @@ -194,7 +186,14 @@ static ENV_VARS: LazyLock<EnvVars> = LazyLock::new(|| {
),
chain_follower: chain_follower::EnvVars::new(),
internal_api_key: StringEnvVar::new_optional("INTERNAL_API_KEY", true),
check_config_tick,
check_config_tick: StringEnvVar::new_as_duration(
"CHECK_CONFIG_TICK",
CHECK_CONFIG_TICK_DEFAULT,
),
metrics_memory_interval: StringEnvVar::new_as_duration(
"METRICS_MEMORY_INTERVAL",
METRICS_MEMORY_INTERVAL_DEFAULT,
),
}
});

Expand Down Expand Up @@ -288,6 +287,11 @@ impl Settings {
ENV_VARS.service_id.as_str()
}

/// The memory metrics interval
pub(crate) fn metrics_memory_interval() -> Duration {
ENV_VARS.metrics_memory_interval
}

/// Get a list of all host names to serve the API on.
///
/// Used by the `OpenAPI` Documentation to point to the correct backend.
Expand Down
35 changes: 35 additions & 0 deletions catalyst-gateway/bin/src/settings/str_env_var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use std::{
env::{self, VarError},
fmt::{self, Display},
str::FromStr,
time::Duration,
};

use duration_string::DurationString;
use strum::VariantNames;
use tracing::{error, info};

Expand Down Expand Up @@ -168,6 +170,39 @@ impl StringEnvVar {
value
}

/// Convert an Envvar into the required Duration type.
pub(crate) fn new_as_duration(var_name: &str, default: &str) -> Duration {
let choices = "A value in the format of `[0-9]+(ns|us|ms|[smhdwy])`";

let raw_value = StringEnvVar::new(
var_name,
(default.to_string().as_str(), false, choices).into(),
)
.as_string();

match DurationString::try_from(raw_value.clone()) {
Ok(duration) => duration.into(),
Err(error) => {
error!(
"Invalid Duration: {} : {}. Defaulting to {}.",
raw_value, error, default
);

match DurationString::try_from(default.to_string()) {
Ok(duration) => duration.into(),
// The error from parsing the default value must not happen
Err(error) => {
error!(
"Invalid Default Duration: {} : {}. Defaulting to 1s.",
default, error
);
Duration::from_secs(1)
},
}
},
}
}

/// Convert an Envvar into an integer in the bounded range.
pub(super) fn new_as<T>(var_name: &str, default: T, min: T, max: T) -> T
where
Expand Down

0 comments on commit 5575800

Please sign in to comment.