Skip to content

Commit

Permalink
feature: Add network interface filtering (#381)
Browse files Browse the repository at this point in the history
Adds a new option in the config file to filter out network interfaces.  Also add the option to filter by whole words.

Interface follows that of the existing ones:

```toml
[net_filter]
is_list_ignored = false
list = ["virbr0.*"]
regex = true
case_sensitive = false
whole_word = false
```
  • Loading branch information
ClementTsang authored Jan 1, 2021
1 parent d8d72d0 commit 90be973
Show file tree
Hide file tree
Showing 15 changed files with 257 additions and 184 deletions.
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"hjkl",
"htop",
"indexmap",
"iwlwifi",
"keybinds",
"le",
"libc",
Expand Down Expand Up @@ -112,6 +113,7 @@
"use",
"use curr usage",
"utime",
"virbr",
"virt",
"vsize",
"whitespaces",
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- [#379](https://github.com/ClementTsang/bottom/pull/379): Adds `--process_command` flag and corresponding config option to default to showing a process' command.

- [#381](https://github.com/ClementTsang/bottom/pull/381): Adds a filter in the config file for network interfaces.

## Changes

- [#372](https://github.com/ClementTsang/bottom/pull/372): Hides the SWAP graph and legend in normal mode if SWAP is 0.
Expand Down
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ A cross-platform graphical process/system monitor with a customizable interface
- [Config flags](#config-flags)
- [Theming](#theming)
- [Layout](#layout)
- [Disk and temperature filtering](#disk-and-temperature-filtering)
- [Disk and temperature filtering](#disk-temperature-and-network-filtering)
- [Battery](#battery)
- [Compatibility](#compatibility)
- [FAQ](#faq)
Expand Down Expand Up @@ -670,9 +670,9 @@ Furthermore, you can have duplicate widgets. This means you could do something l
and get the following CPU donut:
![CPU donut](./assets/cpu_layout.png)

#### Disk and temperature filtering
#### Disk, temperature, and network filtering

You can hide specific disks and temperature sensors by name in the config file via `disk_filter` and `temp_filter` respectively. Regex (`regex = true`) and case-sensitivity (`case_sensitive = true`) are supported, but are off by default.
You can hide specific disks, temperature sensors, and networks by name in the config file via `disk_filter`, `temp_filter`, and `net_filter` respectively. Regex (`regex = true`), case-sensitivity (`case_sensitive = true`), and matching only the entire word (`whole_word = true`) are supported, but are off by default.

For example, let's say , given this disk list:

Expand Down Expand Up @@ -712,6 +712,20 @@ Now, flipping to `case_sensitive = false` would instead show:

![Temp filter after with case sensitivity off](./assets/temp_filter_post2.png)

Lastly, let's say I want to filter out _exactly_ "iwlwifi_1" from my results. I could do:

```toml
[temp_filter]
is_list_ignored = true
list = ["iwlwifi_1"]
case_sensitive = true
whole_word = true
```

This will match the entire word, "iwlwifi_1", and ignore any result that exactly matches it:

![Temp filter after with whole_word](./assets/temp_filter_post3.png)

### Battery

You can get battery statistics (charge, time to fill/discharge, consumption in watts, and battery health) via the battery widget.
Expand Down
Binary file added assets/temp_filter_post3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 0 additions & 16 deletions sample_configs/demo_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,3 @@ whole_word = false
regex = true
default_widget_type = "cpu"
default_widget_count = 1

[colors]
# Based on gruvbox: https://github.com/morhetz/gruvbox
table_header_color="#458588"
widget_title_color="#cc241d"
cpu_core_colors=["#cc241d", "#98971a", "#d79921", "#458588", "#b16286", "#689d6a", "#fb4934", "#b8bb26", "#fabd2f", "#83a598"]
ram_color="#fb4934"
swap_color="#fabd2f"
rx_color="#458588"
tx_color="#689d6a"
border_color="#ebdbb2"
highlighted_border_color="#fe8019"
text_color="#ebdbb2"
graph_color="#ebdbb2"
selected_text_color="#282828"
selected_bg_color="#458588"
4 changes: 3 additions & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ pub struct AppConfigFields {
}

/// For filtering out information
#[derive(Debug, Clone)]
pub struct DataFilters {
pub disk_filter: Option<Filter>,
pub temp_filter: Option<Filter>,
pub net_filter: Option<Filter>,
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Filter {
pub is_list_ignored: bool,
pub list: Vec<regex::Regex>,
Expand Down
23 changes: 15 additions & 8 deletions src/app/data_harvester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use crate::app::layout_manager::UsedWidgets;

use futures::join;

use super::DataFilters;

pub mod batteries;
pub mod cpu;
pub mod disks;
Expand Down Expand Up @@ -96,15 +98,15 @@ pub struct DataCollector {
battery_list: Option<Vec<Battery>>,
#[cfg(target_os = "linux")]
page_file_size_kb: u64,
filters: DataFilters,
}

impl Default for DataCollector {
fn default() -> Self {
// trace!("Creating default data collector...");
impl DataCollector {
pub fn new(filters: DataFilters) -> Self {
DataCollector {
data: Data::default(),
#[cfg(not(target_os = "linux"))]
sys: System::new_with_specifics(sysinfo::RefreshKind::new()), // FIXME: Make this run on only macOS and Windows.
sys: System::new_with_specifics(sysinfo::RefreshKind::new()),
#[cfg(target_os = "linux")]
previous_cpu_times: vec![],
#[cfg(target_os = "linux")]
Expand Down Expand Up @@ -132,11 +134,10 @@ impl Default for DataCollector {
// page_file_size_kb
libc::sysconf(libc::_SC_PAGESIZE) as u64 / 1024
},
filters,
}
}
}

impl DataCollector {
pub fn init(&mut self) {
#[cfg(target_os = "linux")]
{
Expand All @@ -147,6 +148,7 @@ impl DataCollector {
self.sys.refresh_memory();
self.mem_total_kb = self.sys.get_total_memory();

// TODO: Would be good to get this and network list running on a timer instead...?
// Refresh components list once...
if self.widgets_to_harvest.use_temp {
self.sys.refresh_components_list();
Expand Down Expand Up @@ -295,6 +297,7 @@ impl DataCollector {
&mut self.total_tx,
current_instant,
self.widgets_to_harvest.use_net,
&self.filters.net_filter,
)
}
#[cfg(not(target_os = "windows"))]
Expand All @@ -305,19 +308,22 @@ impl DataCollector {
&mut self.total_tx,
current_instant,
self.widgets_to_harvest.use_net,
&self.filters.net_filter,
)
}
};
let mem_data_fut = mem::get_mem_data(self.widgets_to_harvest.use_mem);
let disk_data_fut = disks::get_disk_usage(self.widgets_to_harvest.use_disk);
let disk_io_usage_fut = disks::get_io_usage(false, self.widgets_to_harvest.use_disk);
let disk_data_fut =
disks::get_disk_usage(self.widgets_to_harvest.use_disk, &self.filters.disk_filter);
let disk_io_usage_fut = disks::get_io_usage(self.widgets_to_harvest.use_disk);
let temp_data_fut = {
#[cfg(not(target_os = "linux"))]
{
temperature::get_temperature_data(
&self.sys,
&self.temperature_type,
self.widgets_to_harvest.use_temp,
&self.filters.temp_filter,
)
}

Expand All @@ -326,6 +332,7 @@ impl DataCollector {
temperature::get_temperature_data(
&self.temperature_type,
self.widgets_to_harvest.use_temp,
&self.filters.temp_filter,
)
}
};
Expand Down
113 changes: 58 additions & 55 deletions src/app/data_harvester/disks.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::app::Filter;

#[derive(Debug, Clone, Default)]
pub struct DiskHarvest {
pub name: String,
Expand All @@ -15,9 +17,7 @@ pub struct IOData {

pub type IOHarvest = std::collections::HashMap<String, Option<IOData>>;

pub async fn get_io_usage(
get_physical: bool, actually_get: bool,
) -> crate::utils::error::Result<Option<IOHarvest>> {
pub async fn get_io_usage(actually_get: bool) -> crate::utils::error::Result<Option<IOHarvest>> {
if !actually_get {
return Ok(None);
}
Expand All @@ -26,45 +26,31 @@ pub async fn get_io_usage(

let mut io_hash: std::collections::HashMap<String, Option<IOData>> =
std::collections::HashMap::new();
if get_physical {
let physical_counter_stream = heim::disk::io_counters_physical().await?;
futures::pin_mut!(physical_counter_stream);

while let Some(io) = physical_counter_stream.next().await {
if let Ok(io) = io {
let mount_point = io.device_name().to_str().unwrap_or("Name Unavailable");
io_hash.insert(
mount_point.to_string(),
Some(IOData {
read_bytes: io.read_bytes().get::<heim::units::information::megabyte>(),
write_bytes: io.write_bytes().get::<heim::units::information::megabyte>(),
}),
);
}
}
} else {
let counter_stream = heim::disk::io_counters().await?;
futures::pin_mut!(counter_stream);

while let Some(io) = counter_stream.next().await {
if let Ok(io) = io {
let mount_point = io.device_name().to_str().unwrap_or("Name Unavailable");
io_hash.insert(
mount_point.to_string(),
Some(IOData {
read_bytes: io.read_bytes().get::<heim::units::information::byte>(),
write_bytes: io.write_bytes().get::<heim::units::information::byte>(),
}),
);
}

let counter_stream = heim::disk::io_counters().await?;
futures::pin_mut!(counter_stream);

while let Some(io) = counter_stream.next().await {
if let Ok(io) = io {
let mount_point = io.device_name().to_str().unwrap_or("Name Unavailable");

// FIXME: [MOUNT POINT] Add the filter here I guess?

io_hash.insert(
mount_point.to_string(),
Some(IOData {
read_bytes: io.read_bytes().get::<heim::units::information::byte>(),
write_bytes: io.write_bytes().get::<heim::units::information::byte>(),
}),
);
}
}

Ok(Some(io_hash))
}

pub async fn get_disk_usage(
actually_get: bool,
actually_get: bool, name_filter: &Option<Filter>,
) -> crate::utils::error::Result<Option<Vec<DiskHarvest>>> {
if !actually_get {
return Ok(None);
Expand All @@ -77,26 +63,43 @@ pub async fn get_disk_usage(
futures::pin_mut!(partitions_stream);

while let Some(part) = partitions_stream.next().await {
if let Ok(part) = part {
let partition = part;
let usage = heim::disk::usage(partition.mount_point().to_path_buf()).await?;

vec_disks.push(DiskHarvest {
free_space: usage.free().get::<heim::units::information::byte>(),
used_space: usage.used().get::<heim::units::information::byte>(),
total_space: usage.total().get::<heim::units::information::byte>(),
mount_point: (partition
.mount_point()
.to_str()
.unwrap_or("Name Unavailable"))
.to_string(),
name: (partition
.device()
.unwrap_or_else(|| std::ffi::OsStr::new("Name Unavailable"))
.to_str()
.unwrap_or("Name Unavailable"))
.to_string(),
});
if let Ok(partition) = part {
let name = (partition
.device()
.unwrap_or_else(|| std::ffi::OsStr::new("Name Unavailable"))
.to_str()
.unwrap_or("Name Unavailable"))
.to_string();

let mount_point = (partition
.mount_point()
.to_str()
.unwrap_or("Name Unavailable"))
.to_string();

let to_keep = if let Some(filter) = name_filter {
let mut ret = filter.is_list_ignored;
for r in &filter.list {
if r.is_match(&name) {
ret = !filter.is_list_ignored;
break;
}
}
ret
} else {
true
};

if to_keep {
let usage = heim::disk::usage(partition.mount_point().to_path_buf()).await?;
vec_disks.push(DiskHarvest {
free_space: usage.free().get::<heim::units::information::byte>(),
used_space: usage.used().get::<heim::units::information::byte>(),
total_space: usage.total().get::<heim::units::information::byte>(),
mount_point,
name,
});
}
}
}

Expand Down
Loading

0 comments on commit 90be973

Please sign in to comment.