summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeon Yang (Containers) <lnyng@meta.com>2024-04-26 07:11:10 -0700
committerFacebook GitHub Bot <facebook-github-bot@users.noreply.github.com>2024-04-26 07:11:10 -0700
commitd50cb2d3fe4ae7fadfa56c1592923b2dbbb282bf (patch)
treeee5b387c5c4e35a53eb0d2f80046e1626a58b6e2
parent1ac3fe69e3f87cb16f4e115350dc43ff2187604d (diff)
Support summary view extra rows
Summary: This diff adds the feature to add extra rows to the bottom of the summary view. Each row has an optional title and each field has an optional alias. Invalid field IDs are skipped. Supported field IDs can be found in common_field_ids.rs or shown in the status bar at the bottom of below when a column is in focused. An example viewrc looks like: ``` [[view.summary_view_extra_rows]] title = "My Extra Row" [[view.summary_view_extra_rows.items]] alias = "Kernel" field_id = "system.kernel_version" [[view.summary_view_extra_rows.items]] field_id = "system.vm.oom_kill" [[view.summary_view_extra_rows.items]] alias = "Sys Slice CPU" field_id = "cgroup.path:/system.slice/.cpu.usage_pct" [[view.summary_view_extra_rows]] [[view.summary_view_extra_rows.items]] field_id = "system.stat.blocked_processes" [[view.summary_view_extra_rows.items]] field_id = "system.stat.running_processes" [[view.summary_view_extra_rows.items]] field_id = "invalid.field.id" [[view.summary_view_extra_rows.items]] field_id = "system.mem.swap_free" ``` Reviewed By: brianc118 Differential Revision: D56504773 fbshipit-source-id: 22874aec922e8a4f3e6699094ec63dc6c66ad5d1
-rw-r--r--below/model/src/lib.rs2
-rw-r--r--below/render/src/default_configs.rs20
-rw-r--r--below/view/src/default_styles.rs2
-rw-r--r--below/view/src/lib.rs4
-rw-r--r--below/view/src/render.rs9
-rw-r--r--below/view/src/summary_view.rs62
-rw-r--r--below/view/src/viewrc.rs14
7 files changed, 112 insertions, 1 deletions
diff --git a/below/model/src/lib.rs b/below/model/src/lib.rs
index 307ccf01..c2e5b067 100644
--- a/below/model/src/lib.rs
+++ b/below/model/src/lib.rs
@@ -470,7 +470,7 @@ pub struct NetworkStats<'a> {
ethtool: &'a Option<ethtool::EthtoolStats>,
}
-#[derive(Serialize, Deserialize, below_derive::Queriable)]
+#[derive(Clone, Serialize, Deserialize, below_derive::Queriable)]
pub struct Model {
#[queriable(ignore)]
pub time_elapsed: Duration,
diff --git a/below/render/src/default_configs.rs b/below/render/src/default_configs.rs
index 016f3cae..7d8e5080 100644
--- a/below/render/src/default_configs.rs
+++ b/below/render/src/default_configs.rs
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+use model::ProcessModelFieldId;
use model::SingleCgroupModelFieldId;
use model::SingleProcessModelFieldId;
use RenderFormat::Duration;
@@ -24,6 +25,25 @@ use RenderFormat::SectorReadableSize;
use super::*;
+impl HasRenderConfig for model::Model {
+ fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
+ use model::ModelFieldId::*;
+ let rc = RenderConfigBuilder::new();
+ match field_id {
+ System(field_id) => model::SystemModel::get_render_config_builder(field_id),
+ Cgroup(field_id) => {
+ model::SingleCgroupModel::get_render_config_builder(&field_id.subquery_id.0)
+ }
+ Process(ProcessModelFieldId::Processes(field_id)) => {
+ model::SingleProcessModel::get_render_config_builder(&field_id.subquery_id.0)
+ }
+ Network(field_id) => model::NetworkModel::get_render_config_builder(field_id),
+ Gpu(_) => rc,
+ Resctrl(_) => rc,
+ }
+ }
+}
+
impl HasRenderConfig for model::SingleCgroupModel {
fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
use model::SingleCgroupModelFieldId::*;
diff --git a/below/view/src/default_styles.rs b/below/view/src/default_styles.rs
index bdb17e92..4e46bde7 100644
--- a/below/view/src/default_styles.rs
+++ b/below/view/src/default_styles.rs
@@ -92,6 +92,8 @@ impl HasViewStyle for model::MemoryModel {
}
}
+impl HasViewStyle for model::Model {}
+
impl HasViewStyle for model::SingleCpuModel {}
impl HasViewStyle for model::VmModel {}
diff --git a/below/view/src/lib.rs b/below/view/src/lib.rs
index 6b456148..315ea8cf 100644
--- a/below/view/src/lib.rs
+++ b/below/view/src/lib.rs
@@ -240,6 +240,8 @@ pub struct ViewState {
/// can certainly go higher (b/c of a loaded system or other delays).
pub lowest_time_elapsed: Duration,
pub timestamp: SystemTime,
+ // TODO: Replace other fields with model
+ pub model: Rc<RefCell<Model>>,
pub system: Rc<RefCell<SystemModel>>,
pub cgroup: Rc<RefCell<CgroupModel>>,
pub process: Rc<RefCell<ProcessModel>>,
@@ -262,6 +264,7 @@ impl ViewState {
self.lowest_time_elapsed = model.time_elapsed;
}
self.timestamp = model.timestamp;
+ self.model.replace(model.clone());
self.system.replace(model.system);
self.cgroup.replace(model.cgroup);
self.process.replace(model.process);
@@ -281,6 +284,7 @@ impl ViewState {
time_elapsed: model.time_elapsed,
lowest_time_elapsed: model.time_elapsed,
timestamp: model.timestamp,
+ model: Rc::new(RefCell::new(model.clone())),
system: Rc::new(RefCell::new(model.system)),
cgroup: Rc::new(RefCell::new(model.cgroup)),
process: Rc::new(RefCell::new(model.process)),
diff --git a/below/view/src/render.rs b/below/view/src/render.rs
index 4ffccae8..13e74c73 100644
--- a/below/view/src/render.rs
+++ b/below/view/src/render.rs
@@ -87,6 +87,11 @@ impl ViewConfig {
self.apply_style(rendered, field)
}
+ pub fn render_tight(&self, field: Option<Field>) -> StyledString {
+ let rendered = self.render_config.render(field.clone(), false);
+ self.apply_style(rendered, field)
+ }
+
pub fn render_indented(&self, field: Option<Field>, depth: usize) -> StyledString {
let rendered = self
.render_config
@@ -138,6 +143,10 @@ impl<F: FieldId> ViewItem<F> {
pub fn render(&self, model: &F::Queriable) -> StyledString {
self.config.render(model.query(&self.field_id))
}
+
+ pub fn render_tight(&self, model: &F::Queriable) -> StyledString {
+ self.config.render_tight(model.query(&self.field_id))
+ }
}
impl<F, T> ViewItem<F>
diff --git a/below/view/src/summary_view.rs b/below/view/src/summary_view.rs
index 76977b40..c884bda9 100644
--- a/below/view/src/summary_view.rs
+++ b/below/view/src/summary_view.rs
@@ -21,9 +21,13 @@ use crate::ViewState;
mod render_impl {
use std::collections::BTreeMap;
+ use std::str::FromStr;
+ use base_render::RenderConfig;
use base_render::RenderConfigBuilder as Rc;
use cursive::utils::markup::StyledString;
+ use model::Model;
+ use model::ModelFieldId;
use model::Queriable;
use model::SingleDiskModel;
use model::SingleNetModel;
@@ -31,6 +35,7 @@ mod render_impl {
use once_cell::sync::Lazy;
use crate::render::ViewItem;
+ use crate::viewrc::ViewRc;
/// Renders corresponding Fields From SystemModel.
type SummaryViewItem = ViewItem<model::SystemModelFieldId>;
@@ -101,6 +106,21 @@ mod render_impl {
row
}
+ pub fn render_extra_row(extra_row: &SummaryViewExtraRow, model: &Model) -> StyledString {
+ let mut row = StyledString::new();
+ if let Some(title) = &extra_row.title {
+ row.append(title.clone());
+ }
+ for item in &extra_row.items {
+ if !row.is_empty() {
+ row.append(" | ");
+ }
+ row.append(format!("{} ", item.config.render_config.get_title()));
+ row.append(item.render_tight(model));
+ }
+ row
+ }
+
pub fn render_read_write_models_row<'a, T: 'a + Queriable>(
name: &'static str,
models: impl Iterator<Item = (&'a String, &'a T)>,
@@ -162,6 +182,39 @@ mod render_impl {
ViewItem::from_default(TxBytesPerSec),
)
}
+
+ pub struct SummaryViewExtraRow {
+ pub title: Option<String>,
+ pub items: Vec<ViewItem<model::ModelFieldId>>,
+ }
+
+ pub fn get_summary_view_extra_rows(viewrc: &ViewRc) -> Vec<SummaryViewExtraRow> {
+ if let Some(viewrc_rows) = viewrc.summary_view_extra_rows.as_ref() {
+ viewrc_rows
+ .iter()
+ .map(|viewrc_row| SummaryViewExtraRow {
+ title: viewrc_row.title.clone(),
+ items: viewrc_row
+ .items
+ .iter()
+ // Skip invalid field ids
+ .filter_map(|item| {
+ ModelFieldId::from_str(&item.field_id)
+ .map(|field_id| {
+ ViewItem::from_default(field_id).update(RenderConfig {
+ title: item.alias.clone(),
+ ..Default::default()
+ })
+ })
+ .ok()
+ })
+ .collect(),
+ })
+ .collect()
+ } else {
+ vec![]
+ }
+ }
}
fn fill_content(c: &mut Cursive, v: &mut LinearLayout) {
@@ -184,6 +237,15 @@ fn fill_content(c: &mut Cursive, v: &mut LinearLayout) {
view.add_child(TextView::new(io_row));
view.add_child(TextView::new(iface_row));
+ let model = view_state.model.borrow();
+ // TODO: Save the parsed extra rows in a struct and reuse
+ let extra_rows = render_impl::get_summary_view_extra_rows(&view_state.viewrc);
+ for extra_row in extra_rows {
+ view.add_child(TextView::new(render_impl::render_extra_row(
+ &extra_row, &model,
+ )));
+ }
+
*v = view;
}
diff --git a/below/view/src/viewrc.rs b/below/view/src/viewrc.rs
index 356eb105..267da630 100644
--- a/below/view/src/viewrc.rs
+++ b/below/view/src/viewrc.rs
@@ -28,6 +28,18 @@ pub enum DefaultFrontView {
System,
}
+#[derive(Default, Deserialize)]
+pub struct SummaryViewExtraRowItem {
+ pub alias: Option<String>,
+ pub field_id: String,
+}
+
+#[derive(Default, Deserialize)]
+pub struct SummaryViewExtraRow {
+ pub title: Option<String>,
+ pub items: Vec<SummaryViewExtraRowItem>,
+}
+
/// Runtime configuration on the below view.
#[derive(Default, Deserialize)]
pub struct ViewRc {
@@ -39,6 +51,8 @@ pub struct ViewRc {
pub collapse_cgroups: Option<bool>,
// Overrides cgroup name column width.
pub cgroup_name_width: Option<usize>,
+ // Extra rows to add in the summary view.
+ pub summary_view_extra_rows: Option<Vec<SummaryViewExtraRow>>,
}
impl ViewRc {