use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::error::{FlowError, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum ResourceMetricsMeasurementScope {
#[default]
RuntimeDefault,
Global,
ApplicationProcess,
ProcessTree,
}
impl ResourceMetricsMeasurementScope {
pub const fn as_str(self) -> &'static str {
match self {
Self::RuntimeDefault => "runtime_default",
Self::Global => "global",
Self::ApplicationProcess => "application_process",
Self::ProcessTree => "process_tree",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsPollingConfig {
pub enabled: bool,
pub interval_millis: u64,
}
impl Default for ResourceMetricsPollingConfig {
fn default() -> Self {
Self {
enabled: false,
interval_millis: 5_000,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsCpuConfig {
pub enabled: bool,
}
impl Default for ResourceMetricsCpuConfig {
fn default() -> Self {
Self { enabled: true }
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsMemoryConfig {
pub enabled: bool,
}
impl Default for ResourceMetricsMemoryConfig {
fn default() -> Self {
Self { enabled: true }
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsProcessConfig {
pub enabled: bool,
}
impl Default for ResourceMetricsProcessConfig {
fn default() -> Self {
Self { enabled: true }
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsDiskConfig {
pub enabled: bool,
pub process_io: bool,
pub filesystem_paths: Vec<PathBuf>,
}
impl Default for ResourceMetricsDiskConfig {
fn default() -> Self {
Self {
enabled: true,
process_io: true,
filesystem_paths: Vec::new(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsGpuConfig {
pub enabled: bool,
pub devices: Vec<String>,
pub device_metrics: bool,
pub process_metrics: bool,
}
impl Default for ResourceMetricsGpuConfig {
fn default() -> Self {
Self {
enabled: true,
devices: Vec::new(),
device_metrics: true,
process_metrics: true,
}
}
}
pub use nemo_relay_types::api::resource_metrics::{
BandwidthUnit, CapacityUnit, CpuUnit, DataUnit, DurationUnit, UtilizationUnit,
};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsCpuUnits {
pub user_time: DurationUnit,
pub system_time: DurationUnit,
pub total_time: DurationUnit,
pub throttled_time: DurationUnit,
pub some_pressure_stall_time: DurationUnit,
pub full_pressure_stall_time: DurationUnit,
pub consumption_rate: CpuUnit,
pub effective_limit: CpuUnit,
}
crate::editor_config! {
impl ResourceMetricsCpuUnits {
user_time => { label: "user_time", kind: Enum, values: ["microseconds", "milliseconds", "seconds", "minutes"] },
system_time => { label: "system_time", kind: Enum, values: ["microseconds", "milliseconds", "seconds", "minutes"] },
total_time => { label: "total_time", kind: Enum, values: ["microseconds", "milliseconds", "seconds", "minutes"] },
throttled_time => { label: "throttled_time", kind: Enum, values: ["microseconds", "milliseconds", "seconds", "minutes"] },
some_pressure_stall_time => { label: "some_pressure_stall_time", kind: Enum, values: ["microseconds", "milliseconds", "seconds", "minutes"] },
full_pressure_stall_time => { label: "full_pressure_stall_time", kind: Enum, values: ["microseconds", "milliseconds", "seconds", "minutes"] },
consumption_rate => { label: "consumption_rate", kind: Enum, values: ["logical_processors", "millicores"] },
effective_limit => { label: "effective_limit", kind: Enum, values: ["logical_processors", "millicores"] },
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsMemoryUnits {
pub system_used: CapacityUnit,
pub system_total: CapacityUnit,
pub system_available: CapacityUnit,
pub resident: CapacityUnit,
pub private: CapacityUnit,
pub physical_footprint: CapacityUnit,
pub virtual_memory: CapacityUnit,
pub peak_resident: CapacityUnit,
pub limit: CapacityUnit,
pub environment_accounted: CapacityUnit,
pub some_pressure_stall_time: DurationUnit,
pub full_pressure_stall_time: DurationUnit,
}
crate::editor_config! {
impl ResourceMetricsMemoryUnits {
system_used => { label: "system_used", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
system_total => { label: "system_total", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
system_available => { label: "system_available", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
resident => { label: "resident", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
private => { label: "private", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
physical_footprint => { label: "physical_footprint", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
virtual_memory => { label: "virtual_memory", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
peak_resident => { label: "peak_resident", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
limit => { label: "limit", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
environment_accounted => { label: "environment_accounted", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
some_pressure_stall_time => { label: "some_pressure_stall_time", kind: Enum, values: ["microseconds", "milliseconds", "seconds", "minutes"] },
full_pressure_stall_time => { label: "full_pressure_stall_time", kind: Enum, values: ["microseconds", "milliseconds", "seconds", "minutes"] },
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsDiskUnits {
pub read_data: DataUnit,
pub write_data: DataUnit,
pub filesystem_total_capacity: CapacityUnit,
pub filesystem_available_capacity: CapacityUnit,
pub filesystem_free_capacity: CapacityUnit,
pub read_throughput: BandwidthUnit,
pub write_throughput: BandwidthUnit,
}
impl Default for ResourceMetricsDiskUnits {
fn default() -> Self {
Self {
read_data: DataUnit::Bytes,
write_data: DataUnit::Bytes,
filesystem_total_capacity: CapacityUnit::Bytes,
filesystem_available_capacity: CapacityUnit::Bytes,
filesystem_free_capacity: CapacityUnit::Bytes,
read_throughput: BandwidthUnit::BytesPerSecond,
write_throughput: BandwidthUnit::BytesPerSecond,
}
}
}
crate::editor_config! {
impl ResourceMetricsDiskUnits {
read_data => { label: "read_data", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
write_data => { label: "write_data", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
filesystem_total_capacity => { label: "filesystem_total_capacity", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
filesystem_available_capacity => { label: "filesystem_available_capacity", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
filesystem_free_capacity => { label: "filesystem_free_capacity", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
read_throughput => { label: "read_throughput", kind: Enum, values: ["bytes_per_second", "kibibytes_per_second", "mebibytes_per_second", "gibibytes_per_second", "bits_per_second", "megabits_per_second", "gigabits_per_second"] },
write_throughput => { label: "write_throughput", kind: Enum, values: ["bytes_per_second", "kibibytes_per_second", "mebibytes_per_second", "gibibytes_per_second", "bits_per_second", "megabits_per_second", "gigabits_per_second"] },
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsGpuUnits {
pub device_memory_used: CapacityUnit,
pub process_memory_used: CapacityUnit,
pub device_compute_utilization: UtilizationUnit,
pub process_compute_utilization: UtilizationUnit,
}
crate::editor_config! {
impl ResourceMetricsGpuUnits {
device_memory_used => { label: "device_memory_used", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
process_memory_used => { label: "process_memory_used", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
device_compute_utilization => { label: "device_compute_utilization", kind: Enum, values: ["percentage", "fraction"] },
process_compute_utilization => { label: "process_compute_utilization", kind: Enum, values: ["percentage", "fraction"] },
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsNetworkTrafficUnits {
pub received_data: DataUnit,
pub transmitted_data: DataUnit,
pub receive_throughput: BandwidthUnit,
pub transmit_throughput: BandwidthUnit,
}
crate::editor_config! {
impl ResourceMetricsNetworkTrafficUnits {
received_data => { label: "received_data", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
transmitted_data => { label: "transmitted_data", kind: Enum, values: ["bytes", "kilobytes", "megabytes", "gigabytes", "terabytes", "kibibytes", "mebibytes", "gibibytes", "tebibytes"] },
receive_throughput => { label: "receive_throughput", kind: Enum, values: ["bytes_per_second", "kibibytes_per_second", "mebibytes_per_second", "gibibytes_per_second", "bits_per_second", "megabits_per_second", "gigabits_per_second"] },
transmit_throughput => { label: "transmit_throughput", kind: Enum, values: ["bytes_per_second", "kibibytes_per_second", "mebibytes_per_second", "gibibytes_per_second", "bits_per_second", "megabits_per_second", "gigabits_per_second"] },
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsNetworkUnits {
pub system: ResourceMetricsNetworkTrafficUnits,
pub interface: ResourceMetricsNetworkTrafficUnits,
}
crate::editor_config! {
impl ResourceMetricsNetworkUnits {
system => { label: "System", kind: Section, nested: ResourceMetricsNetworkTrafficUnits, default: ResourceMetricsNetworkTrafficUnits },
interface => { label: "Interface", kind: Section, nested: ResourceMetricsNetworkTrafficUnits, default: ResourceMetricsNetworkTrafficUnits },
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsUnits {
pub cpu: ResourceMetricsCpuUnits,
pub memory: ResourceMetricsMemoryUnits,
pub disk: ResourceMetricsDiskUnits,
pub gpu: ResourceMetricsGpuUnits,
pub network: ResourceMetricsNetworkUnits,
}
crate::editor_config! {
impl ResourceMetricsUnits {
cpu => { label: "CPU", kind: Section, nested: ResourceMetricsCpuUnits, default: ResourceMetricsCpuUnits },
memory => { label: "Memory", kind: Section, nested: ResourceMetricsMemoryUnits, default: ResourceMetricsMemoryUnits },
disk => { label: "Disk", kind: Section, nested: ResourceMetricsDiskUnits, default: ResourceMetricsDiskUnits },
gpu => { label: "GPU", kind: Section, nested: ResourceMetricsGpuUnits, default: ResourceMetricsGpuUnits },
network => { label: "Network", kind: Section, nested: ResourceMetricsNetworkUnits, default: ResourceMetricsNetworkUnits },
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsNetworkConfig {
pub enabled: bool,
pub interfaces: Vec<String>,
}
impl Default for ResourceMetricsNetworkConfig {
fn default() -> Self {
Self {
enabled: true,
interfaces: Vec::new(),
}
}
}
crate::editor_config! {
impl ResourceMetricsNetworkConfig {
enabled => { label: "enabled", kind: Boolean },
interfaces => { label: "interfaces", kind: List, list: &crate::config_editor::STRING_LIST_ITEM },
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(default, deny_unknown_fields)]
pub struct ResourceMetricsConfig {
pub measurement_scope: ResourceMetricsMeasurementScope,
pub polling: ResourceMetricsPollingConfig,
pub cpu: ResourceMetricsCpuConfig,
pub memory: ResourceMetricsMemoryConfig,
pub process: ResourceMetricsProcessConfig,
pub disk: ResourceMetricsDiskConfig,
pub gpu: ResourceMetricsGpuConfig,
pub network: ResourceMetricsNetworkConfig,
pub units: ResourceMetricsUnits,
}
crate::editor_config! {
impl ResourceMetricsPollingConfig {
enabled => { label: "enabled", kind: Boolean },
interval_millis => { label: "interval_millis", kind: Integer },
}
}
crate::editor_config! {
impl ResourceMetricsCpuConfig {
enabled => { label: "enabled", kind: Boolean },
}
}
crate::editor_config! {
impl ResourceMetricsMemoryConfig {
enabled => { label: "enabled", kind: Boolean },
}
}
crate::editor_config! {
impl ResourceMetricsProcessConfig {
enabled => { label: "enabled", kind: Boolean },
}
}
crate::editor_config! {
impl ResourceMetricsDiskConfig {
enabled => { label: "enabled", kind: Boolean },
process_io => { label: "process_io", kind: Boolean },
filesystem_paths => {
label: "filesystem_paths",
kind: List,
list: &crate::config_editor::STRING_LIST_ITEM,
},
}
}
crate::editor_config! {
impl ResourceMetricsGpuConfig {
enabled => { label: "enabled", kind: Boolean },
devices => {
label: "devices",
kind: List,
list: &crate::config_editor::STRING_LIST_ITEM,
},
device_metrics => { label: "device_metrics", kind: Boolean },
process_metrics => { label: "process_metrics", kind: Boolean },
}
}
crate::editor_config! {
impl ResourceMetricsConfig {
measurement_scope => {
label: "measurement_scope",
kind: Enum,
values: ["runtime_default", "global", "application_process", "process_tree"],
},
polling => {
label: "polling",
kind: Section,
nested: ResourceMetricsPollingConfig,
default: ResourceMetricsPollingConfig,
},
cpu => {
label: "CPU",
kind: Section,
nested: ResourceMetricsCpuConfig,
default: ResourceMetricsCpuConfig,
},
memory => {
label: "Memory",
kind: Section,
nested: ResourceMetricsMemoryConfig,
default: ResourceMetricsMemoryConfig,
},
process => {
label: "Process",
kind: Section,
nested: ResourceMetricsProcessConfig,
default: ResourceMetricsProcessConfig,
},
disk => {
label: "Disk",
kind: Section,
nested: ResourceMetricsDiskConfig,
default: ResourceMetricsDiskConfig,
},
gpu => {
label: "GPU",
kind: Section,
nested: ResourceMetricsGpuConfig,
default: ResourceMetricsGpuConfig,
},
network => { label: "Network", kind: Section, nested: ResourceMetricsNetworkConfig, default: ResourceMetricsNetworkConfig },
units => { label: "Units", kind: Section, nested: ResourceMetricsUnits, default: ResourceMetricsUnits },
}
}
impl ResourceMetricsConfig {
pub(crate) fn validate(&self) -> Result<()> {
if self.polling.interval_millis == 0 {
return Err(FlowError::InvalidArgument(
"resource_metrics.polling.interval_millis must be greater than zero".into(),
));
}
for (index, path) in self.disk.filesystem_paths.iter().enumerate() {
if path.as_os_str().is_empty() {
return Err(FlowError::InvalidArgument(format!(
"resource_metrics.disk.filesystem_paths[{index}] must not be empty"
)));
}
if !path.is_absolute() {
return Err(FlowError::InvalidArgument(format!(
"resource_metrics.disk.filesystem_paths[{index}] must be absolute"
)));
}
}
if self
.network
.interfaces
.iter()
.any(|name| name.trim().is_empty())
{
return Err(FlowError::InvalidArgument(
"resource_metrics.network.interfaces must not contain blank names".into(),
));
}
if self
.gpu
.devices
.iter()
.any(|device| device.trim().is_empty())
{
return Err(FlowError::InvalidArgument(
"resource_metrics.gpu.devices must not contain empty identifiers".into(),
));
}
Ok(())
}
}