1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
use {
    crate::{
        Key,
        Fields,
    },
    argh::FromArgs,
    std::path::PathBuf,
};

#[derive(Debug, Default, FromArgs)]
/// Rhit gives you a report of the hits found in your nginx logs.
///
/// Complete documentation at https://dystroy.org/rhit
pub struct Args {

    #[argh(switch)]
    /// print the version
    pub version: bool,

    #[argh(option, default = "Default::default()")]
    /// color and style: 'yes', 'no' or 'auto' (auto should be good in most cases)
    pub color: BoolArg,

    #[argh(option, short = 'k', default = "Default::default()")]
    /// key used in sorting and histogram, either 'hits' (default) or 'bytes'
    pub key: Key,

    #[argh(option, short = 'l', default = "1")]
    /// detail level, from 0 to 6 (default 1), impacts the lengths of tables
    pub length: usize,

    #[argh(option, short = 'f', default = "Default::default()")]
    /// comma separated list of hit fields to display.
    /// Use `-f a` to get all fields.
    /// Use `-f +i` to add i(p).
    /// Available fields: date,method,status,ip,ref,path.
    /// Default fields: date,status,ref,path.
    pub fields: Fields,

    #[argh(switch, short = 'c')]
    /// add tables with more popular and less popular entries (ip, referers or paths)
    pub changes: bool,

    #[argh(option, short = 'd')]
    /// filter the dates, on a precise day or in an inclusive range
    /// (eg: `-r 12/24` or `-r '2021/12/24-2022/01/21'`)
    pub date: Option<String>,

    #[argh(option, short = 'i')]
    /// ip address to filter by. May be negated with a `!`
    pub ip: Option<String>,

    #[argh(option, short = 'm')]
    /// http method to filter by. Make it negative with a `!`.
    /// (eg: `-m PUT` or `-m !DELETE` or `-m none` or `-m other`)
    pub method: Option<String>,

    #[argh(option, short = 'p')]
    /// filter the paths with a pattern
    /// (eg: `-p broot` or `-p '^/\d+'` or `-p 'miaou | blog'`)
    pub path: Option<String>,

    #[argh(option, short = 'r')]
    /// filter the referers with a pattern
    pub referer: Option<String>,

    #[argh(option, short = 's')]
    /// comma separated list of statuses or status ranges.
    /// (eg: `-s 514` or `-s 4xx,5xx`, or `-s 310-340,400-450` or `-s 5xx,!502`)
    pub status: Option<String>,

    #[argh(switch, short = 'a')]
    /// show all paths, including resources
    pub all: bool,

    #[argh(switch)]
    /// tries to open all files, whatever their names
    pub no_name_check: bool,

    #[argh(switch)]
    /// print the original log lines, filtered and sorted
    pub lines: bool,

    #[argh(switch)]
    /// don't print anything during load, no progress bar or file list
    pub silent_load: bool,

    #[argh(positional)]
    /// the log file or folder to analyze
    pub file: Option<PathBuf>,
}

/// An optional boolean for use in Argh
#[derive(Debug, Clone, Copy, Default)]
pub struct BoolArg(Option<bool>);

impl BoolArg {
    pub fn value(self) -> Option<bool> {
        self.0
    }
}

impl argh::FromArgValue for BoolArg {
    fn from_arg_value(value: &str) -> Result<Self, String> {
        match value.to_lowercase().as_ref() {
            "auto" => Ok(BoolArg(None)),
            "yes" => Ok(BoolArg(Some(true))),
            "no" => Ok(BoolArg(Some(false))),
            _ => Err(format!("Illegal value: {:?}", value)),
        }
    }
}