Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attempt to handle "kstat-based metrics produce samples from the 1980's" #6589

Merged
merged 2 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 112 additions & 24 deletions oximeter/instruments/src/kstat/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,22 @@ use kstat_rs::Data;
use kstat_rs::Kstat;
use kstat_rs::Named;
use oximeter::types::Cumulative;
use oximeter::FieldType;
use oximeter::FieldValue;
use oximeter::Sample;
use oximeter::Target;
use uuid::Uuid;

oximeter::use_timeseries!("sled-data-link.toml");
pub use self::sled_data_link::SledDataLink as SledDataLinkTarget;

/// Helper function to extract the same kstat metrics from all link targets.
fn extract_link_kstats<T>(
target: &T,
fn extract_link_kstats(
target: &SledDataLink,
named_data: &Named,
creation_time: DateTime<Utc>,
snapshot_time: DateTime<Utc>,
) -> Option<Result<Sample, Error>>
where
T: KstatTarget,
{
) -> Option<Result<Sample, Error>> {
let Named { name, value } = named_data;
if *name == "rbytes64" {
Some(value.as_u64().and_then(|x| {
Expand Down Expand Up @@ -83,23 +85,53 @@ where
}
}

// Helper trait for defining `KstatTarget` for all the link-based stats.
trait LinkKstatTarget: KstatTarget {
fn link_name(&self) -> &str;
#[derive(Clone, Debug)]
pub struct SledDataLink {
/// The target for this link.
pub target: SledDataLinkTarget,
/// Flag indicating whether the sled associated with this link is synced with
/// NTP.
pub time_synced: bool,
}

impl LinkKstatTarget for sled_data_link::SledDataLink {
fn link_name(&self) -> &str {
&self.link_name
impl SledDataLink {
/// Create a new `SledDataLink` with the given target and synchronization
/// flag.
pub fn new(target: SledDataLinkTarget, time_synced: bool) -> Self {
Self { target, time_synced }
}

/// Create a new `SledDataLink` with the given target .
#[cfg(test)]
pub fn unsynced(target: SledDataLinkTarget) -> Self {
Self { target, time_synced: false }
}

/// Return the name of the link.
pub fn link_name(&self) -> &str {
&self.target.link_name
}

/// Return the zone name of the link.
pub fn zone_name(&self) -> &str {
&self.target.zone_name
}

/// Return the kind of link.
pub fn kind(&self) -> &str {
&self.target.kind
}

/// Return the idenity of the sled.
pub fn sled_id(&self) -> Uuid {
self.target.sled_id
}
}

impl<T> KstatTarget for T
where
T: LinkKstatTarget,
{
impl KstatTarget for SledDataLink {
fn interested(&self, kstat: &Kstat<'_>) -> bool {
kstat.ks_module == "link"
self.time_synced
&& kstat.ks_module == "link"
&& kstat.ks_instance == 0
&& kstat.ks_name == self.link_name()
}
Expand All @@ -124,6 +156,25 @@ where
}
}

// NOTE: Delegate to the inner target type for this implementation.
impl Target for SledDataLink {
fn name(&self) -> &'static str {
self.target.name()
}

fn field_names(&self) -> &'static [&'static str] {
self.target.field_names()
}

fn field_types(&self) -> Vec<FieldType> {
self.target.field_types()
}

fn field_values(&self) -> Vec<FieldValue> {
self.target.field_values()
}
}

#[cfg(all(test, target_os = "illumos"))]
mod tests {
use super::*;
Expand Down Expand Up @@ -225,10 +276,40 @@ mod tests {
}
}

#[test]
fn test_kstat_interested() {
let link = TestEtherstub::new();
let target = SledDataLinkTarget {
rack_id: RACK_ID,
sled_id: SLED_ID,
sled_serial: SLED_SERIAL.into(),
link_name: link.name.clone().into(),
kind: KIND.into(),
sled_model: SLED_MODEL.into(),
sled_revision: SLED_REVISION,
zone_name: ZONE_NAME.into(),
};
// not with a synced sled (by default)
let mut dl = SledDataLink::unsynced(target);

let ctl = Ctl::new().unwrap();
let ctl = ctl.update().unwrap();
let kstat = ctl
.filter(Some("link"), Some(0), Some(link.name.as_str()))
.next()
.unwrap();

assert!(!dl.interested(&kstat));

// with a synced sled
dl.time_synced = true;
assert!(dl.interested(&kstat));
}

#[test]
fn test_sled_datalink() {
let link = TestEtherstub::new();
let dl = sled_data_link::SledDataLink {
let target = SledDataLinkTarget {
rack_id: RACK_ID,
sled_id: SLED_ID,
sled_serial: SLED_SERIAL.into(),
Expand All @@ -238,6 +319,7 @@ mod tests {
sled_revision: SLED_REVISION,
zone_name: ZONE_NAME.into(),
};
let dl = SledDataLink::new(target, true);
let ctl = Ctl::new().unwrap();
let ctl = ctl.update().unwrap();
let mut kstat = ctl
Expand All @@ -254,7 +336,7 @@ mod tests {
async fn test_kstat_sampler() {
let mut sampler = KstatSampler::new(&test_logger()).unwrap();
let link = TestEtherstub::new();
let dl = sled_data_link::SledDataLink {
let target = SledDataLinkTarget {
rack_id: RACK_ID,
sled_id: SLED_ID,
sled_serial: SLED_SERIAL.into(),
Expand All @@ -264,6 +346,7 @@ mod tests {
sled_revision: SLED_REVISION,
zone_name: ZONE_NAME.into(),
};
let dl = SledDataLink::new(target, true);
let details = CollectionDetails::never(Duration::from_secs(1));
let id = sampler.add_target(dl, details).await.unwrap();
let samples: Vec<_> = sampler.produce().unwrap().collect();
Expand Down Expand Up @@ -304,7 +387,7 @@ mod tests {
let mut sampler =
KstatSampler::with_sample_limit(&test_logger(), limit).unwrap();
let link = TestEtherstub::new();
let dl = sled_data_link::SledDataLink {
let target = SledDataLinkTarget {
rack_id: RACK_ID,
sled_id: SLED_ID,
sled_serial: SLED_SERIAL.into(),
Expand All @@ -314,6 +397,7 @@ mod tests {
sled_revision: SLED_REVISION,
zone_name: ZONE_NAME.into(),
};
let dl = SledDataLink::new(target, true);
let details = CollectionDetails::never(Duration::from_secs(1));
sampler.add_target(dl, details).await.unwrap();
let samples: Vec<_> = sampler.produce().unwrap().collect();
Expand Down Expand Up @@ -373,7 +457,7 @@ mod tests {
let mut sampler = KstatSampler::new(&log).unwrap();
let link = TestEtherstub::new();
info!(log, "created test etherstub"; "name" => &link.name);
let dl = sled_data_link::SledDataLink {
let target = SledDataLinkTarget {
rack_id: RACK_ID,
sled_id: SLED_ID,
sled_serial: SLED_SERIAL.into(),
Expand All @@ -383,6 +467,7 @@ mod tests {
sled_revision: SLED_REVISION,
zone_name: ZONE_NAME.into(),
};
let dl = SledDataLink::new(target, true);
let collection_interval = Duration::from_secs(1);
let expiry = Duration::from_secs(1);
let details = CollectionDetails::duration(collection_interval, expiry);
Expand Down Expand Up @@ -432,7 +517,7 @@ mod tests {
let mut sampler = KstatSampler::new(&log).unwrap();
let link = TestEtherstub::new();
info!(log, "created test etherstub"; "name" => &link.name);
let dl = sled_data_link::SledDataLink {
let target = SledDataLinkTarget {
rack_id: RACK_ID,
sled_id: SLED_ID,
sled_serial: SLED_SERIAL.into(),
Expand All @@ -442,6 +527,7 @@ mod tests {
sled_revision: SLED_REVISION,
zone_name: ZONE_NAME.into(),
};
let dl = SledDataLink::new(target, true);
let collection_interval = Duration::from_secs(1);
let expiry = Duration::from_secs(1);
let details = CollectionDetails::duration(collection_interval, expiry);
Expand Down Expand Up @@ -483,7 +569,7 @@ mod tests {
name: link.name.clone(),
};
info!(log, "created test etherstub"; "name" => &link.name);
let dl = sled_data_link::SledDataLink {
let target = SledDataLinkTarget {
rack_id: RACK_ID,
sled_id: SLED_ID,
sled_serial: SLED_SERIAL.into(),
Expand All @@ -493,6 +579,7 @@ mod tests {
sled_revision: SLED_REVISION,
zone_name: ZONE_NAME.into(),
};
let dl = SledDataLink::new(target, true);
let collection_interval = Duration::from_secs(1);
let expiry = Duration::from_secs(1);
let details = CollectionDetails::duration(collection_interval, expiry);
Expand Down Expand Up @@ -532,7 +619,7 @@ mod tests {
name: link.name.clone(),
};
info!(log, "created test etherstub"; "name" => &link.name);
let dl = sled_data_link::SledDataLink {
let target = SledDataLinkTarget {
rack_id: RACK_ID,
sled_id: SLED_ID,
sled_serial: SLED_SERIAL.into(),
Expand All @@ -542,6 +629,7 @@ mod tests {
sled_revision: SLED_REVISION,
zone_name: ZONE_NAME.into(),
};
let dl = SledDataLink::new(target, true);
let collection_interval = Duration::from_secs(1);
let expiry = Duration::from_secs(1);
let details = CollectionDetails::duration(collection_interval, expiry);
Expand Down
1 change: 1 addition & 0 deletions oximeter/instruments/src/kstat/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ use std::time::Duration;
pub mod link;
mod sampler;

pub use link::SledDataLink;
pub use sampler::CollectionDetails;
pub use sampler::ExpirationBehavior;
pub use sampler::KstatSampler;
Expand Down
Loading
Loading