Skip to content

Commit 0b0c37c

Browse files
rejaoRegis Oliveira
andauthored
Migrate from chrono to time (#68)
* Migrate from chrono to time * Migrate from chrono to time * Migrate from chrono to time Co-authored-by: Regis Oliveira <olivregi@amazon.com>
1 parent b9990f0 commit 0b0c37c

18 files changed

+276
-165
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Changelog
2+
3+
All notable changes to the time project will be documented in this file.
4+
---
5+
6+
7+
8+
<a name="0.3.0"></a>
9+
### 0.3.0 (2022-03-14)
10+
11+
#### Breaking Changes
12+
13+
* Migrate from chrono to [time](https://docs.rs/time/latest/time/)
14+
* String formatting changed from strftime to [time](https://docs.rs/time/latest/time/format_description/index.html) custom formatting

Cargo.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
edition = "2018"
33
name = "flowgger"
4-
version = "0.2.14"
4+
version = "0.3.0"
55
authors = ["Frank Denis <github@pureftpd.org>", "Matteo Bigoi <bigo@crisidev.org>", "Vivien Chene <viv.chene@gmail.com>", "Francesco Berni <kurojishi@kurojishi.me>"]
66
build = "build.rs"
77
repository = "https://github.com/awslabs/flowgger"
@@ -38,8 +38,6 @@ optional = true
3838

3939
[dependencies]
4040
capnp = { version = "0.14", optional = true }
41-
chrono = "0.4"
42-
chrono-tz = "0.5"
4341
clap = "3"
4442
flate2 = "1"
4543
glob = { version = "0.3", optional = true }
@@ -53,7 +51,8 @@ serde = { version = "1", optional = true }
5351
serde_json = { version = "~0.8", optional = true }
5452
may = { version = "~0.3", optional = true }
5553
toml = "0.5"
56-
time = "0.3"
54+
time = { version = "0.3", features = ["parsing", "formatting"] }
55+
time-tz = "0.3"
5756

5857
[dev-dependencies]
5958
tempdir = "0.3"

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@
44

55
[![Build Status](https://app.travis-ci.com/awslabs/flowgger.svg?branch=master)](https://app.travis-ci.com/awslabs/flowgger) [![License: BSD2](https://img.shields.io/badge/License-BSD2-brightgreen.svg)](https://github.com/awslabs/flowgger/blob/master/LICENSE)
66

7+
<a name="0.3.0"></a>
8+
### New major version: 0.3.0 (2022-03-14)
9+
10+
#### Breaking Changes
11+
12+
* Migrate from chrono to [time](https://docs.rs/time/latest/time/) as per https://rustsec.org/advisories/RUSTSEC-2020-0071
13+
* String formatting changed from strftime to [time](https://docs.rs/time/latest/time/format_description/index.html) custom formatting - see ```flowgger.toml``` for examples on change
14+
15+
---
16+
717
Flowgger is a fast, simple and lightweight data collector written in Rust.
818

919
It reads log entries over a given protocol, extracts them, decodes them using a

flowgger.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,9 @@ file_rotation_size = 2048
9393
file_rotation_time = 2
9494

9595
# Optional: When time rotation is enabled, the timestamp format is appended to the filenames.
96-
# Default is set to "%Y%m%dT%H%M%SZ". Format must conform to https://docs.rs/chrono/0.3.1/chrono/format/strftime/index.html
97-
file_rotation_timeformat = "%Y%m%dT%H%M%SZ"
96+
# Default is set to "[year][month][day]T[hour][minute][second]Z".
97+
# Format must conform to https://docs.rs/time/0.3.7/time/format_description/index.html
98+
file_rotation_timeformat = "[year][month][day]T[hour][minute][second]Z"
9899

99100
# Optional, only used if either file_rotation_size or file_rotation_time is set:
100101
# Specifies number of rotation files to use. The default value is 50.
@@ -158,4 +159,4 @@ framing = "line"
158159
# "rfc3164" or "rfc5424" or "passthrough"
159160
format = "rfc3164"
160161
# Format of the optional timestamp to be prepended to each event
161-
syslog_prepend_timestamp="[%Y-%m-%dT%H:%M:%S%.6fZ]"
162+
syslog_prepend_timestamp="[[[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]Z]"

src/flowgger/decoder/ltsv_decoder.rs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use super::Decoder;
22
use crate::flowgger::config::Config;
33
use crate::flowgger::record::{Record, SDValue, SDValueType, StructuredData};
44
use crate::flowgger::utils;
5-
use chrono::DateTime;
65
use std::collections::HashMap;
6+
use time::format_description::well_known::Rfc3339;
7+
use time::{format_description, OffsetDateTime};
78

89
#[derive(Clone)]
910
struct Suffixes {
@@ -221,23 +222,41 @@ impl Decoder for LTSVDecoder {
221222
}
222223

223224
fn rfc3339_to_unix(rfc3339: &str) -> Result<f64, &'static str> {
224-
match DateTime::parse_from_rfc3339(rfc3339) {
225-
Ok(date) => Ok(utils::PreciseTimestamp::from_datetime(date).as_f64()),
226-
Err(_) => Err("Unable to parse the date"),
225+
match OffsetDateTime::parse(rfc3339, &Rfc3339) {
226+
Ok(date) => Ok(utils::PreciseTimestamp::from_offset_datetime(date).as_f64()),
227+
Err(_) => Err("Unable to parse the date from RFC3339 to Unix in LTSV decoder"),
227228
}
228229
}
229230

230231
fn english_time_to_unix(et: &str) -> Result<f64, &'static str> {
231-
match DateTime::parse_from_str(et, "%e/%b/%Y:%H:%M:%S%.f %z") {
232-
Ok(date) => Ok(utils::PreciseTimestamp::from_datetime(date).as_f64()),
233-
Err(_) => Err("Unable to parse the date"),
232+
english_time_to_unix_with_subsecond(et, false)
233+
.or_else(|_| english_time_to_unix_with_subsecond(et, true))
234+
}
235+
236+
fn english_time_to_unix_with_subsecond(
237+
et: &str,
238+
with_subsecond: bool,
239+
) -> Result<f64, &'static str> {
240+
let mut format_str =
241+
"[day padding:none]/[month repr:short]/[year]:[hour]:[minute]:[second].[subsecond] \
242+
[offset_hour sign:mandatory][offset_minute]"
243+
.to_string();
244+
245+
if !with_subsecond {
246+
format_str = format_str.replace(".[subsecond]", "");
247+
}
248+
249+
let format_item = format_description::parse(&format_str).unwrap();
250+
match OffsetDateTime::parse(&et, &format_item) {
251+
Ok(date) => Ok(utils::PreciseTimestamp::from_offset_datetime(date).as_f64()),
252+
Err(_) => Err("Unable to parse the English to Unix timestamp in LTSV decoder"),
234253
}
235254
}
236255

237256
fn unix_strtime_to_unix(et: &str) -> Result<f64, &'static str> {
238257
match et.parse::<f64>() {
239258
Ok(ts) => Ok(ts),
240-
Err(_) => Err("Unable to parse the date"),
259+
Err(_) => Err("Unable to parse the date from Unix strtime to Unix in LTSV decoder"),
241260
}
242261
}
243262

@@ -451,3 +470,18 @@ fn test_ltsv_3() {
451470
false
452471
}));
453472
}
473+
474+
#[test]
475+
fn test_ltsv4() {
476+
let config = Config::from_string(
477+
"[input]\n[input.ltsv_schema]\ncounter = \"u64\"\nscore = \
478+
\"i64\"\nmean = \"f64\"\ndone = \"bool\"\n",
479+
);
480+
let ltsv_decoder = LTSVDecoder::new(&config.unwrap());
481+
let msg =
482+
"time:[5/Aug/2015:15:53:45.637824 -0000]\thost:testhostname\tname1:value1\tname 2: value \
483+
2\tn3:v3";
484+
let res = ltsv_decoder.decode(msg).unwrap();
485+
println!("{}", res.ts);
486+
assert!(res.ts == 1_438_790_025.637_824);
487+
}

src/flowgger/decoder/rfc3164_decoder.rs

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ use super::Decoder;
22
use crate::flowgger::config::Config;
33
use crate::flowgger::record::Record;
44
use crate::flowgger::utils;
5-
use chrono::{Datelike, NaiveDateTime, TimeZone, Utc};
6-
use chrono_tz::Tz;
75
use std::io::{stderr, Write};
6+
use time::{format_description, OffsetDateTime, PrimitiveDateTime};
7+
use time_tz::timezones::get_by_name;
8+
use time_tz::PrimitiveDateTimeExt;
89

910
#[derive(Clone)]
1011
pub struct RFC3164Decoder {}
@@ -169,49 +170,60 @@ fn parse_date<'a>(
169170
// If no year in the string, parse manually add the current year
170171
if has_year {
171172
idx = 4;
172-
ts_str = ts_tokens[0..idx].join(" ");
173+
ts_str = match ts_tokens.get(0..idx) {
174+
Some(str) => str.join(" "),
175+
None => return Err("Unable to parse RFC3164 date with year"),
176+
};
173177
} else {
174178
idx = 3;
175-
let current_year = Utc::now().year();
176-
ts_str = format!("{} {}", current_year, ts_tokens[0..idx].join(" "));
179+
let current_year = OffsetDateTime::now_utc().year();
180+
ts_str = match ts_tokens.get(0..idx) {
181+
Some(str) => format!("{} {}", current_year, str.join(" ")),
182+
None => return Err("Unable to parse RFC3164 date without year"),
183+
};
177184
}
178185

179-
match NaiveDateTime::parse_from_str(&ts_str, "%Y %b %d %H:%M:%S") {
180-
Ok(naive_dt) => {
186+
let format_item = format_description::parse(
187+
"[year] [month repr:short] [day padding:none] [hour]:[minute]:[second]",
188+
)
189+
.unwrap();
190+
match PrimitiveDateTime::parse(&ts_str, &format_item) {
191+
Ok(primitive_date) => {
181192
// See if the next token is a timezone
182-
let mut ts = 0.0;
183-
let tz_res: Result<Tz, String> = if ts_tokens.len() > idx {
184-
ts_tokens[idx].parse()
193+
let ts: f64;
194+
let tz_res = if ts_tokens.len() > idx {
195+
get_by_name(ts_tokens[idx]).ok_or("No timezone".to_string())
185196
} else {
186197
Err("No timezone".to_string())
187198
};
199+
188200
if let Ok(tz) = tz_res {
189-
let dt = tz.from_local_datetime(&naive_dt).single();
190-
if dt.is_some() {
191-
ts = utils::PreciseTimestamp::from_datetime_tz(dt.unwrap()).as_f64();
192-
idx += 1;
193-
}
201+
let dt = primitive_date.assume_timezone(tz);
202+
ts = utils::PreciseTimestamp::from_offset_datetime(dt).as_f64();
203+
idx += 1;
194204
}
195205
// No timezome, give a timestamp without tz
196206
else {
197-
ts = utils::PreciseTimestamp::from_naive_datetime(naive_dt).as_f64();
207+
ts = utils::PreciseTimestamp::from_primitive_datetime(primitive_date).as_f64();
198208
}
199209
Ok((ts, ts_tokens[idx..].to_vec()))
200210
}
201-
Err(_err) => Err("Unable to parse date"),
211+
Err(_) => Err("Unable to parse the date in RFC3164 decoder"),
202212
}
203213
}
204214

205215
#[cfg(test)]
206216
use crate::flowgger::utils::test_utils::rfc_test_utils::{
207217
ts_from_date_time, ts_from_partial_date_time,
208218
};
219+
#[cfg(test)]
220+
use time::Month;
209221

210222
#[test]
211223
fn test_rfc3164_decode_nopri() {
212224
let msg = r#"Aug 6 11:15:24 testhostname appname 69 42 [origin@123 software="te\st sc\"ript" swVersion="0.0.1"] test message"#;
213225
let cfg = Config::from_string("[input]\n[input.ltsv_schema]\nformat = \"rfc3164\"\n").unwrap();
214-
let expected_ts = ts_from_partial_date_time(8, 6, 11, 15, 24);
226+
let expected_ts = ts_from_partial_date_time(Month::August, 6, 11, 15, 24);
215227

216228
let decoder = RFC3164Decoder::new(&cfg);
217229
let res = decoder.decode(msg).unwrap();
@@ -231,7 +243,7 @@ fn test_rfc3164_decode_nopri() {
231243
fn test_rfc3164_decode_with_pri() {
232244
let msg = r#"<13>Aug 6 11:15:24 testhostname appname 69 42 [origin@123 software="te\st sc\"ript" swVersion="0.0.1"] test message"#;
233245
let cfg = Config::from_string("[input]\n[input.ltsv_schema]\nformat = \"rfc3164\"\n").unwrap();
234-
let expected_ts = ts_from_partial_date_time(8, 6, 11, 15, 24);
246+
let expected_ts = ts_from_partial_date_time(Month::August, 6, 11, 15, 24);
235247

236248
let decoder = RFC3164Decoder::new(&cfg);
237249
let res = decoder.decode(msg).unwrap();
@@ -251,7 +263,7 @@ fn test_rfc3164_decode_with_pri() {
251263
fn test_rfc3164_decode_with_pri_year() {
252264
let msg = r#"<13>2020 Aug 6 11:15:24 testhostname appname 69 42 [origin@123 software="te\st sc\"ript" swVersion="0.0.1"] test message"#;
253265
let cfg = Config::from_string("[input]\n[input.ltsv_schema]\nformat = \"rfc3164\"\n").unwrap();
254-
let expected_ts = ts_from_date_time(2020, 8, 6, 11, 15, 24, 0);
266+
let expected_ts = ts_from_date_time(2020, Month::August, 6, 11, 15, 24, 0);
255267

256268
let decoder = RFC3164Decoder::new(&cfg);
257269
let res = decoder.decode(msg).unwrap();
@@ -269,9 +281,9 @@ fn test_rfc3164_decode_with_pri_year() {
269281

270282
#[test]
271283
fn test_rfc3164_decode_with_pri_year_tz() {
272-
let msg = r#"<13>2020 Aug 6 11:15:24 UTC testhostname appname 69 42 [origin@123 software="te\st sc\"ript" swVersion="0.0.1"] test message"#;
284+
let msg = r#"<13>2020 Aug 6 05:15:24 America/Sao_Paulo testhostname appname 69 42 [origin@123 software="te\st sc\"ript" swVersion="0.0.1"] test message"#;
273285
let cfg = Config::from_string("[input]\n[input.ltsv_schema]\nformat = \"rfc3164\"\n").unwrap();
274-
let expected_ts = ts_from_date_time(2020, 8, 6, 11, 15, 24, 0);
286+
let expected_ts = ts_from_date_time(2020, Month::August, 6, 08, 15, 24, 0);
275287

276288
let decoder = RFC3164Decoder::new(&cfg);
277289
let res = decoder.decode(msg).unwrap();
@@ -291,7 +303,7 @@ fn test_rfc3164_decode_with_pri_year_tz() {
291303
fn test_rfc3164_decode_tz_no_year() {
292304
let msg = r#"Aug 6 11:15:24 UTC testhostname appname 69 42 [origin@123 software="te\st sc\"ript" swVersion="0.0.1"] test message"#;
293305
let cfg = Config::from_string("[input]\n[input.ltsv_schema]\nformat = \"rfc3164\"\n").unwrap();
294-
let expected_ts = ts_from_partial_date_time(8, 6, 11, 15, 24);
306+
let expected_ts = ts_from_partial_date_time(Month::August, 6, 11, 15, 24);
295307

296308
let decoder = RFC3164Decoder::new(&cfg);
297309
let res = decoder.decode(msg).unwrap();
@@ -329,11 +341,9 @@ fn test_rfc3164_decode_invalid_date() {
329341

330342
#[test]
331343
fn test_rfc3164_decode_custom_with_year() {
332-
// let msg = r#"testhostname: 2019 Mar 27 12:09:39 UTC: appname: test message"#;
333344
let msg = r#"testhostname: 2020 Aug 6 11:15:24 UTC: appname 69 42 some test message"#;
334345
let cfg = Config::from_string("[input]\n[input.ltsv_schema]\nformat = \"rfc3164\"\n").unwrap();
335-
// let expected_ts = ts_from_date_time(2019, 3, 27, 12, 9, 39, 0);
336-
let expected_ts = ts_from_date_time(2020, 8, 6, 11, 15, 24, 0);
346+
let expected_ts = ts_from_date_time(2020, Month::August, 6, 11, 15, 24, 0);
337347

338348
let decoder = RFC3164Decoder::new(&cfg);
339349
let res = decoder.decode(msg).unwrap();
@@ -356,7 +366,7 @@ fn test_rfc3164_decode_custom_with_year() {
356366
fn test_rfc3164_decode_custom_with_year_notz() {
357367
let msg = r#"testhostname: 2019 Mar 27 12:09:39: appname: a test message"#;
358368
let cfg = Config::from_string("[input]\n[input.ltsv_schema]\nformat = \"rfc3164\"\n").unwrap();
359-
let expected_ts = ts_from_date_time(2019, 3, 27, 12, 9, 39, 0);
369+
let expected_ts = ts_from_date_time(2019, Month::March, 27, 12, 9, 39, 0);
360370

361371
let decoder = RFC3164Decoder::new(&cfg);
362372
let res = decoder.decode(msg).unwrap();
@@ -376,7 +386,7 @@ fn test_rfc3164_decode_custom_with_year_notz() {
376386
fn test_rfc3164_decode_custom_with_pri() {
377387
let msg = r#"<13>testhostname: 2019 Mar 27 12:09:39 UTC: appname: test message"#;
378388
let cfg = Config::from_string("[input]\n[input.ltsv_schema]\nformat = \"rfc3164\"\n").unwrap();
379-
let expected_ts = ts_from_date_time(2019, 3, 27, 12, 9, 39, 0);
389+
let expected_ts = ts_from_date_time(2019, Month::March, 27, 12, 9, 39, 0);
380390

381391
let decoder = RFC3164Decoder::new(&cfg);
382392
let res = decoder.decode(msg).unwrap();
@@ -396,7 +406,7 @@ fn test_rfc3164_decode_custom_with_pri() {
396406
fn test_rfc3164_decode_custom_trimed() {
397407
let msg = "<13>testhostname: 2019 Mar 27 12:09:39 UTC: appname: test message \n";
398408
let cfg = Config::from_string("[input]\n[input.ltsv_schema]\nformat = \"rfc3164\"\n").unwrap();
399-
let expected_ts = ts_from_date_time(2019, 3, 27, 12, 9, 39, 0);
409+
let expected_ts = ts_from_date_time(2019, Month::March, 27, 12, 9, 39, 0);
400410

401411
let decoder = RFC3164Decoder::new(&cfg);
402412
let res = decoder.decode(msg).unwrap();

src/flowgger/decoder/rfc5424_decoder.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use super::Decoder;
22
use crate::flowgger::config::Config;
33
use crate::flowgger::record::{Record, SDValue, StructuredData};
44
use crate::flowgger::utils;
5-
use chrono::DateTime;
5+
use time::format_description::well_known::Rfc3339;
6+
use time::OffsetDateTime;
67

78
#[derive(Clone)]
89
pub struct RFC5424Decoder;
@@ -91,9 +92,9 @@ fn parse_pri_version(line: &str) -> Result<Pri, &'static str> {
9192
}
9293

9394
fn rfc3339_to_unix(rfc3339: &str) -> Result<f64, &'static str> {
94-
match DateTime::parse_from_rfc3339(rfc3339) {
95-
Ok(date) => Ok(utils::PreciseTimestamp::from_datetime(date).as_f64()),
96-
Err(_) => Err("Unable to parse the date"),
95+
match OffsetDateTime::parse(rfc3339, &Rfc3339) {
96+
Ok(date) => Ok(utils::PreciseTimestamp::from_offset_datetime(date).as_f64()),
97+
Err(_) => Err("Unable to parse the date from RFC3339 to Unix time in RFC5424 decoder"),
9798
}
9899
}
99100

src/flowgger/encoder/ltsv_encoder.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,15 @@ impl Encoder for LTSVEncoder {
128128
use crate::flowgger::record::StructuredData;
129129
#[cfg(test)]
130130
use crate::flowgger::utils::test_utils::rfc_test_utils::ts_from_partial_date_time;
131+
#[cfg(test)]
132+
use time::Month;
131133

132134
#[test]
133135
fn test_ltsv_full_encode_no_sd() {
134136
let full_msg = "<23>Aug 6 11:15:24 testhostname appname[69]: 42 - some test message";
135137
let expected_msg = "host:testhostname\ttime:1659784524\tmessage:some test message\tfull_message:<23>Aug 6 11:15:24 testhostname appname[69]: 42 - some test message\tlevel:7\tfacility:2\tappname:appname\tprocid:69\tmsgid:42";
136138
let cfg = Config::from_string("[input]\n[input.ltsv_schema]\nformat = \"ltsv\"\n").unwrap();
137-
let ts = ts_from_partial_date_time(8, 6, 11, 15, 24);
139+
let ts = ts_from_partial_date_time(Month::August, 6, 11, 15, 24);
138140

139141
let record = Record {
140142
ts,
@@ -159,7 +161,7 @@ fn test_ltsv_full_encode_multiple_sd() {
159161
let full_msg = "<23>Aug 6 11:15:24 testhostname appname[69]: 42 [someid a=\"b\" c=\"123456\"][someid2 a2=\"b2\" c2=\"123456\"] some test message";
160162
let expected_msg = "a:b\tc:123456\ta2:b2\tc2:123456\thost:testhostname\ttime:1659784524\tmessage:some test message\tfull_message:<23>Aug 6 11:15:24 testhostname appname[69]: 42 [someid a=\"b\" c=\"123456\"][someid2 a2=\"b2\" c2=\"123456\"] some test message\tlevel:7\tfacility:2\tappname:appname\tprocid:69\tmsgid:42";
161163
let cfg = Config::from_string("[input]\n[input.ltsv_schema]\nformat = \"ltsv\"\n").unwrap();
162-
let ts = ts_from_partial_date_time(8, 6, 11, 15, 24);
164+
let ts = ts_from_partial_date_time(Month::August, 6, 11, 15, 24);
163165

164166
let record = Record {
165167
ts,

0 commit comments

Comments
 (0)