1use clap::builder::PossibleValue;
2use clap::Parser;
3use clap::ValueEnum;
4use env_logger::TimestampPrecision as EnvLoggerTimestampPrecision;
5use logged_stream::BinaryFormatter;
6use logged_stream::BufferFormatter;
7use logged_stream::DecimalFormatter;
8use logged_stream::LowercaseHexadecimalFormatter;
9use logged_stream::OctalFormatter;
10use logged_stream::UppercaseHexadecimalFormatter;
11use std::convert::From;
12use std::fmt;
13use std::net;
14use std::str::FromStr;
15
16#[derive(Debug, Clone, Copy)]
17pub enum LoggingLevel {
18 Trace,
19 Debug,
20 Info,
21 Warn,
22 Error,
23 Off,
24}
25
26impl ValueEnum for LoggingLevel {
27 fn value_variants<'a>() -> &'a [Self] {
28 &[
29 Self::Trace,
30 Self::Debug,
31 Self::Info,
32 Self::Warn,
33 Self::Error,
34 Self::Off,
35 ]
36 }
37
38 fn to_possible_value(&self) -> Option<PossibleValue> {
39 Some(match self {
40 Self::Trace => PossibleValue::new("trace"),
41 Self::Debug => PossibleValue::new("debug"),
42 Self::Info => PossibleValue::new("info"),
43 Self::Warn => PossibleValue::new("warn"),
44 Self::Error => PossibleValue::new("error"),
45 Self::Off => PossibleValue::new("off"),
46 })
47 }
48}
49
50impl FromStr for LoggingLevel {
51 type Err = String;
52
53 fn from_str(s: &str) -> Result<Self, Self::Err> {
54 for variant in Self::value_variants() {
55 if variant.to_possible_value().unwrap().matches(s, false) {
56 return Ok(*variant);
57 }
58 }
59 Err(format!("Invalid variant: {}", s))
60 }
61}
62
63impl fmt::Display for LoggingLevel {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 self.to_possible_value()
66 .expect("no values are skipped")
67 .get_name()
68 .fmt(f)
69 }
70}
71
72#[derive(Debug, Clone, Copy)]
73pub enum PayloadFormatingKind {
74 Decimal,
75 LowerHex,
76 UpperHex,
77 Binary,
78 Octal,
79}
80
81impl ValueEnum for PayloadFormatingKind {
82 fn value_variants<'a>() -> &'a [Self] {
83 &[
84 Self::Decimal,
85 Self::LowerHex,
86 Self::UpperHex,
87 Self::Binary,
88 Self::Octal,
89 ]
90 }
91
92 fn to_possible_value(&self) -> Option<PossibleValue> {
93 Some(match self {
94 Self::Decimal => PossibleValue::new("decimal"),
95 Self::LowerHex => PossibleValue::new("lowerhex"),
96 Self::UpperHex => PossibleValue::new("upperhex"),
97 Self::Binary => PossibleValue::new("binary"),
98 Self::Octal => PossibleValue::new("octal"),
99 })
100 }
101}
102
103impl FromStr for PayloadFormatingKind {
104 type Err = String;
105
106 fn from_str(s: &str) -> Result<Self, Self::Err> {
107 for variant in Self::value_variants() {
108 if variant.to_possible_value().unwrap().matches(s, false) {
109 return Ok(*variant);
110 }
111 }
112 Err(format!("Invalid variant: {}", s))
113 }
114}
115
116impl fmt::Display for PayloadFormatingKind {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 self.to_possible_value()
119 .expect("no values are skipped")
120 .get_name()
121 .fmt(f)
122 }
123}
124
125pub fn get_formatter_by_kind(
126 kind: PayloadFormatingKind,
127 separator: &str,
128) -> Box<dyn BufferFormatter> {
129 match kind {
130 PayloadFormatingKind::Decimal => Box::new(DecimalFormatter::new(Some(separator))),
131 PayloadFormatingKind::LowerHex => {
132 Box::new(LowercaseHexadecimalFormatter::new(Some(separator)))
133 }
134 PayloadFormatingKind::UpperHex => {
135 Box::new(UppercaseHexadecimalFormatter::new(Some(separator)))
136 }
137 PayloadFormatingKind::Binary => Box::new(BinaryFormatter::new(Some(separator))),
138 PayloadFormatingKind::Octal => Box::new(OctalFormatter::new(Some(separator))),
139 }
140}
141
142#[derive(Debug, Clone, Copy)]
143pub enum TimestampPrecision {
144 Seconds,
145 Milliseconds,
146 Microseconds,
147 Nanoseconds,
148}
149
150impl ValueEnum for TimestampPrecision {
151 fn value_variants<'a>() -> &'a [Self] {
152 &[
153 Self::Seconds,
154 Self::Milliseconds,
155 Self::Microseconds,
156 Self::Nanoseconds,
157 ]
158 }
159
160 fn to_possible_value(&self) -> Option<PossibleValue> {
161 Some(match self {
162 Self::Seconds => PossibleValue::new("seconds"),
163 Self::Milliseconds => PossibleValue::new("milliseconds"),
164 Self::Microseconds => PossibleValue::new("microseconds"),
165 Self::Nanoseconds => PossibleValue::new("nanoseconds"),
166 })
167 }
168}
169
170impl FromStr for TimestampPrecision {
171 type Err = String;
172
173 fn from_str(s: &str) -> Result<Self, Self::Err> {
174 for variant in Self::value_variants() {
175 if variant.to_possible_value().unwrap().matches(s, false) {
176 return Ok(*variant);
177 }
178 }
179 Err(format!("Invalid variant: {}", s))
180 }
181}
182
183impl fmt::Display for TimestampPrecision {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 self.to_possible_value()
186 .expect("no values are skipped")
187 .get_name()
188 .fmt(f)
189 }
190}
191
192impl From<TimestampPrecision> for EnvLoggerTimestampPrecision {
193 fn from(precision: TimestampPrecision) -> Self {
194 match precision {
195 TimestampPrecision::Seconds => EnvLoggerTimestampPrecision::Seconds,
196 TimestampPrecision::Milliseconds => EnvLoggerTimestampPrecision::Millis,
197 TimestampPrecision::Microseconds => EnvLoggerTimestampPrecision::Micros,
198 TimestampPrecision::Nanoseconds => EnvLoggerTimestampPrecision::Nanos,
199 }
200 }
201}
202
203#[derive(Debug, Clone, Parser)]
204#[command(next_line_help = true)]
205#[command(author, version, about, long_about = None)]
206pub struct Arguments {
207 #[arg(short, long, default_value = "debug")]
209 pub level: LoggingLevel,
210 #[arg(short, long)]
212 pub bind_listener_addr: net::SocketAddr,
213 #[arg(short, long)]
215 pub remote_addr: net::SocketAddr,
216 #[arg(short, long, default_value = "60")]
218 pub timeout: u64,
219 #[arg(short, long, default_value = "lowerhex")]
221 pub formatting: PayloadFormatingKind,
222 #[arg(short, long, default_value = ":")]
224 pub separator: String,
225 #[arg(short, long, default_value = "seconds")]
227 pub precision: TimestampPrecision,
228}