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:
DustInDark
2022-05-23 21:32:49 +09:00
committed by GitHub
parent 67502bfc4f
commit 947f65a7bc
3 changed files with 158 additions and 4 deletions

View File

@@ -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(&timestamps, marker_count, length);
let sparkline = build_sparkline(&timestamps, 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