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

116
Cargo.lock generated
View File

@@ -271,12 +271,36 @@ dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"strsim 0.8.0",
"textwrap 0.11.0",
"unicode-width",
"vec_map",
]
[[package]]
name = "clap"
version = "3.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b"
dependencies = [
"atty",
"bitflags",
"clap_lex",
"indexmap",
"strsim 0.10.0",
"termcolor",
"textwrap 0.15.0",
]
[[package]]
name = "clap_lex"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
@@ -662,7 +686,7 @@ dependencies = [
"bitflags",
"byteorder",
"chrono",
"clap",
"clap 2.34.0",
"crc",
"dialoguer",
"encoding",
@@ -711,6 +735,16 @@ dependencies = [
"instant",
]
[[package]]
name = "file-chunker"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92828425bb36590609d28014a252d6f0f71b698875a2b131fae367c627b6c656"
dependencies = [
"anyhow",
"memmap2",
]
[[package]]
name = "flate2"
version = "1.0.23"
@@ -886,7 +920,7 @@ version = "1.2.2"
dependencies = [
"base64 0.13.0",
"chrono",
"clap",
"clap 2.34.0",
"csv",
"dotenv",
"downcast-rs",
@@ -897,6 +931,7 @@ dependencies = [
"hex 0.4.3",
"hhmmss",
"is_elevated",
"krapslog",
"lazy_static",
"linked-hash-map",
"num_cpus",
@@ -911,6 +946,7 @@ dependencies = [
"slack-hook",
"static_vcruntime",
"termcolor",
"terminal_size",
"tokio 1.18.2",
"yaml-rust",
]
@@ -1059,6 +1095,18 @@ dependencies = [
"hashbrown 0.11.2",
]
[[package]]
name = "indicatif"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b"
dependencies = [
"console",
"lazy_static",
"number_prefix",
"regex",
]
[[package]]
name = "indoc"
version = "1.0.6"
@@ -1144,6 +1192,27 @@ dependencies = [
"winapi-build",
]
[[package]]
name = "krapslog"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70d4d54b2c8b875b6692487e5269cb66f12cd51af11fe1807f135ad0d6b771de"
dependencies = [
"anyhow",
"atty",
"chrono",
"clap 3.1.18",
"file-chunker",
"indicatif",
"memmap2",
"num_cpus",
"progress-streams",
"rayon",
"regex",
"tempfile",
"terminal_size",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@@ -1248,6 +1317,15 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memmap2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "057a3db23999c867821a7a59feb06a578fcb03685e983dff90daf9e7d24ac08f"
dependencies = [
"libc",
]
[[package]]
name = "memoffset"
version = "0.5.6"
@@ -1403,6 +1481,12 @@ dependencies = [
"libc",
]
[[package]]
name = "number_prefix"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "object"
version = "0.28.4"
@@ -1473,6 +1557,12 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "os_str_bytes"
version = "6.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435"
[[package]]
name = "parking_lot"
version = "0.9.0"
@@ -1587,6 +1677,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "progress-streams"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e965d96c8162c607b0cd8d66047ad3c9fd35273c134d994327882c6e47f986a7"
[[package]]
name = "publicsuffix"
version = "1.5.6"
@@ -2208,6 +2304,12 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.95"
@@ -2284,6 +2386,12 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "textwrap"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]]
name = "thiserror"
version = "1.0.31"

View File

@@ -33,6 +33,8 @@ hex = "0.4.*"
git2="0.13"
termcolor="*"
prettytable-rs = "0.8"
krapslog="*"
terminal_size = "*"
[target.'cfg(windows)'.dependencies]
is_elevated = "0.1.2"

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