mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 10:04:12 +02:00
group by remote and user
This commit is contained in:
parent
06704ebc6a
commit
181559d841
4 changed files with 92 additions and 21 deletions
|
|
@ -1,14 +1,19 @@
|
||||||
mod app;
|
mod app;
|
||||||
|
mod remote;
|
||||||
mod unique;
|
mod unique;
|
||||||
mod url;
|
mod url;
|
||||||
|
mod user;
|
||||||
|
|
||||||
use crate::app::{Filter, LineSet};
|
use crate::app::{Filter, LineSet};
|
||||||
use crate::grouping::app::{AppGrouping, APP_GROUPING_UI};
|
use crate::grouping::app::{AppGrouping, APP_GROUPING_UI};
|
||||||
|
use crate::grouping::remote::{RemoteGrouping, REMOTE_GROUPING_UI};
|
||||||
use crate::grouping::url::{UrlGrouping, URL_GROUPING_UI};
|
use crate::grouping::url::{UrlGrouping, URL_GROUPING_UI};
|
||||||
|
use crate::grouping::user::{UserGrouping, USER_GROUPING_UI};
|
||||||
use crate::logfile::LogLine;
|
use crate::logfile::LogLine;
|
||||||
use crate::matcher::MatchResult;
|
use crate::matcher::MatchResult;
|
||||||
use crate::timegraph::{SparkLine, TimeGraph};
|
use crate::timegraph::{SparkLine, TimeGraph};
|
||||||
use ahash::AHasher;
|
use ahash::AHasher;
|
||||||
|
use derive_more::From;
|
||||||
use ratatui::layout::{Alignment, Constraint};
|
use ratatui::layout::{Alignment, Constraint};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::OnceCell;
|
use std::cell::OnceCell;
|
||||||
|
|
@ -120,29 +125,13 @@ where
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Clone, From)]
|
||||||
pub enum Groupings<'logs> {
|
pub enum Groupings<'logs> {
|
||||||
Match(MatchResult),
|
Match(MatchResult),
|
||||||
Url(UrlGrouping<'logs>),
|
Url(UrlGrouping<'logs>),
|
||||||
App(AppGrouping<'logs>),
|
App(AppGrouping<'logs>),
|
||||||
}
|
User(UserGrouping<'logs>),
|
||||||
|
Remote(RemoteGrouping<'logs>),
|
||||||
impl<'logs> From<MatchResult> for Groupings<'logs> {
|
|
||||||
fn from(value: MatchResult) -> Self {
|
|
||||||
Groupings::Match(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'logs> From<UrlGrouping<'logs>> for Groupings<'logs> {
|
|
||||||
fn from(value: UrlGrouping<'logs>) -> Self {
|
|
||||||
Groupings::Url(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'logs> From<AppGrouping<'logs>> for Groupings<'logs> {
|
|
||||||
fn from(value: AppGrouping<'logs>) -> Self {
|
|
||||||
Groupings::App(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'logs> GroupingResult<'logs> for Groupings<'logs> {
|
impl<'logs> GroupingResult<'logs> for Groupings<'logs> {
|
||||||
|
|
@ -151,6 +140,8 @@ impl<'logs> GroupingResult<'logs> for Groupings<'logs> {
|
||||||
Groupings::Match(r) => r.matches(filter),
|
Groupings::Match(r) => r.matches(filter),
|
||||||
Groupings::Url(r) => r.matches(filter),
|
Groupings::Url(r) => r.matches(filter),
|
||||||
Groupings::App(r) => r.matches(filter),
|
Groupings::App(r) => r.matches(filter),
|
||||||
|
Groupings::User(r) => r.matches(filter),
|
||||||
|
Groupings::Remote(r) => r.matches(filter),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,6 +152,8 @@ impl<'logs> GroupingResult<'logs> for Groupings<'logs> {
|
||||||
}
|
}
|
||||||
Groupings::Url(r) => Box::new(r.render()),
|
Groupings::Url(r) => Box::new(r.render()),
|
||||||
Groupings::App(r) => Box::new(r.render()),
|
Groupings::App(r) => Box::new(r.render()),
|
||||||
|
Groupings::User(r) => Box::new(r.render()),
|
||||||
|
Groupings::Remote(r) => Box::new(r.render()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -169,11 +162,19 @@ impl<'logs> GroupingResult<'logs> for Groupings<'logs> {
|
||||||
pub enum GroupingOptions {
|
pub enum GroupingOptions {
|
||||||
Url,
|
Url,
|
||||||
App,
|
App,
|
||||||
|
User,
|
||||||
|
Remote,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GroupingOptions {
|
impl GroupingOptions {
|
||||||
pub fn all() -> impl Iterator<Item = Self> {
|
pub fn all() -> impl Iterator<Item = Self> {
|
||||||
[GroupingOptions::Url, GroupingOptions::App].into_iter()
|
[
|
||||||
|
GroupingOptions::Url,
|
||||||
|
GroupingOptions::App,
|
||||||
|
GroupingOptions::User,
|
||||||
|
GroupingOptions::Remote,
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn group_key(&self, line: &LogLine) -> u64 {
|
pub fn group_key(&self, line: &LogLine) -> u64 {
|
||||||
|
|
@ -181,6 +182,8 @@ impl GroupingOptions {
|
||||||
match self {
|
match self {
|
||||||
GroupingOptions::Url => line.url.hash(&mut hasher),
|
GroupingOptions::Url => line.url.hash(&mut hasher),
|
||||||
GroupingOptions::App => line.app.hash(&mut hasher),
|
GroupingOptions::App => line.app.hash(&mut hasher),
|
||||||
|
GroupingOptions::User => line.user.hash(&mut hasher),
|
||||||
|
GroupingOptions::Remote => line.remote.hash(&mut hasher),
|
||||||
}
|
}
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
|
|
@ -193,6 +196,12 @@ impl GroupingOptions {
|
||||||
GroupingOptions::App => Groupings::App(AppGrouping {
|
GroupingOptions::App => Groupings::App(AppGrouping {
|
||||||
app: line.app.as_ref(),
|
app: line.app.as_ref(),
|
||||||
}),
|
}),
|
||||||
|
GroupingOptions::User => Groupings::User(UserGrouping {
|
||||||
|
user: line.user.as_str(),
|
||||||
|
}),
|
||||||
|
GroupingOptions::Remote => Groupings::Remote(RemoteGrouping {
|
||||||
|
remote: line.remote.as_str(),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,6 +209,8 @@ impl GroupingOptions {
|
||||||
match self {
|
match self {
|
||||||
GroupingOptions::Url => "Url",
|
GroupingOptions::Url => "Url",
|
||||||
GroupingOptions::App => "App",
|
GroupingOptions::App => "App",
|
||||||
|
GroupingOptions::User => "User",
|
||||||
|
GroupingOptions::Remote => "Remote",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,6 +218,8 @@ impl GroupingOptions {
|
||||||
match self {
|
match self {
|
||||||
GroupingOptions::Url => URL_GROUPING_UI,
|
GroupingOptions::Url => URL_GROUPING_UI,
|
||||||
GroupingOptions::App => APP_GROUPING_UI,
|
GroupingOptions::App => APP_GROUPING_UI,
|
||||||
|
GroupingOptions::User => USER_GROUPING_UI,
|
||||||
|
GroupingOptions::Remote => REMOTE_GROUPING_UI,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
29
src/grouping/remote.rs
Normal file
29
src/grouping/remote.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
use crate::app::Filter;
|
||||||
|
use crate::grouping::{GroupingResult, GroupingUi};
|
||||||
|
use ratatui::layout::{Alignment, Constraint};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone)]
|
||||||
|
pub struct RemoteGrouping<'a> {
|
||||||
|
pub remote: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const REMOTE_GROUPING_UI: GroupingUi = GroupingUi {
|
||||||
|
header: &[("Remote", Alignment::Left)],
|
||||||
|
widths: &[Constraint::Percentage(100)],
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'a> GroupingResult<'a> for RemoteGrouping<'a> {
|
||||||
|
fn matches(&self, filter: &Filter) -> bool {
|
||||||
|
if filter.is_empty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
filter
|
||||||
|
.parts()
|
||||||
|
.all(|filter_part| filter_part.is_match(self.remote))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&self) -> impl Iterator<Item = Cow<'a, str>> {
|
||||||
|
[self.remote.into()].into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/grouping/user.rs
Normal file
29
src/grouping/user.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
use crate::app::Filter;
|
||||||
|
use crate::grouping::{GroupingResult, GroupingUi};
|
||||||
|
use ratatui::layout::{Alignment, Constraint};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone)]
|
||||||
|
pub struct UserGrouping<'a> {
|
||||||
|
pub user: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const USER_GROUPING_UI: GroupingUi = GroupingUi {
|
||||||
|
header: &[("User", Alignment::Left)],
|
||||||
|
widths: &[Constraint::Percentage(100)],
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'a> GroupingResult<'a> for UserGrouping<'a> {
|
||||||
|
fn matches(&self, filter: &Filter) -> bool {
|
||||||
|
if filter.is_empty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
filter
|
||||||
|
.parts()
|
||||||
|
.all(|filter_part| filter_part.is_match(self.user))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&self) -> impl Iterator<Item = Cow<'a, str>> {
|
||||||
|
[self.user.into()].into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -53,7 +53,7 @@ impl<'a> PartialEq for LogLine<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Hash)]
|
||||||
pub enum LogUser {
|
pub enum LogUser {
|
||||||
None,
|
None,
|
||||||
User(TinyAsciiStr<64>),
|
User(TinyAsciiStr<64>),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue