diff options
author | Dan Schatzberg <dschatzberg@fb.com> | 2022-04-15 09:49:15 -0700 |
---|---|---|
committer | Facebook GitHub Bot <facebook-github-bot@users.noreply.github.com> | 2022-04-15 09:49:15 -0700 |
commit | 603d8e0d82cede43cc1aac2853391b656126624c (patch) | |
tree | d7cd99a432b24c8653c592ba820a7572b18f62bd | |
parent | 490411af8446bb6fd57f01809b37b4f02a1d7626 (diff) |
Handle unsupported pressure metrics gracefully
Summary:
Capture the error and report it nicely in cgroupfs and then
squash it in below.
Reviewed By: brianc118
Differential Revision: D35560379
fbshipit-source-id: d64699cfac457536adb2f98522b55a64b09524f0
-rw-r--r-- | below/cgroupfs/src/lib.rs | 32 | ||||
-rw-r--r-- | below/model/src/collector.rs | 14 |
2 files changed, 40 insertions, 6 deletions
diff --git a/below/cgroupfs/src/lib.rs b/below/cgroupfs/src/lib.rs index 672e6544..de529ad8 100644 --- a/below/cgroupfs/src/lib.rs +++ b/below/cgroupfs/src/lib.rs @@ -40,6 +40,8 @@ pub enum Error { UnexpectedLine(PathBuf, String), #[error("Not cgroup2 filesystem: {0:?}")] NotCgroup2(PathBuf), + #[error("Pressure metrics not supported: {0:?}")] + PressureNotSupported(PathBuf), } pub type Result<T> = std::result::Result<T, Error>; @@ -273,6 +275,12 @@ impl CgroupReader { p.push(file_name); Error::UnexpectedLine(p, line) } + + fn pressure_not_supported<P: AsRef<Path>>(&self, file_name: P) -> Error { + let mut p = self.relative_path.clone(); + p.push(file_name); + Error::PressureNotSupported(p) + } } // Trait to add a read() method for `key value` formatted files @@ -374,15 +382,29 @@ trait NameKVRead: Sized { ) -> Result<BTreeMap<String, Self>>; } +struct AllowsEmpty(bool); +struct AllowsPressureEOpNotSupp(bool); + macro_rules! name_key_equal_value_format { - ($struct:ident; $allows_empty:expr; [ $($field:ident,)+ ]) => ( + ($struct:ident; $allows_empty:expr; $allows_pressure_eopnotsupp:expr; [ $($field:ident,)+ ]) => ( impl NameKVRead for $struct { fn read<P: AsRef<Path> + AsPath + Clone>(r: &CgroupReader, file_name: P) -> Result<BTreeMap<String, $struct>> { let mut map = BTreeMap::new(); let file = r.dir.open_file(file_name.clone()).map_err(|e| r.io_error(file_name.clone(), e))?; let buf_reader = BufReader::new(file); for line in buf_reader.lines() { - let line = line.map_err(|e| r.io_error(file_name.clone(), e))?; + let line = line.map_err(|e| { + // Capture a different error if pressure + // metrics aren't supported + if $allows_pressure_eopnotsupp.0 { + if let Some(errno) = e.raw_os_error() { + if errno == /* EOPNOTSUPP */ 95 { + return r.pressure_not_supported(file_name.clone()); + } + } + } + r.io_error(file_name.clone(), e) + })?; let items = line.split_whitespace().collect::<Vec<_>>(); // as an example, io.stat looks like: // 253:0 rbytes=531745786880 wbytes=1623798909952 ... @@ -405,7 +427,7 @@ macro_rules! name_key_equal_value_format { } map.insert(items[0].to_string(), s); } - if !$allows_empty && map.is_empty() { + if !$allows_empty.0 && map.is_empty() { Err(r.invalid_file_format(file_name)) } else { Ok(map) @@ -415,7 +437,7 @@ macro_rules! name_key_equal_value_format { ); } -name_key_equal_value_format!(IoStat; true; [ +name_key_equal_value_format!(IoStat; AllowsEmpty(true); AllowsPressureEOpNotSupp(false); [ rbytes, wbytes, rios, @@ -424,7 +446,7 @@ name_key_equal_value_format!(IoStat; true; [ dios, ]); -name_key_equal_value_format!(PressureMetrics; false; [ +name_key_equal_value_format!(PressureMetrics; AllowsEmpty(false); AllowsPressureEOpNotSupp(true); [ avg10, avg60, avg300, diff --git a/below/model/src/collector.rs b/below/model/src/collector.rs index 88a544ee..b0661466 100644 --- a/below/model/src/collector.rs +++ b/below/model/src/collector.rs @@ -296,6 +296,18 @@ fn io_stat_wrap<S: Sized>( } } +/// Pressure metrics may not be supported, in which case cgroupfs will +/// return a specific error. We don't fail all data collection, just +/// omit pressure metrics. +fn pressure_wrap<S: Sized>( + v: std::result::Result<S, cgroupfs::Error>, +) -> std::result::Result<Option<S>, cgroupfs::Error> { + match wrap(v) { + Err(cgroupfs::Error::PressureNotSupported(_)) => Ok(None), + wrapped => wrapped, + } +} + fn collect_cgroup_sample( reader: &cgroupfs::CgroupReader, collect_io_stat: bool, @@ -312,7 +324,7 @@ fn collect_cgroup_sample( io_stat: io_stat.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect()), memory_current: wrap(reader.read_memory_current().map(|v| v as i64))?, memory_stat: wrap(reader.read_memory_stat())?.map(Into::into), - pressure: wrap(reader.read_pressure())?.map(Into::into), + pressure: pressure_wrap(reader.read_pressure())?.map(Into::into), // We transpose at the end here to convert the // Option<Result<BTreeMap... into Result<Option<BTreeMap and // then bail any errors with `?` - leaving us with the |