Skip to content

Commit dce8a70

Browse files
authored
Merge pull request #11 from cosmo0920/validate-arbitrary-digits-timestamp
Validate arbitrary digits timestamp
2 parents 86e4a68 + 3672f33 commit dce8a70

File tree

3 files changed

+48
-3
lines changed

3 files changed

+48
-3
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ elasticsearch.
3333
`subsecond_precision` controls the subsecond precision during the conversion.
3434
Default value is set to `3` (millisecond).
3535

36+
Other `subsecond_precision` sample values are:
37+
38+
* `6` (microsecond)
39+
* `9` (nanosecond)
40+
* `12` (picosecond)
41+
42+
and more high precision is also supported.
43+
3644
## Usage
3745

3846
```

lib/fluent/plugin/filter_elasticsearch_timestamp_check.rb

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
module Fluent::Plugin
44
class ElasticsearchTimestampCheckFilter < Filter
5+
attr_reader :timestamp_digits
6+
57
Fluent::Plugin.register_filter('elasticsearch_timestamp_check', self)
68

79
config_param :subsecond_precision, :integer, default: 3
@@ -11,6 +13,15 @@ def configure(conf)
1113
require 'date'
1214
raise Fluent::ConfigError, "specify 1 or bigger number." if subsecond_precision < 1
1315
@strftime_format = "%Y-%m-%dT%H:%M:%S.%#{@subsecond_precision}N%z".freeze
16+
@timestamp_digits = configure_digits
17+
end
18+
19+
def configure_digits
20+
subepoch_precision = 10 + @subsecond_precision
21+
timestamp_digits = [10, 13]
22+
timestamp_digits << subepoch_precision
23+
timestamp_digits.uniq!
24+
timestamp_digits
1425
end
1526

1627
def start
@@ -29,10 +40,11 @@ def filter(tag, time, record)
2940
# all digit entry would be treated as epoch seconds or epoch millis
3041
if !!(timestamp =~ /\A[-+]?\d+\z/)
3142
num = timestamp.to_f
32-
# epoch second or epoch millis should be either 10 or 13 digits
43+
# By default, epoch second or epoch millis should be either 10 or 13 digits
3344
# other length should be considered invalid (until the next digit
3445
# rollover at 2286-11-20 17:46:40 Z
35-
next unless [10, 13].include?(Math.log10(num).to_i + 1)
46+
# For user-defined precision also should handle here.
47+
next unless @timestamp_digits.include?(Math.log10(num).to_i + 1)
3648
record['@timestamp'] = record['fluent_converted_timestamp'] =
3749
Time.at(
3850
num / (10 ** ((Math.log10(num).to_i + 1) - 10))

test/plugin/test_filter_elasticsearch_timestamp_check.rb

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,30 @@ def test_timestamp_with_digit(data)
6464
formatted_time = Time.at(
6565
num / (10 ** ((Math.log10(num).to_i + 1) - 10))
6666
).strftime('%Y-%m-%dT%H:%M:%S.%3N%z')
67+
assert_equal([10, 13], d.instance.timestamp_digits)
68+
assert_true(filtered.key?("@timestamp"))
69+
assert_true(filtered.key?("fluent_converted_timestamp"))
70+
assert_equal(formatted_time, filtered["fluent_converted_timestamp"])
71+
end
72+
73+
data('@timestamp' => '@timestamp',
74+
'timestamp' => 'timestamp',
75+
'time' => 'time',
76+
'syslog_timestamp' => 'syslog_timestamp')
77+
def test_timestamp_with_digit_and_micro_precision(data)
78+
timekey = data
79+
precision = 6
80+
d = create_driver(%[subsecond_precision #{precision}])
81+
timestamp = '1517878172013770'
82+
d.run(default_tag: 'test') do
83+
d.feed({'test' => 'notime'}.merge(timekey => timestamp))
84+
end
85+
filtered = d.filtered.map{|e| e.last}.first
86+
num = timestamp.to_f
87+
formatted_time = Time.at(
88+
num / (10 ** ((Math.log10(num).to_i + 1) - 10))
89+
).strftime("%Y-%m-%dT%H:%M:%S.%#{precision}N%z")
90+
assert_equal([10, 13, 10 + precision], d.instance.timestamp_digits)
6791
assert_true(filtered.key?("@timestamp"))
6892
assert_true(filtered.key?("fluent_converted_timestamp"))
6993
assert_equal(formatted_time, filtered["fluent_converted_timestamp"])
@@ -77,7 +101,7 @@ def test_timestamp_with_digit_and_nano_precision(data)
77101
timekey = data
78102
precision = 9
79103
d = create_driver(%[subsecond_precision #{precision}])
80-
timestamp = '1505800348899'
104+
timestamp = '1517878172013770000'
81105
d.run(default_tag: 'test') do
82106
d.feed({'test' => 'notime'}.merge(timekey => timestamp))
83107
end
@@ -86,6 +110,7 @@ def test_timestamp_with_digit_and_nano_precision(data)
86110
formatted_time = Time.at(
87111
num / (10 ** ((Math.log10(num).to_i + 1) - 10))
88112
).strftime("%Y-%m-%dT%H:%M:%S.%#{precision}N%z")
113+
assert_equal([10, 13, 10 + precision], d.instance.timestamp_digits)
89114
assert_true(filtered.key?("@timestamp"))
90115
assert_true(filtered.key?("fluent_converted_timestamp"))
91116
assert_equal(formatted_time, filtered["fluent_converted_timestamp"])

0 commit comments

Comments
 (0)