1use crate::compiler::prelude::*;
2use nom::{
3 IResult, Parser,
4 branch::alt,
5 bytes::complete::{tag, take_while1},
6 character::complete::char,
7 combinator::map_res,
8 sequence::{delimited, preceded},
9};
10use std::collections::BTreeMap;
11
12fn parse_aws_alb_log(bytes: Value, strict_mode: Option<Value>) -> Resolved {
13 let bytes = bytes.try_bytes()?;
14 let strict_mode = strict_mode
15 .map(Value::try_boolean)
16 .transpose()?
17 .unwrap_or(true);
18 parse_log(&String::from_utf8_lossy(&bytes), strict_mode)
19}
20
21#[derive(Clone, Copy, Debug)]
22pub struct ParseAwsAlbLog;
23
24impl Function for ParseAwsAlbLog {
25 fn identifier(&self) -> &'static str {
26 "parse_aws_alb_log"
27 }
28
29 fn examples(&self) -> &'static [Example] {
30 &[
31 Example {
32 title: "valid",
33 source: r#"parse_aws_alb_log!(s'http 2025-01-01T00:00:00.000000Z a/b 1.1.1.1:1 - 0.000 0.000 0.000 200 200 1 2 "GET http://a/ HTTP/1.1" "u" - - arn:a "Root=1-1-1" "-" "-" 0 2025-01-01T00:00:00.000000Z "f" "-" "-" "-" "-" "-" "-" TID_x')"#,
34 result: Ok(
35 r#"{ "actions_executed": "f", "chosen_cert_arn": null, "classification": null, "classification_reason": null, "client_host": "1.1.1.1:1", "domain_name": null, "elb": "a/b", "elb_status_code": "200", "error_reason": null, "matched_rule_priority": "0", "received_bytes": 1, "redirect_url": null, "request_creation_time": "2025-01-01T00:00:00.000000Z", "request_method": "GET", "request_processing_time": 0.0, "request_protocol": "HTTP/1.1", "request_url": "http://a/", "response_processing_time": 0.0, "sent_bytes": 2, "ssl_cipher": null, "ssl_protocol": null, "target_group_arn": "arn:a", "target_host": null, "target_port_list": [], "target_processing_time": 0.0, "target_status_code": "200", "target_status_code_list": [], "timestamp": "2025-01-01T00:00:00.000000Z", "trace_id": "Root=1-1-1", "type": "http", "user_agent": "u", "traceability_id": "TID_x" }"#,
36 ),
37 },
38 Example {
39 title: "ignores trailing fields when strict_mode is false",
40 source: r#"parse_aws_alb_log!(s'http 2025-01-01T00:00:00.000000Z a/b 1.1.1.1:1 - 0.000 0.000 0.000 200 200 1 2 "GET http://a/ HTTP/1.1" "u" - - arn:a "Root=1-1-1" "-" "-" 0 2025-01-01T00:00:00.000000Z "f" "-" "-" "-" "-" "-" "-" TID_x "-" "-" "-"', strict_mode: false)"#,
41 result: Ok(
42 r#"{ "actions_executed": "f", "chosen_cert_arn": null, "classification": null, "classification_reason": null, "client_host": "1.1.1.1:1", "domain_name": null, "elb": "a/b", "elb_status_code": "200", "error_reason": null, "matched_rule_priority": "0", "received_bytes": 1, "redirect_url": null, "request_creation_time": "2025-01-01T00:00:00.000000Z", "request_method": "GET", "request_processing_time": 0.0, "request_protocol": "HTTP/1.1", "request_url": "http://a/", "response_processing_time": 0.0, "sent_bytes": 2, "ssl_cipher": null, "ssl_protocol": null, "target_group_arn": "arn:a", "target_host": null, "target_port_list": [], "target_processing_time": 0.0, "target_status_code": "200", "target_status_code_list": [], "timestamp": "2025-01-01T00:00:00.000000Z", "trace_id": "Root=1-1-1", "type": "http", "user_agent": "u", "traceability_id": "TID_x" }"#,
43 ),
44 },
45 ]
46 }
47
48 fn compile(
49 &self,
50 _state: &state::TypeState,
51 _ctx: &mut FunctionCompileContext,
52 arguments: ArgumentList,
53 ) -> Compiled {
54 let value = arguments.required("value");
55 let strict_mode = arguments.optional("strict_mode");
56
57 Ok(ParseAwsAlbLogFn::new(value, strict_mode).as_expr())
58 }
59
60 fn parameters(&self) -> &'static [Parameter] {
61 &[
62 Parameter {
63 keyword: "value",
64 kind: kind::BYTES,
65 required: true,
66 },
67 Parameter {
68 keyword: "strict_mode",
69 kind: kind::BOOLEAN,
70 required: false,
71 },
72 ]
73 }
74}
75
76#[derive(Debug, Clone)]
77struct ParseAwsAlbLogFn {
78 value: Box<dyn Expression>,
79 strict_mode: Option<Box<dyn Expression>>,
80}
81
82impl ParseAwsAlbLogFn {
83 fn new(value: Box<dyn Expression>, strict_mode: Option<Box<dyn Expression>>) -> Self {
84 Self { value, strict_mode }
85 }
86}
87
88impl FunctionExpression for ParseAwsAlbLogFn {
89 fn resolve(&self, ctx: &mut Context) -> Resolved {
90 let bytes = self.value.resolve(ctx)?;
91 let strict_mode = self
92 .strict_mode
93 .as_ref()
94 .map(|expr| expr.resolve(ctx))
95 .transpose()?;
96 parse_aws_alb_log(bytes, strict_mode)
97 }
98
99 fn type_def(&self, _: &state::TypeState) -> TypeDef {
100 TypeDef::object(inner_kind()).fallible()
101 }
102}
103
104fn inner_kind() -> BTreeMap<Field, Kind> {
105 BTreeMap::from([
106 (
107 Field::from("actions_executed"),
108 Kind::bytes() | Kind::null(),
109 ),
110 (Field::from("chosen_cert_arn"), Kind::bytes() | Kind::null()),
111 (
112 Field::from("classification_reason"),
113 Kind::bytes() | Kind::null(),
114 ),
115 (Field::from("classification"), Kind::bytes() | Kind::null()),
116 (Field::from("client_host"), Kind::bytes()),
117 (Field::from("domain_name"), Kind::bytes() | Kind::null()),
118 (Field::from("elb_status_code"), Kind::bytes()),
119 (Field::from("elb"), Kind::bytes()),
120 (Field::from("error_reason"), Kind::bytes() | Kind::null()),
121 (
122 Field::from("matched_rule_priority"),
123 Kind::bytes() | Kind::null(),
124 ),
125 (Field::from("received_bytes"), Kind::integer()),
126 (Field::from("redirect_url"), Kind::bytes() | Kind::null()),
127 (Field::from("request_creation_time"), Kind::bytes()),
128 (Field::from("request_method"), Kind::bytes()),
129 (Field::from("request_processing_time"), Kind::float()),
130 (Field::from("request_protocol"), Kind::bytes()),
131 (Field::from("request_url"), Kind::bytes()),
132 (Field::from("response_processing_time"), Kind::float()),
133 (Field::from("sent_bytes"), Kind::integer()),
134 (Field::from("ssl_cipher"), Kind::bytes() | Kind::null()),
135 (Field::from("ssl_protocol"), Kind::bytes() | Kind::null()),
136 (Field::from("target_group_arn"), Kind::bytes()),
137 (Field::from("target_host"), Kind::bytes() | Kind::null()),
138 (
139 Field::from("target_port_list"),
140 Kind::bytes() | Kind::null(),
141 ),
142 (Field::from("target_processing_time"), Kind::float()),
143 (
144 Field::from("target_status_code_list"),
145 Kind::bytes() | Kind::null(),
146 ),
147 (
148 Field::from("target_status_code"),
149 Kind::bytes() | Kind::null(),
150 ),
151 (Field::from("timestamp"), Kind::bytes()),
152 (Field::from("trace_id"), Kind::bytes()),
153 (Field::from("type"), Kind::bytes()),
154 (Field::from("user_agent"), Kind::bytes()),
155 (Field::from("traceability_id"), Kind::bytes() | Kind::null()),
156 ])
157}
158
159#[allow(clippy::too_many_lines)]
160fn parse_log(mut input: &str, strict_mode: bool) -> ExpressionResult<Value> {
161 let mut log = BTreeMap::<KeyString, Value>::new();
162
163 macro_rules! get_value {
164 ($name:expr_2021, $parser:expr_2021, $err:ty) => {{
165 let result: IResult<_, _, $err> = $parser.parse(input);
166 match result {
167 Ok((rest, value)) => {
168 input = rest;
169 value
170 }
171 Err(error) => {
172 return Err(format!("failed to get field `{}`: {}", $name, error).into());
173 }
174 }
175 }};
176 ($name:expr_2021, $parser:expr_2021) => {
177 get_value!($name, $parser, (&str, nom::error::ErrorKind))
178 };
179 }
180 macro_rules! field_raw {
181 ($name:expr_2021, $parser:expr_2021, $err:ty) => {
182 log.insert(
183 $name.into(),
184 match get_value!($name, $parser, $err).into() {
185 Value::Bytes(bytes) if bytes == "-" => Value::Null,
186 value => value,
187 },
188 )
189 };
190 ($name:expr_2021, $parser:expr_2021) => {
191 field_raw!($name, $parser, (&str, nom::error::ErrorKind))
192 };
193 }
194 macro_rules! field {
195 ($name:expr_2021, $($pattern:pat_param)|+) => {
196 field_raw!($name, preceded(char(' '), take_while1(|c| matches!(c, $($pattern)|+))))
197 };
198 }
199 macro_rules! field_parse {
200 ($name:expr_2021, $($pattern:pat_param)|+, $type:ty) => {
201 field_raw!($name, map_res(preceded(char(' '), take_while1(|c| matches!(c, $($pattern)|+))), |s: &str| s.parse::<$type>()))
202 };
203 }
204 macro_rules! field_tid {
205 ($name:expr_2021) => {
206 log.insert(
207 $name.into(),
208 match get_value!($name, take_tid_or_nothing) {
209 Some(value) => Value::Bytes(value.to_owned().into()),
210 None => Value::Null,
211 },
212 )
213 };
214 }
215
216 field_raw!("type", take_while1(|c| matches!(c, 'a'..='z' | '0'..='9')));
217 field!("timestamp", '0'..='9' | '.' | '-' | ':' | 'T' | 'Z');
218 field_raw!("elb", take_anything);
219 field!("client_host", '0'..='9' | 'a'..='f' | '.' | ':' | '-');
220 field!("target_host", '0'..='9' | 'a'..='f' | '.' | ':' | '-');
221 field_parse!(
222 "request_processing_time",
223 '0'..='9' | '.' | '-',
224 NotNan<f64>
225 );
226 field_parse!("target_processing_time", '0'..='9' | '.' | '-', NotNan<f64>);
227 field_parse!(
228 "response_processing_time",
229 '0'..='9' | '.' | '-',
230 NotNan<f64>
231 );
232 field!("elb_status_code", '0'..='9' | '-');
233 field!("target_status_code", '0'..='9' | '-');
234 field_parse!("received_bytes", '0'..='9' | '-', i64);
235 field_parse!("sent_bytes", '0'..='9' | '-', i64);
236 let request = get_value!("request", take_quoted1);
237 let mut iter = request.splitn(2, ' ');
238 log.insert(
239 "request_method".to_owned().into(),
240 match iter.next().unwrap().into() {
241 Value::Bytes(bytes) if bytes == "-" => Value::Null,
242 value => value,
243 },
244 ); match iter.next() {
246 Some(value) => {
247 let mut iter = value.rsplitn(2, ' ');
248 log.insert(
249 "request_protocol".to_owned().into(),
250 match iter.next().unwrap().into() {
251 Value::Bytes(bytes) if bytes == "-" => Value::Null,
252 value => value,
253 },
254 ); match iter.next() {
256 Some(value) => log.insert("request_url".into(), value.into()),
257 None => return Err("failed to get field `request_url`".into()),
258 }
259 }
260 None => return Err("failed to get field `request_url`".into()),
261 };
262
263 field_raw!("user_agent", take_quoted1);
264 field_raw!("ssl_cipher", take_anything);
265 field_raw!("ssl_protocol", take_anything);
266 field_raw!("target_group_arn", take_anything);
267 field_raw!("trace_id", take_quoted1);
268 field_raw!("domain_name", take_quoted1);
269 field_raw!("chosen_cert_arn", take_quoted1);
270 field!("matched_rule_priority", '0'..='9' | '-');
271 field!(
272 "request_creation_time",
273 '0'..='9' | '.' | '-' | ':' | 'T' | 'Z'
274 );
275 field_raw!("actions_executed", take_quoted1);
276 field_raw!("redirect_url", take_quoted1);
277 field_raw!("error_reason", take_quoted1);
278 field_raw!(
279 "target_port_list",
280 take_maybe_quoted_list(|c| matches!(c, '0'..='9' | 'a'..='f' | '.' | ':' | '-')),
281 ()
282 );
283 field_raw!(
284 "target_status_code_list",
285 take_maybe_quoted_list(|c| c.is_ascii_digit()),
286 ()
287 );
288 field_raw!("classification", take_quoted1);
289 field_raw!("classification_reason", take_quoted1);
290 field_tid!("traceability_id");
291
292 if input.is_empty() {
293 Ok(log.into())
294 } else if strict_mode {
295 Err(format!(r#"Log should be fully consumed: "{input}""#).into())
296 } else {
297 Ok(log.into())
299 }
300}
301
302type SResult<'a, O> = IResult<&'a str, O, (&'a str, nom::error::ErrorKind)>;
303
304fn take_anything(input: &str) -> SResult<'_, &str> {
305 preceded(char(' '), take_while1(|c| c != ' ')).parse(input)
306}
307
308fn take_quoted1(input: &str) -> SResult<'_, String> {
309 delimited(tag(" \""), until_quote, char('"')).parse(input)
310}
311
312fn take_tid_or_nothing(input: &str) -> SResult<'_, Option<&str>> {
313 if input.starts_with(" TID_") {
314 let (rest, value) = take_anything(input)?;
315 Ok((rest, Some(value)))
316 } else {
317 Ok((input, None))
318 }
319}
320
321fn until_quote(input: &str) -> SResult<'_, String> {
322 let mut ret = String::new();
323 let mut skip_delimiter = false;
324 for (i, ch) in input.char_indices() {
325 if ch == '\\' && !skip_delimiter {
326 skip_delimiter = true;
327 } else if ch == '"' && !skip_delimiter {
328 return Ok((&input[i..], ret));
329 } else {
330 ret.push(ch);
331 skip_delimiter = false;
332 }
333 }
334 Err(nom::Err::Incomplete(nom::Needed::Unknown))
335}
336
337fn take_maybe_quoted_list<'a>(
338 cond: impl Fn(char) -> bool + Clone,
339) -> impl Parser<&'a str, Error = (), Output = Vec<&'a str>> {
340 alt((
341 map_res(tag(r#" "-""#), |_| {
342 Ok::<_, std::convert::Infallible>(vec![])
343 }),
344 map_res(
345 delimited(tag(" \""), take_while1(cond.clone()), char('"')),
346 |v: &str| Ok::<_, std::convert::Infallible>(vec![v]),
347 ),
348 map_res(preceded(char(' '), take_while1(cond)), |v: &str| {
349 Ok::<_, std::convert::Infallible>(vec![v])
350 }),
351 ))
352}
353
354#[cfg(test)]
355mod tests {
356 use super::*;
357 use crate::value;
358
359 test_function![
360 parse_aws_alb_log => ParseAwsAlbLog;
361
362 one {
363 args: func_args![value: r#"http 2018-07-02T22:23:00.186641Z app/my-loadbalancer/50dc6c495c0c9188 192.168.131.39:2817 10.0.0.1:80 0.000 0.001 0.000 200 200 34 366 "GET http://www.example.com:80/ HTTP/1.1" "curl/7.46.0" - - arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 "Root=1-58337262-36d228ad5d99923122bbe354" "-" "-" 0 2018-07-02T22:22:48.364000Z "forward" "-" "-" 10.0.0.1:80 200 "-" "-" TID_dc57cebed65b444ebc8177bb698fe166"#],
364 want: Ok(value!({actions_executed: "forward",
365 chosen_cert_arn: null,
366 classification: null,
367 classification_reason: null,
368 client_host: "192.168.131.39:2817",
369 domain_name: null,
370 elb: "app/my-loadbalancer/50dc6c495c0c9188",
371 elb_status_code: "200",
372 error_reason: null,
373 matched_rule_priority: "0",
374 received_bytes: 34,
375 redirect_url: null,
376 request_creation_time: "2018-07-02T22:22:48.364000Z",
377 request_method: "GET",
378 request_processing_time: 0.0,
379 request_protocol: "HTTP/1.1",
380 request_url: "http://www.example.com:80/",
381 response_processing_time: 0.0,
382 sent_bytes: 366,
383 ssl_cipher: null,
384 ssl_protocol: null,
385 target_group_arn: "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067",
386 target_host: "10.0.0.1:80",
387 target_port_list: ["10.0.0.1:80"],
388 target_processing_time: 0.001,
389 target_status_code: "200",
390 target_status_code_list: ["200"],
391 timestamp: "2018-07-02T22:23:00.186641Z",
392 trace_id: "Root=1-58337262-36d228ad5d99923122bbe354",
393 type: "http",
394 user_agent: "curl/7.46.0",
395 traceability_id: "TID_dc57cebed65b444ebc8177bb698fe166"
396
397
398 })),
399 tdef: TypeDef::object(inner_kind()).fallible(),
400 }
401
402 two {
403 args: func_args![value: r#"https 2018-07-02T22:23:00.186641Z app/my-loadbalancer/50dc6c495c0c9188 192.168.131.39:2817 10.0.0.1:80 0.086 0.048 0.037 200 200 0 57 "GET https://www.example.com:443/ HTTP/1.1" "curl/7.46.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 "Root=1-58337281-1d84f3d73c47ec4e58577259" "www.example.com" "arn:aws:acm:us-east-2:123456789012:certificate/12345678-1234-1234-1234-123456789012" 1 2018-07-02T22:22:48.364000Z "authenticate,forward" "-" "-" 10.0.0.1:80 200 "-" "-" TID_dc57cebed65b444ebc8177bb698fe166"#],
404 want: Ok(value! ({actions_executed: "authenticate,forward",
405 chosen_cert_arn: "arn:aws:acm:us-east-2:123456789012:certificate/12345678-1234-1234-1234-123456789012",
406 classification: null,
407 classification_reason: null,
408 client_host: "192.168.131.39:2817",
409 domain_name: "www.example.com",
410 elb: "app/my-loadbalancer/50dc6c495c0c9188",
411 elb_status_code: "200",
412 error_reason: null,
413 matched_rule_priority: "1",
414 received_bytes: 0,
415 redirect_url: null,
416 request_creation_time: "2018-07-02T22:22:48.364000Z",
417 request_method: "GET",
418 request_processing_time: 0.086,
419 request_protocol: "HTTP/1.1",
420 request_url: "https://www.example.com:443/",
421 response_processing_time: 0.037,
422 sent_bytes: 57,
423 ssl_cipher: "ECDHE-RSA-AES128-GCM-SHA256",
424 ssl_protocol: "TLSv1.2",
425 target_group_arn: "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067",
426 target_host: "10.0.0.1:80",
427 target_port_list: ["10.0.0.1:80"],
428 target_processing_time: 0.048,
429 target_status_code: "200",
430 target_status_code_list: ["200"],
431 timestamp: "2018-07-02T22:23:00.186641Z",
432 trace_id: "Root=1-58337281-1d84f3d73c47ec4e58577259",
433 type: "https",
434 user_agent: "curl/7.46.0",
435 traceability_id: "TID_dc57cebed65b444ebc8177bb698fe166"})),
436 tdef: TypeDef::object(inner_kind()).fallible(),
437 }
438
439 three {
440 args: func_args![value: r#"h2 2018-07-02T22:23:00.186641Z app/my-loadbalancer/50dc6c495c0c9188 10.0.1.252:48160 10.0.0.66:9000 0.000 0.002 0.000 200 200 5 257 "GET https://10.0.2.105:773/ HTTP/2.0" "curl/7.46.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 "Root=1-58337327-72bd00b0343d75b906739c42" "-" "-" 1 2018-07-02T22:22:48.364000Z "redirect" "https://example.com:80/" "-" 10.0.0.66:9000 200 "-" "-" TID_dc57cebed65b444ebc8177bb698fe166"#],
441 want: Ok(value! ({actions_executed: "redirect",
442 chosen_cert_arn: null,
443 classification: null,
444 classification_reason: null,
445 client_host: "10.0.1.252:48160",
446 domain_name: null,
447 elb: "app/my-loadbalancer/50dc6c495c0c9188",
448 elb_status_code: "200",
449 error_reason: null,
450 matched_rule_priority: "1",
451 received_bytes: 5,
452 redirect_url: "https://example.com:80/",
453 request_creation_time: "2018-07-02T22:22:48.364000Z",
454 request_method: "GET",
455 request_processing_time: 0.0,
456 request_protocol: "HTTP/2.0",
457 request_url: "https://10.0.2.105:773/",
458 response_processing_time: 0.0,
459 sent_bytes: 257,
460 ssl_cipher: "ECDHE-RSA-AES128-GCM-SHA256",
461 ssl_protocol: "TLSv1.2",
462 target_group_arn: "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067",
463 target_host: "10.0.0.66:9000",
464 target_port_list: ["10.0.0.66:9000"],
465 target_processing_time: 0.002,
466 target_status_code: "200",
467 target_status_code_list: ["200"],
468 timestamp: "2018-07-02T22:23:00.186641Z",
469 trace_id: "Root=1-58337327-72bd00b0343d75b906739c42",
470 type: "h2",
471 user_agent: "curl/7.46.0",
472 traceability_id: "TID_dc57cebed65b444ebc8177bb698fe166"})),
473 tdef: TypeDef::object(inner_kind()).fallible(),
474 }
475
476 four {
477 args: func_args![value: r#"ws 2018-07-02T22:23:00.186641Z app/my-loadbalancer/50dc6c495c0c9188 10.0.0.140:40914 10.0.1.192:8010 0.001 0.003 0.000 101 101 218 587 "GET http://10.0.0.30:80/ HTTP/1.1" "-" - - arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 "Root=1-58337364-23a8c76965a2ef7629b185e3" "-" "-" 1 2018-07-02T22:22:48.364000Z "forward" "-" "-" 10.0.1.192:8010 101 "-" "-" TID_dc57cebed65b444ebc8177bb698fe166"#],
478 want: Ok(value!({actions_executed: "forward",
479 chosen_cert_arn: null,
480 classification: null,
481 classification_reason: null,
482 client_host: "10.0.0.140:40914",
483 domain_name: null,
484 elb: "app/my-loadbalancer/50dc6c495c0c9188",
485 elb_status_code: "101",
486 error_reason: null,
487 matched_rule_priority: "1",
488 received_bytes: 218,
489 redirect_url: null,
490 request_creation_time: "2018-07-02T22:22:48.364000Z",
491 request_method: "GET",
492 request_processing_time: 0.001,
493 request_protocol: "HTTP/1.1",
494 request_url: "http://10.0.0.30:80/",
495 response_processing_time: 0.0,
496 sent_bytes: 587,
497 ssl_cipher: null,
498 ssl_protocol: null,
499 target_group_arn: "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067",
500 target_host: "10.0.1.192:8010",
501 target_port_list: ["10.0.1.192:8010"],
502 target_processing_time: 0.003,
503 target_status_code: "101",
504 target_status_code_list: ["101"],
505 timestamp: "2018-07-02T22:23:00.186641Z",
506 trace_id: "Root=1-58337364-23a8c76965a2ef7629b185e3",
507 type: "ws",
508 user_agent: null,
509 traceability_id: "TID_dc57cebed65b444ebc8177bb698fe166"})),
510 tdef: TypeDef::object(inner_kind()).fallible(),
511 }
512
513 five {
514 args: func_args![value: r#"wss 2018-07-02T22:23:00.186641Z app/my-loadbalancer/50dc6c495c0c9188 10.0.0.140:44244 10.0.0.171:8010 0.000 0.001 0.000 101 101 218 786 "GET https://10.0.0.30:443/ HTTP/1.1" "-" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 "Root=1-58337364-23a8c76965a2ef7629b185e3" "-" "-" 1 2018-07-02T22:22:48.364000Z "forward" "-" "-" 10.0.0.171:8010 101 "-" "-" TID_dc57cebed65b444ebc8177bb698fe166"#],
515 want: Ok(value! ({actions_executed: "forward",
516 chosen_cert_arn: null,
517 classification: null,
518 classification_reason: null,
519 client_host: "10.0.0.140:44244",
520 domain_name: null,
521 elb: "app/my-loadbalancer/50dc6c495c0c9188",
522 elb_status_code: "101",
523 error_reason: null,
524 matched_rule_priority: "1",
525 received_bytes: 218,
526 redirect_url: null,
527 request_creation_time: "2018-07-02T22:22:48.364000Z",
528 request_method: "GET",
529 request_processing_time: 0.0,
530 request_protocol: "HTTP/1.1",
531 request_url: "https://10.0.0.30:443/",
532 response_processing_time: 0.0,
533 sent_bytes: 786,
534 ssl_cipher: "ECDHE-RSA-AES128-GCM-SHA256",
535 ssl_protocol: "TLSv1.2",
536 target_group_arn: "arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067",
537 target_host: "10.0.0.171:8010",
538 target_port_list: ["10.0.0.171:8010"],
539 target_processing_time: 0.001,
540 target_status_code: "101",
541 target_status_code_list: ["101"],
542 timestamp: "2018-07-02T22:23:00.186641Z",
543 trace_id: "Root=1-58337364-23a8c76965a2ef7629b185e3",
544 type: "wss",
545 user_agent: null,
546 traceability_id: "TID_dc57cebed65b444ebc8177bb698fe166"})),
547 tdef: TypeDef::object(inner_kind()).fallible(),
548 }
549
550 six {
551 args: func_args![value: r#"http 2018-11-30T22:23:00.186641Z app/my-loadbalancer/50dc6c495c0c9188 192.168.131.39:2817 - 0.000 0.001 0.000 200 200 34 366 "GET http://www.example.com:80/ HTTP/1.1" "curl/7.46.0" - - arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 "Root=1-58337364-23a8c76965a2ef7629b185e3" "-" "-" 0 2018-11-30T22:22:48.364000Z "forward" "-" "-" "-" "-" "-" "-" TID_dc57cebed65b444ebc8177bb698fe166"#],
552 want: Ok(value! ({actions_executed: "forward",
553 chosen_cert_arn: null,
554 classification: null,
555 classification_reason: null,
556 client_host: "192.168.131.39:2817",
557 domain_name: null,
558 elb: "app/my-loadbalancer/50dc6c495c0c9188",
559 elb_status_code: "200",
560 error_reason: null,
561 matched_rule_priority: "0",
562 received_bytes: 34,
563 redirect_url: null,
564 request_creation_time: "2018-11-30T22:22:48.364000Z",
565 request_method: "GET",
566 request_processing_time: 0.0,
567 request_protocol: "HTTP/1.1",
568 request_url: "http://www.example.com:80/",
569 response_processing_time: 0.0,
570 sent_bytes: 366,
571 ssl_cipher: null,
572 ssl_protocol: null,
573 target_group_arn: "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067",
574 target_host: null,
575 target_port_list: [],
576 target_processing_time: 0.001,
577 target_status_code: "200",
578 target_status_code_list: [],
579 timestamp: "2018-11-30T22:23:00.186641Z",
580 trace_id: "Root=1-58337364-23a8c76965a2ef7629b185e3",
581 type: "http",
582 user_agent: "curl/7.46.0",
583 traceability_id: "TID_dc57cebed65b444ebc8177bb698fe166"})),
584 tdef: TypeDef::object(inner_kind()).fallible(),
585 }
586
587 seven {
588 args: func_args![value: r#"http 2018-11-30T22:23:00.186641Z app/my-loadbalancer/50dc6c495c0c9188 192.168.131.39:2817 - 0.000 0.001 0.000 502 - 34 366 "GET http://www.example.com:80/ HTTP/1.1" "curl/7.46.0" - - arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 "Root=1-58337364-23a8c76965a2ef7629b185e3" "-" "-" 0 2018-11-30T22:22:48.364000Z "forward" "-" "LambdaInvalidResponse" "-" "-" "-" "-" TID_dc57cebed65b444ebc8177bb698fe166"#],
589 want: Ok(value!({actions_executed: "forward",
590 chosen_cert_arn: null,
591 classification: null,
592 classification_reason: null,
593 client_host: "192.168.131.39:2817",
594 domain_name: null,
595 elb: "app/my-loadbalancer/50dc6c495c0c9188",
596 elb_status_code: "502",
597 error_reason: "LambdaInvalidResponse",
598 matched_rule_priority: "0",
599 received_bytes: 34,
600 redirect_url: null,
601 request_creation_time: "2018-11-30T22:22:48.364000Z",
602 request_method: "GET",
603 request_processing_time: 0.0,
604 request_protocol: "HTTP/1.1",
605 request_url: "http://www.example.com:80/",
606 response_processing_time: 0.0,
607 sent_bytes: 366,
608 ssl_cipher: null,
609 ssl_protocol: null,
610 target_group_arn: "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067",
611 target_host: null,
612 target_port_list: [],
613 target_processing_time: 0.001,
614 target_status_code: null,
615 target_status_code_list: [],
616 timestamp: "2018-11-30T22:23:00.186641Z",
617 trace_id: "Root=1-58337364-23a8c76965a2ef7629b185e3",
618 type: "http",
619 user_agent: "curl/7.46.0",
620 traceability_id: "TID_dc57cebed65b444ebc8177bb698fe166"})),
621 tdef: TypeDef::object(inner_kind()).fallible(),
622 }
623
624 eight {
625 args: func_args![value: r#"https 2021-03-16T20:20:00.135052Z app/awseb-AWSEB-1MVD8OW91UMOH/a32a5528b8fdaa6b 10.209.14.140:50599 10.119.5.47:80 0.001 0.052 0.000 200 200 589 2084 "POST https://test.domain.com:443/api/deposits/transactions:search?detailsLevel=FULL&offset=0&limit=50 HTTP/1.1" "User 1.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 arn:aws:elasticloadbalancing:us-east-1:755269215481:targetgroup/awseb-AWSEB-91MZX0WA1A0F/5a03cc723870f039 "Root=1-605112f0-31f367be4fd3da651daa4157" "some.domain.com" "arn:aws:acm:us-east-1:765229915481:certificate/d8450a8a-b4f6-4714-8535-17c625c36899" 0 2021-03-16T20:20:00.081000Z "waf,forward" "-" "-" "10.229.5.47:80" "200" "-" "-" TID_dc57cebed65b444ebc8177bb698fe166"#],
626 want: Ok(value!({type: "https",
627 timestamp: "2021-03-16T20:20:00.135052Z",
628 elb: "app/awseb-AWSEB-1MVD8OW91UMOH/a32a5528b8fdaa6b",
629 client_host: "10.209.14.140:50599",
630 target_host: "10.119.5.47:80",
631 request_processing_time: 0.001,
632 target_processing_time: 0.052,
633 response_processing_time: 0.0,
634 elb_status_code: "200",
635 target_status_code: "200",
636 received_bytes: 589,
637 sent_bytes: 2084,
638 request_method: "POST",
639 request_url: "https://test.domain.com:443/api/deposits/transactions:search?detailsLevel=FULL&offset=0&limit=50",
640 request_protocol: "HTTP/1.1",
641 user_agent: "User 1.0",
642 ssl_cipher: "ECDHE-RSA-AES128-GCM-SHA256",
643 ssl_protocol: "TLSv1.2",
644 target_group_arn: "arn:aws:elasticloadbalancing:us-east-1:755269215481:targetgroup/awseb-AWSEB-91MZX0WA1A0F/5a03cc723870f039",
645 trace_id: "Root=1-605112f0-31f367be4fd3da651daa4157",
646 domain_name: "some.domain.com",
647 chosen_cert_arn: "arn:aws:acm:us-east-1:765229915481:certificate/d8450a8a-b4f6-4714-8535-17c625c36899",
648 matched_rule_priority: "0",
649 request_creation_time: "2021-03-16T20:20:00.081000Z",
650 actions_executed: "waf,forward",
651 redirect_url: null,
652 error_reason: null,
653 target_port_list: ["10.229.5.47:80"],
654 target_status_code_list: ["200"],
655 classification: null,
656 classification_reason: null,
657 traceability_id: "TID_dc57cebed65b444ebc8177bb698fe166"})),
658 tdef: TypeDef::object(inner_kind()).fallible(),
659 }
660
661 nine {
662 args: func_args![value: r#"http 2021-03-17T18:54:14.216357Z app/awseb-AWSEB-1KGU6EBAG3FAD/7f0dc2b05788640f 113.241.19.90:15070 - -1 -1 -1 400 - 0 272 "- http://awseb-awseb-1kgu6fbag3fad-640112591.us-east-1.elb.amazonaws.com:80- -" "-" - - - "-" "-" "-" - 2021-03-17T18:54:13.967000Z "-" "-" "-" "-" "-" "-" "-" TID_dc57cebed65b444ebc8177bb698fe166"#],
663 want: Ok(value!({type: "http",
664 timestamp: "2021-03-17T18:54:14.216357Z",
665 elb: "app/awseb-AWSEB-1KGU6EBAG3FAD/7f0dc2b05788640f",
666 client_host: "113.241.19.90:15070",
667 target_host: null,
668 request_processing_time: (-1.0),
669 target_processing_time: (-1.0),
670 response_processing_time: (-1.0),
671 elb_status_code: "400",
672 target_status_code: null,
673 received_bytes: 0,
674 sent_bytes: 272,
675 request_method: null,
676 request_url: "http://awseb-awseb-1kgu6fbag3fad-640112591.us-east-1.elb.amazonaws.com:80-",
677 request_protocol: null,
678 user_agent: null,
679 ssl_cipher: null,
680 ssl_protocol: null,
681 target_group_arn: null,
682 trace_id: null,
683 domain_name: null,
684 chosen_cert_arn: null,
685 matched_rule_priority: null,
686 request_creation_time: "2021-03-17T18:54:13.967000Z",
687 actions_executed: null,
688 redirect_url: null,
689 error_reason: null,
690 target_port_list: [],
691 target_status_code_list: [],
692 classification: null,
693 classification_reason: null,
694 traceability_id: "TID_dc57cebed65b444ebc8177bb698fe166"})),
695 tdef: TypeDef::object(inner_kind()).fallible(),
696 }
697
698 ten {
699 args: func_args![value: r#"http 2021-03-18T04:00:26.920977Z app/awseb-AWSEB-1KGU6EBAG3FAD/7f0dc2b05788640f 31.211.20.175:57720 - -1 -1 -1 400 - 191 272 "POST http://awseb-awseb-1kgu6fbag3fad-640112591.us-east-1.elb.amazonaws.com:80/cgi-bin/login.cgi HTTP/1.1" "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0" - - - "-" "-" "-" - 2021-03-18T04:00:26.599000Z "-" "-" "-" "-" "-" "-" "-" TID_dc57cebed65b444ebc8177bb698fe166"#],
700 want: Ok(value!({type: "http",
701 timestamp: "2021-03-18T04:00:26.920977Z",
702 elb: "app/awseb-AWSEB-1KGU6EBAG3FAD/7f0dc2b05788640f",
703 client_host: "31.211.20.175:57720",
704 target_host: null,
705 request_processing_time: (-1.0),
706 target_processing_time: (-1.0),
707 response_processing_time: (-1.0),
708 elb_status_code: "400",
709 target_status_code: null,
710 received_bytes: 191,
711 sent_bytes: 272,
712 request_method: "POST",
713 request_url: "http://awseb-awseb-1kgu6fbag3fad-640112591.us-east-1.elb.amazonaws.com:80/cgi-bin/login.cgi",
714 request_protocol: "HTTP/1.1",
715 user_agent: "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0",
716 ssl_cipher: null,
717 ssl_protocol: null,
718 target_group_arn: null,
719 trace_id: null,
720 domain_name: null,
721 chosen_cert_arn: null,
722 matched_rule_priority: null,
723 request_creation_time: "2021-03-18T04:00:26.599000Z",
724 actions_executed: null,
725 redirect_url: null,
726 error_reason: null,
727 target_port_list: [],
728 target_status_code_list: [],
729 classification: null,
730 classification_reason: null,
731 traceability_id: "TID_dc57cebed65b444ebc8177bb698fe166"})),
732 tdef: TypeDef::object(inner_kind()).fallible(),
733 }
734
735 eleven {
736 args: func_args![value: r#"https 2021-03-16T20:20:00.135052Z app/awseb-AWSEB-1MVD8OW91UMOH/a32a5528b8fdaa6b 2601:6bbc:c529:9dad:6bbc:c529:9dad:6bbc:50599 fd6d:6bbc:c529:6::face:ed83:f46:80 0.001 0.052 0.000 200 200 589 2084 "POST https://test.domain.com:443/api/deposits/transactions:search?detailsLevel=FULL&offset=0&limit=50 HTTP/1.1" "User 1.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 arn:aws:elasticloadbalancing:us-east-1:755269215481:targetgroup/awseb-AWSEB-91MZX0WA1A0F/5a03cc723870f039 "Root=1-605112f0-31f367be4fd3da651daa4157" "some.domain.com" "arn:aws:acm:us-east-1:765229915481:certificate/d8450a8a-b4f6-4714-8535-17c625c36899" 0 2021-03-16T20:20:00.081000Z "waf,forward" "-" "-" "fd6d:6bbc:c529:27ff:b::dead:ed84:80" "200" "-" "-" TID_dc57cebed65b444ebc8177bb698fe166"#],
737 want: Ok(value!({type: "https",
738 timestamp: "2021-03-16T20:20:00.135052Z",
739 elb: "app/awseb-AWSEB-1MVD8OW91UMOH/a32a5528b8fdaa6b",
740 client_host: "2601:6bbc:c529:9dad:6bbc:c529:9dad:6bbc:50599",
741 target_host: "fd6d:6bbc:c529:6::face:ed83:f46:80",
742 request_processing_time: 0.001,
743 target_processing_time: 0.052,
744 response_processing_time: 0.0,
745 elb_status_code: "200",
746 target_status_code: "200",
747 received_bytes: 589,
748 sent_bytes: 2084,
749 request_method: "POST",
750 request_url: "https://test.domain.com:443/api/deposits/transactions:search?detailsLevel=FULL&offset=0&limit=50",
751 request_protocol: "HTTP/1.1",
752 user_agent: "User 1.0",
753 ssl_cipher: "ECDHE-RSA-AES128-GCM-SHA256",
754 ssl_protocol: "TLSv1.2",
755 target_group_arn: "arn:aws:elasticloadbalancing:us-east-1:755269215481:targetgroup/awseb-AWSEB-91MZX0WA1A0F/5a03cc723870f039",
756 trace_id: "Root=1-605112f0-31f367be4fd3da651daa4157",
757 domain_name: "some.domain.com",
758 chosen_cert_arn: "arn:aws:acm:us-east-1:765229915481:certificate/d8450a8a-b4f6-4714-8535-17c625c36899",
759 matched_rule_priority: "0",
760 request_creation_time: "2021-03-16T20:20:00.081000Z",
761 actions_executed: "waf,forward",
762 redirect_url: null,
763 error_reason: null,
764 target_port_list: ["fd6d:6bbc:c529:27ff:b::dead:ed84:80"],
765 target_status_code_list: ["200"],
766 classification: null,
767 classification_reason: null,
768 traceability_id: "TID_dc57cebed65b444ebc8177bb698fe166"})),
769 tdef: TypeDef::object(inner_kind()).fallible(),
770 }
771 twelve {
772 args: func_args![value: r#"https 2021-03-16T20:20:00.135052Z app/awseb-AWSEB-1MVD8OW91UMOH/a32a5528b8fdaa6b 2601:6bbc:c529:9dad:6bbc:c529:9dad:6bbc:50599 fd6d:6bbc:c529:6::face:ed83:f46:80 0.001 0.052 0.000 200 200 589 2084 "POST https://test.domain.com:443/api/deposits/transactions:search?detailsLevel=FULL&offset=0&limit=50 HTTP/1.1" "User 1.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 arn:aws:elasticloadbalancing:us-east-1:755269215481:targetgroup/awseb-AWSEB-91MZX0WA1A0F/5a03cc723870f039 "Root=1-605112f0-31f367be4fd3da651daa4157" "some.domain.com" "arn:aws:acm:us-east-1:765229915481:certificate/d8450a8a-b4f6-4714-8535-17c625c36899" 0 2021-03-16T20:20:00.081000Z "waf,forward" "-" "-" "fd6d:6bbc:c529:27ff:b::dead:ed84:80" "200" "-" "-""#],
773 want: Ok(value!({type: "https",
774 timestamp: "2021-03-16T20:20:00.135052Z",
775 elb: "app/awseb-AWSEB-1MVD8OW91UMOH/a32a5528b8fdaa6b",
776 client_host: "2601:6bbc:c529:9dad:6bbc:c529:9dad:6bbc:50599",
777 target_host: "fd6d:6bbc:c529:6::face:ed83:f46:80",
778 request_processing_time: 0.001,
779 target_processing_time: 0.052,
780 response_processing_time: 0.0,
781 elb_status_code: "200",
782 target_status_code: "200",
783 received_bytes: 589,
784 sent_bytes: 2084,
785 request_method: "POST",
786 request_url: "https://test.domain.com:443/api/deposits/transactions:search?detailsLevel=FULL&offset=0&limit=50",
787 request_protocol: "HTTP/1.1",
788 user_agent: "User 1.0",
789 ssl_cipher: "ECDHE-RSA-AES128-GCM-SHA256",
790 ssl_protocol: "TLSv1.2",
791 target_group_arn: "arn:aws:elasticloadbalancing:us-east-1:755269215481:targetgroup/awseb-AWSEB-91MZX0WA1A0F/5a03cc723870f039",
792 trace_id: "Root=1-605112f0-31f367be4fd3da651daa4157",
793 domain_name: "some.domain.com",
794 chosen_cert_arn: "arn:aws:acm:us-east-1:765229915481:certificate/d8450a8a-b4f6-4714-8535-17c625c36899",
795 matched_rule_priority: "0",
796 request_creation_time: "2021-03-16T20:20:00.081000Z",
797 actions_executed: "waf,forward",
798 redirect_url: null,
799 error_reason: null,
800 target_port_list: ["fd6d:6bbc:c529:27ff:b::dead:ed84:80"],
801 target_status_code_list: ["200"],
802 classification: null,
803 classification_reason: null,
804 traceability_id: null})),
805 tdef: TypeDef::object(inner_kind()).fallible(),
806 }
807 thirteen {
808 args: func_args![value: r#"http 2018-07-02T22:23:00.186641Z app/my-loadbalancer/50dc6c495c0c9188 192.168.131.39:2817 10.0.0.1:80 0.000 0.001 0.000 200 200 34 366 "GET http://www.example.com:80/ HTTP/1.1" "curl/7.46.0" - - arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 "Root=1-58337262-36d228ad5d99923122bbe354" "-" "-" 0 2018-07-02T22:22:48.364000Z "forward" "-" "-" 10.0.0.1:80 200 "-" "-" TID_dc57cebed65b444ebc8177bb698fe166 "-" "-" "-""#, strict_mode: false],
809 want: Ok(value!({actions_executed: "forward",
810 chosen_cert_arn: null,
811 classification: null,
812 classification_reason: null,
813 client_host: "192.168.131.39:2817",
814 domain_name: null,
815 elb: "app/my-loadbalancer/50dc6c495c0c9188",
816 elb_status_code: "200",
817 error_reason: null,
818 matched_rule_priority: "0",
819 received_bytes: 34,
820 redirect_url: null,
821 request_creation_time: "2018-07-02T22:22:48.364000Z",
822 request_method: "GET",
823 request_processing_time: 0.0,
824 request_protocol: "HTTP/1.1",
825 request_url: "http://www.example.com:80/",
826 response_processing_time: 0.0,
827 sent_bytes: 366,
828 ssl_cipher: null,
829 ssl_protocol: null,
830 target_group_arn: "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067",
831 target_host: "10.0.0.1:80",
832 target_port_list: ["10.0.0.1:80"],
833 target_processing_time: 0.001,
834 target_status_code: "200",
835 target_status_code_list: ["200"],
836 timestamp: "2018-07-02T22:23:00.186641Z",
837 trace_id: "Root=1-58337262-36d228ad5d99923122bbe354",
838 type: "http",
839 user_agent: "curl/7.46.0",
840 traceability_id: "TID_dc57cebed65b444ebc8177bb698fe166"
841 })),
842 tdef: TypeDef::object(inner_kind()).fallible(),
843 }
844 ];
845}