output timeline histogram (#535)
* added krapslog in cargo * added output timeline histgram feature #533 * added termilan_size to cargo * adjust timeline histgram width size to terminal width #533 * added section output in timeline histogram #533 * centering timeline histgram title #533
This commit is contained in:
@@ -5,6 +5,7 @@ use crate::detections::utils;
|
||||
use chrono::{DateTime, Local, TimeZone, Utc};
|
||||
use csv::QuoteStyle;
|
||||
use hashbrown::HashMap;
|
||||
use krapslog::{build_sparkline, build_time_markers};
|
||||
use lazy_static::lazy_static;
|
||||
use serde::Serialize;
|
||||
use std::error::Error;
|
||||
@@ -14,6 +15,7 @@ use std::io::BufWriter;
|
||||
use std::io::Write;
|
||||
use std::process;
|
||||
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
|
||||
use terminal_size::{terminal_size, Width};
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
@@ -98,6 +100,30 @@ fn _get_output_color(color_map: &HashMap<String, Color>, level: &str) -> Option<
|
||||
color
|
||||
}
|
||||
|
||||
/// print timeline histogram
|
||||
fn _print_timeline_hist(timestamps: Vec<i64>, marker_count: usize, length: usize) {
|
||||
if timestamps.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let buf_wtr = BufferWriter::stdout(ColorChoice::Always);
|
||||
let mut wtr = buf_wtr.buffer();
|
||||
|
||||
let title = "Event Frequency Timeline";
|
||||
let header_row_space = (length - title.len()) / 2;
|
||||
writeln!(wtr).ok();
|
||||
write!(wtr, "{}", " ".repeat(header_row_space)).ok();
|
||||
writeln!(wtr, "{}", title).ok();
|
||||
writeln!(wtr).ok();
|
||||
|
||||
let (header, footer) = build_time_markers(×tamps, marker_count, length);
|
||||
let sparkline = build_sparkline(×tamps, length);
|
||||
writeln!(wtr, "{}", header).ok();
|
||||
writeln!(wtr, "{}", sparkline.unwrap_or_default()).ok();
|
||||
writeln!(wtr, "{}", footer).ok();
|
||||
buf_wtr.print(&wtr).ok();
|
||||
}
|
||||
|
||||
pub fn after_fact() {
|
||||
let fn_emit_csv_err = |err: Box<dyn Error>| {
|
||||
AlertMessage::alert(
|
||||
@@ -151,8 +177,10 @@ fn emit_csv<W: std::io::Write>(
|
||||
let mut detected_rule_files: Vec<String> = Vec::new();
|
||||
|
||||
println!();
|
||||
let mut timestamps: Vec<i64> = Vec::new();
|
||||
let mut plus_header = true;
|
||||
for (time, detect_infos) in messages.iter() {
|
||||
timestamps.push(_get_timestamp(time));
|
||||
for detect_info in detect_infos {
|
||||
let mut level = detect_info.level.to_string();
|
||||
if level == "informational" {
|
||||
@@ -224,6 +252,13 @@ fn emit_csv<W: std::io::Write>(
|
||||
wtr.flush()?;
|
||||
}
|
||||
println!();
|
||||
let size = terminal_size();
|
||||
let terminal_width = match size {
|
||||
Some((Width(w), _)) => w as usize,
|
||||
None => 100,
|
||||
};
|
||||
_print_timeline_hist(timestamps, 10, terminal_width);
|
||||
println!();
|
||||
_print_unique_results(
|
||||
total_detect_counts_by_level,
|
||||
"Total".to_string(),
|
||||
@@ -325,6 +360,15 @@ fn format_time(time: &DateTime<Utc>) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// get timestamp to input datetime.
|
||||
fn _get_timestamp(time: &DateTime<Utc>) -> i64 {
|
||||
if configs::CONFIG.read().unwrap().args.is_present("utc") {
|
||||
time.timestamp()
|
||||
} else {
|
||||
time.with_timezone(&Local).timestamp()
|
||||
}
|
||||
}
|
||||
|
||||
/// return rfc time format string by option
|
||||
fn format_rfc<Tz: TimeZone>(time: &DateTime<Tz>) -> String
|
||||
where
|
||||
|
||||
Reference in New Issue
Block a user