fluent-plugin-time-cutoff 0.1.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +53 -1
- data/lib/fluent/plugin/filter_time_cutoff.rb +217 -21
- metadata +6 -26
- data/.rubocop.yml +0 -2
- data/Rakefile +0 -13
- data/fluent-plugin-time-cutoff.gemspec +0 -37
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5eddac80384bc759095b8ead85af572e50aafb3d0820b8f87b46b8fbc7aa6361
|
|
4
|
+
data.tar.gz: 2df3ffbc38531125d8b893eec4a144ffda0348505efa46a9d9a29412a5da1505
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3bb580a34a68cd2859431f64cb034046b7ffaee4680241617d9f279ed0eb2140b55a1b610dccbf7b35558c1e1b92e3f39b42e9f5db35eab5334cbe1e6dd64918
|
|
7
|
+
data.tar.gz: ff4f97ac6abec3a87807cee266cbf1597dfeb8dae566ff742ba797aef4946238ec89ecdc89374be259dfaea1ae4730e476cdb0dfc46369c2b7023b63abe173f8
|
data/README.md
CHANGED
|
@@ -112,6 +112,12 @@ $ bundle
|
|
|
112
112
|
|
|
113
113
|
source_time_key source_time
|
|
114
114
|
source_time_format iso8601
|
|
115
|
+
|
|
116
|
+
bad_time_action replace_timestamp
|
|
117
|
+
bad_time_log true
|
|
118
|
+
bad_time_key source_time_raw
|
|
119
|
+
|
|
120
|
+
time_key_conflict skip
|
|
115
121
|
</filter>
|
|
116
122
|
|
|
117
123
|
```
|
|
@@ -120,6 +126,8 @@ $ bundle
|
|
|
120
126
|
|
|
121
127
|
Records older than this amount of time are deemed "old". Defaults to 24 hours.
|
|
122
128
|
|
|
129
|
+
Must not be negative.
|
|
130
|
+
|
|
123
131
|
Default value: `86400`.
|
|
124
132
|
|
|
125
133
|
### old_action (enum) (optional)
|
|
@@ -140,6 +148,8 @@ Default value: `true`.
|
|
|
140
148
|
|
|
141
149
|
Records newer than this amount of time are deemed "new". Defaults to 24 hours.
|
|
142
150
|
|
|
151
|
+
Must not be negative.
|
|
152
|
+
|
|
143
153
|
Default value: `86400`.
|
|
144
154
|
|
|
145
155
|
### new_action (enum) (optional)
|
|
@@ -160,6 +170,8 @@ Default value: `true`.
|
|
|
160
170
|
|
|
161
171
|
The key that will hold the original time (for :replace_timestamp action). Defaults to "source_time".
|
|
162
172
|
|
|
173
|
+
Must not be empty or equal to `bad_time_key`.
|
|
174
|
+
|
|
163
175
|
Default value: `source_time`.
|
|
164
176
|
|
|
165
177
|
### source_time_format (enum) (optional)
|
|
@@ -170,7 +182,47 @@ Available values: epoch, epoch_float, iso8601
|
|
|
170
182
|
|
|
171
183
|
Default value: `iso8601`.
|
|
172
184
|
|
|
185
|
+
### bad_time_action (enum) (optional)
|
|
186
|
+
|
|
187
|
+
The action that will be performed to all messages with an unparseable time. Defaults to replacing it with current time.
|
|
188
|
+
|
|
189
|
+
Event times that aren't a `Fluent::EventTime` are parsed before the age check. Integers, floats, numeric strings and ISO 8601 datetime strings are accepted. ISO 8601 strings may use a space instead of `T` and may have a space before the timezone (e.g. `2025-04-08 14:43:14 +0300` or `2025-04-08 11:43:14 UTC`, as produced by Ruby's `Time#to_s`). Strings without a timezone are treated as local time. Any other time is deemed unparseable and is handled according to this action (and logged, unless `bad_time_log` is disabled).
|
|
190
|
+
|
|
191
|
+
Available values: replace_timestamp, drop
|
|
192
|
+
|
|
193
|
+
Default value: `replace_timestamp`.
|
|
194
|
+
|
|
195
|
+
### bad_time_log (bool) (optional)
|
|
196
|
+
|
|
197
|
+
Log the messages with an unparseable time to Fluentd's own log. Defaults to "true".
|
|
198
|
+
|
|
199
|
+
Default value: `true`.
|
|
200
|
+
|
|
201
|
+
### bad_time_key (string) (optional)
|
|
202
|
+
|
|
203
|
+
The key that will hold the original unparseable time (for :replace_timestamp action). Defaults to "source_time_raw".
|
|
204
|
+
|
|
205
|
+
Must not be empty or equal to `source_time_key`.
|
|
206
|
+
|
|
207
|
+
The original time is stored as is if it's a string, or as its Ruby `#inspect` representation otherwise (e.g. `nil`), so this field always holds a string. It is kept separate from `source_time_key`, so that `source_time_key` always holds a value in `source_time_format` and doesn't cause type conflicts in downstream storage.
|
|
208
|
+
|
|
209
|
+
Default value: `source_time_raw`.
|
|
210
|
+
|
|
211
|
+
### time_key_conflict (enum) (optional)
|
|
212
|
+
|
|
213
|
+
The action that will be performed when the record already has source_time_key or bad_time_key. Defaults to keeping the existing value.
|
|
214
|
+
|
|
215
|
+
This happens e.g. when a record passes through more than one `time_cutoff` filter, in which case the existing value is the true original time. The event time itself is replaced with current time in any case.
|
|
216
|
+
|
|
217
|
+
* `skip`: keep the existing value.
|
|
218
|
+
* `warn`: keep the existing value and log a warning to Fluentd's own log.
|
|
219
|
+
* `overwrite`: replace the existing value.
|
|
220
|
+
|
|
221
|
+
Available values: skip, warn, overwrite
|
|
222
|
+
|
|
223
|
+
Default value: `skip`.
|
|
224
|
+
|
|
173
225
|
## Copyright
|
|
174
226
|
|
|
175
|
-
* Copyright(c) 2025 Qrator Labs and Serge Tkatchouk
|
|
227
|
+
* Copyright(c) 2025-2026 Qrator Labs and Serge Tkatchouk
|
|
176
228
|
* License: MIT
|
|
@@ -31,9 +31,41 @@ module Fluent
|
|
|
31
31
|
:iso8601
|
|
32
32
|
].freeze
|
|
33
33
|
|
|
34
|
+
# Available actions for records with an unparseable time.
|
|
35
|
+
BAD_TIME_ACTIONS = [
|
|
36
|
+
# Replace time with "now" and pass:
|
|
37
|
+
:replace_timestamp,
|
|
38
|
+
# Drop record as invalid:
|
|
39
|
+
:drop
|
|
40
|
+
].freeze
|
|
41
|
+
|
|
42
|
+
# Available actions for records that already have the key the original
|
|
43
|
+
# time should be put into (for :replace_timestamp action).
|
|
44
|
+
TIME_KEY_CONFLICT_ACTIONS = [
|
|
45
|
+
# Keep the existing value:
|
|
46
|
+
:skip,
|
|
47
|
+
# Keep the existing value and log a warning:
|
|
48
|
+
:warn,
|
|
49
|
+
# Replace the existing value:
|
|
50
|
+
:overwrite
|
|
51
|
+
].freeze
|
|
52
|
+
|
|
34
53
|
# strftime() format string for :iso8601 time format.
|
|
35
54
|
TIME_ISO8601 = '%FT%T%:z'
|
|
36
55
|
|
|
56
|
+
# Matches a "relaxed" ISO 8601 datetime string, which uses a space
|
|
57
|
+
# instead of "T" between the date and the time and/or has a space
|
|
58
|
+
# before the timezone (e.g. Ruby's Time#to_s: "2026-10-10 03:57:04 +0300"
|
|
59
|
+
# or "2026-10-10 00:57:04 UTC"), so that it can be rebuilt as a strict one.
|
|
60
|
+
ISO8601_RELAXED = /
|
|
61
|
+
\A
|
|
62
|
+
(?<date>\d{4}-\d{2}-\d{2})
|
|
63
|
+
[T\ ]
|
|
64
|
+
(?<time>\d{2}:\d{2}:\d{2}(?:\.\d+)?)
|
|
65
|
+
(?:\ ?(?<zone>Z|UTC|[+-]\d{2}(?::?\d{2})?))?
|
|
66
|
+
\z
|
|
67
|
+
/x.freeze
|
|
68
|
+
|
|
37
69
|
Fluent::Plugin.register_filter('time_cutoff', self)
|
|
38
70
|
|
|
39
71
|
desc 'Records older than this amount of time are deemed "old". Defaults to 24 hours.'
|
|
@@ -52,15 +84,51 @@ module Fluent
|
|
|
52
84
|
config_param :source_time_key, :string, default: 'source_time'
|
|
53
85
|
desc 'Time format for the original timestamp field. Defaults to ISO8601-formatted string.'
|
|
54
86
|
config_param :source_time_format, :enum, list: TIME_FORMATS, default: :iso8601
|
|
87
|
+
desc 'The action that will be performed to all messages with an unparseable time. Defaults to replacing it with current time.'
|
|
88
|
+
config_param :bad_time_action, :enum, list: BAD_TIME_ACTIONS, default: :replace_timestamp
|
|
89
|
+
desc 'Log the messages with an unparseable time to Fluentd\'s own log. Defaults to "true".'
|
|
90
|
+
config_param :bad_time_log, :bool, default: true
|
|
91
|
+
desc 'The key that will hold the original unparseable time (for :replace_timestamp action). Defaults to "source_time_raw".'
|
|
92
|
+
config_param :bad_time_key, :string, default: 'source_time_raw'
|
|
93
|
+
desc 'The action that will be performed when the record already has source_time_key or bad_time_key. Defaults to keeping the existing value.'
|
|
94
|
+
config_param :time_key_conflict, :enum, list: TIME_KEY_CONFLICT_ACTIONS, default: :skip
|
|
95
|
+
|
|
96
|
+
def configure(conf)
|
|
97
|
+
super
|
|
98
|
+
|
|
99
|
+
%i[old_cutoff new_cutoff].each do |param|
|
|
100
|
+
# NOTE: Fluentd's :time type drops the sign of values with a unit
|
|
101
|
+
# (e.g. "-1h" is parsed as 3600), so the raw value is checked too.
|
|
102
|
+
raw = conf[param.to_s].to_s.strip
|
|
103
|
+
next unless raw.start_with?('-') || instance_variable_get("@#{param}").negative?
|
|
104
|
+
|
|
105
|
+
raise Fluent::ConfigError, "#{param} must not be negative, got \"#{raw}\""
|
|
106
|
+
end
|
|
107
|
+
%i[source_time_key bad_time_key].each do |param|
|
|
108
|
+
raise Fluent::ConfigError, "#{param} must not be empty" if instance_variable_get("@#{param}").empty?
|
|
109
|
+
end
|
|
110
|
+
return unless @source_time_key == @bad_time_key
|
|
111
|
+
|
|
112
|
+
raise Fluent::ConfigError, "source_time_key and bad_time_key must differ, both are \"#{@source_time_key}\""
|
|
113
|
+
end
|
|
55
114
|
|
|
56
115
|
def filter_with_time(tag, time, record)
|
|
116
|
+
## Safeguard against rogue integer/float/string time. This has to happen
|
|
117
|
+
## before classification, so that the age check uses the parsed value.
|
|
118
|
+
unless time.is_a?(Fluent::EventTime)
|
|
119
|
+
normalized = normalize_time(time)
|
|
120
|
+
return process_bad_time_record(tag, time, record) if normalized.nil?
|
|
121
|
+
|
|
122
|
+
time = normalized
|
|
123
|
+
end
|
|
124
|
+
|
|
57
125
|
event_time = time.to_i
|
|
58
|
-
|
|
126
|
+
now = current_time
|
|
59
127
|
|
|
60
|
-
if event_time <
|
|
128
|
+
if event_time < now - @old_cutoff
|
|
61
129
|
# Too old
|
|
62
130
|
process_old_record(tag, time, record)
|
|
63
|
-
elsif event_time >
|
|
131
|
+
elsif event_time > now + @new_cutoff
|
|
64
132
|
# Too new
|
|
65
133
|
process_new_record(tag, time, record)
|
|
66
134
|
else
|
|
@@ -71,6 +139,24 @@ module Fluent
|
|
|
71
139
|
|
|
72
140
|
private
|
|
73
141
|
|
|
142
|
+
# Current UNIX time, used as the reference point for the age check.
|
|
143
|
+
# Kept as a separate method so that tests can freeze the clock.
|
|
144
|
+
# @return [Integer] current time in seconds
|
|
145
|
+
def current_time
|
|
146
|
+
Time.now.to_i
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Format the event time as an ISO 8601 datetime string (in local time).
|
|
150
|
+
# NOTE: Time.at(int) is used instead of EventTime#to_time, which was
|
|
151
|
+
# only added to Fluentd in v1.8.0, and instead of Time.at(EventTime),
|
|
152
|
+
# which relies on Ruby coercing EventTime via #to_r/#to_int. EventTime#to_i
|
|
153
|
+
# is available in all Fluentd releases declared in the gemspec.
|
|
154
|
+
# @param time [Fluent::EventTime] the event time
|
|
155
|
+
# @return [String] ISO 8601-formatted datetime string
|
|
156
|
+
def iso8601(time)
|
|
157
|
+
Time.at(time.to_i).strftime(TIME_ISO8601)
|
|
158
|
+
end
|
|
159
|
+
|
|
74
160
|
# Format the event time to a given type/format.
|
|
75
161
|
# @param time [Fluent::EventTime] the original event time
|
|
76
162
|
# @param @source_time_format [Symbol] the target format
|
|
@@ -82,22 +168,50 @@ module Fluent
|
|
|
82
168
|
when :epoch_float
|
|
83
169
|
time.to_f
|
|
84
170
|
when :iso8601
|
|
85
|
-
time
|
|
171
|
+
iso8601(time)
|
|
86
172
|
end
|
|
87
173
|
end
|
|
88
174
|
|
|
89
175
|
# Replace event time and put the old time into a specified field.
|
|
176
|
+
# @param tag [String] log/stream's tag name
|
|
90
177
|
# @param time [Fluent::EventTime] the original event time
|
|
91
178
|
# @param record [Hash] the original record contents
|
|
92
179
|
# @param @source_time_key [String] name of the field to put the old timestamp to.
|
|
93
180
|
# @return [Array] new event time and a modified record.
|
|
94
|
-
def do_replace_timestamp(time, record)
|
|
95
|
-
|
|
181
|
+
def do_replace_timestamp(tag, time, record)
|
|
182
|
+
[Fluent::EventTime.now, put_time_key(tag, record, @source_time_key, format_time(time))]
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Put the original time into the given field of a copy of the record,
|
|
186
|
+
# unless the record already has that field and @time_key_conflict says
|
|
187
|
+
# to keep it. The original record is never modified.
|
|
188
|
+
# @param tag [String] log/stream's tag name
|
|
189
|
+
# @param record [Hash] the original record contents
|
|
190
|
+
# @param key [String] name of the field to put the time to
|
|
191
|
+
# @param value the time value to put into the field
|
|
192
|
+
# @return [Hash] the modified copy of the record, or the original record if kept as is
|
|
193
|
+
def put_time_key(tag, record, key, value)
|
|
194
|
+
if record.key?(key) && @time_key_conflict != :overwrite
|
|
195
|
+
log_time_key_conflict(tag, record, key, value) if @time_key_conflict == :warn
|
|
196
|
+
return record
|
|
197
|
+
end
|
|
198
|
+
|
|
96
199
|
new_record = record.dup
|
|
97
|
-
|
|
98
|
-
new_record
|
|
200
|
+
new_record[key] = value
|
|
201
|
+
new_record
|
|
202
|
+
end
|
|
99
203
|
|
|
100
|
-
|
|
204
|
+
# Log a time key conflict to Fluentd's log.
|
|
205
|
+
# @param tag [String] log/stream's tag name
|
|
206
|
+
# @param record [Hash] the original record contents
|
|
207
|
+
# @param key [String] name of the conflicting field
|
|
208
|
+
# @param value the time value that was not put into the field
|
|
209
|
+
def log_time_key_conflict(tag, record, key, value)
|
|
210
|
+
log_line = format(
|
|
211
|
+
'Record already has the "%<key>s" key, keeping its existing value instead of %<val>s: "%<tag>s: %<msg>s".',
|
|
212
|
+
key: key, val: value.inspect, tag: tag, msg: dump_record(record)
|
|
213
|
+
)
|
|
214
|
+
log.warn log_line
|
|
101
215
|
end
|
|
102
216
|
|
|
103
217
|
# Log the caught event to Fluentd's log.
|
|
@@ -107,28 +221,83 @@ module Fluent
|
|
|
107
221
|
# @param action [Symbol] determined action for this record
|
|
108
222
|
# @param age [Symbol] detemined age for this record (:old or :new)
|
|
109
223
|
def log_record(tag, time, record, action, age)
|
|
110
|
-
fmt_time = Time.at(time).strftime(TIME_ISO8601)
|
|
111
224
|
log_line = format(
|
|
112
225
|
'Record caught [%<age>s, %<act>s]: "%<tag>s: %<time>s %<msg>s".',
|
|
113
|
-
age: age, act: action, tag: tag, time:
|
|
226
|
+
age: age, act: action, tag: tag, time: iso8601(time), msg: dump_record(record)
|
|
114
227
|
)
|
|
115
228
|
log.warn log_line
|
|
116
229
|
end
|
|
117
230
|
|
|
118
|
-
#
|
|
119
|
-
# @param
|
|
120
|
-
# @
|
|
231
|
+
# Log the caught event with an unparseable time to Fluentd's log.
|
|
232
|
+
# @param tag [String] log/stream's tag name
|
|
233
|
+
# @param time the original (unparseable) event time
|
|
234
|
+
# @param record [Hash] the original record contents
|
|
235
|
+
# @param action [Symbol] determined action for this record
|
|
236
|
+
def log_bad_time_record(tag, time, record, action)
|
|
237
|
+
log_line = format(
|
|
238
|
+
'Record caught [unparseable, %<act>s]: "%<tag>s: %<time>s %<msg>s".',
|
|
239
|
+
act: action, tag: tag, time: time.inspect, msg: dump_record(record)
|
|
240
|
+
)
|
|
241
|
+
log.warn log_line
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Serialize the record for logging. Falls back to #inspect when the
|
|
245
|
+
# record can't be represented as JSON (e.g. invalid UTF-8 or NaN), so
|
|
246
|
+
# that a logging failure never affects how the record is processed.
|
|
247
|
+
# @param record [Hash] the original record contents
|
|
248
|
+
# @return [String] the record as a JSON string, or its #inspect output
|
|
249
|
+
def dump_record(record)
|
|
250
|
+
record.to_json
|
|
251
|
+
rescue JSON::GeneratorError, EncodingError
|
|
252
|
+
record.inspect
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Normalize time to Fluent::EventTime if it's plain int or float, a
|
|
256
|
+
# numeric string or an ISO 8601 datetime string.
|
|
257
|
+
# @param time [Integer|Float|String] incoming event time
|
|
258
|
+
# @return [Fluent::EventTime,nil] event time normalized to Fluentd's internal format, or nil if unparseable
|
|
121
259
|
def normalize_time(time)
|
|
122
|
-
case time
|
|
260
|
+
case time
|
|
123
261
|
when Integer
|
|
124
262
|
Fluent::EventTime.new(time)
|
|
125
263
|
when Float
|
|
126
264
|
time_int, time_frac = time.divmod(1)
|
|
127
265
|
Fluent::EventTime.new(time_int, (time_frac * 10**9).to_i)
|
|
128
266
|
else
|
|
129
|
-
|
|
130
|
-
|
|
267
|
+
if (numeric = coerce_to_number(time))
|
|
268
|
+
normalize_time(numeric)
|
|
269
|
+
elsif (parsed = parse_iso8601(time))
|
|
270
|
+
Fluent::EventTime.new(parsed.to_i, parsed.nsec)
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Try to coerce an arbitrary value into a number, or return nil.
|
|
276
|
+
# Integer() is called with an explicit base 10 so that zero-padded
|
|
277
|
+
# strings (e.g. "01700000000") aren't parsed as octal.
|
|
278
|
+
# @param value the value to coerce
|
|
279
|
+
# @return [Integer,Float,nil] the parsed number, or nil if not numeric
|
|
280
|
+
def coerce_to_number(value)
|
|
281
|
+
Integer(value, 10, exception: false) || Float(value, exception: false)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Try to parse a strict ISO 8601 datetime string, or return nil.
|
|
285
|
+
# Time.iso8601 is used instead of the lenient Time.parse, which would
|
|
286
|
+
# happily turn partial or ambiguous strings into a wrong timestamp.
|
|
287
|
+
# "Relaxed" strings (see ISO8601_RELAXED) are rebuilt as strict ones
|
|
288
|
+
# before parsing. Strings without a UTC offset are treated as local time.
|
|
289
|
+
# @param value the value to parse
|
|
290
|
+
# @return [Time,nil] the parsed time, or nil if not an ISO 8601 string
|
|
291
|
+
def parse_iso8601(value)
|
|
292
|
+
return nil unless value.is_a?(String)
|
|
293
|
+
|
|
294
|
+
if (match = ISO8601_RELAXED.match(value))
|
|
295
|
+
zone = match[:zone] == 'UTC' ? 'Z' : match[:zone]
|
|
296
|
+
value = "#{match[:date]}T#{match[:time]}#{zone}"
|
|
131
297
|
end
|
|
298
|
+
Time.iso8601(value)
|
|
299
|
+
rescue ArgumentError
|
|
300
|
+
nil
|
|
132
301
|
end
|
|
133
302
|
|
|
134
303
|
# Process the record according to its determined "age"
|
|
@@ -139,21 +308,48 @@ module Fluent
|
|
|
139
308
|
# @param action [Symbol] determined action for this record
|
|
140
309
|
# @param age [Symbol] detemined age for this record (:old or :new)
|
|
141
310
|
def process_record(tag, time, record, do_log, action, age) # rubocop:disable Metrics/ParameterLists
|
|
142
|
-
## Safeguard against rogue integer time.
|
|
143
|
-
time = normalize_time(time) unless time.is_a?(Fluent::EventTime)
|
|
144
|
-
|
|
145
311
|
log_record(tag, time, record, action, age) if do_log
|
|
146
312
|
|
|
147
313
|
case action
|
|
148
314
|
when :pass
|
|
149
315
|
[time, record]
|
|
150
316
|
when :replace_timestamp
|
|
151
|
-
do_replace_timestamp(time, record)
|
|
317
|
+
do_replace_timestamp(tag, time, record)
|
|
152
318
|
when :drop
|
|
153
319
|
nil
|
|
154
320
|
end
|
|
155
321
|
end
|
|
156
322
|
|
|
323
|
+
# Process the record with an unparseable time according to the configuration
|
|
324
|
+
# @param tag [String] log/stream's tag name
|
|
325
|
+
# @param time the original (unparseable) event time
|
|
326
|
+
# @param record [Hash] the original record contents
|
|
327
|
+
# @return [Array,nil] current time and the record, or nil if dropped.
|
|
328
|
+
def process_bad_time_record(tag, time, record)
|
|
329
|
+
log_bad_time_record(tag, time, record, @bad_time_action) if @bad_time_log
|
|
330
|
+
|
|
331
|
+
case @bad_time_action
|
|
332
|
+
when :replace_timestamp
|
|
333
|
+
do_replace_bad_timestamp(tag, time, record)
|
|
334
|
+
when :drop
|
|
335
|
+
nil
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Replace unparseable event time and put the raw original time into a
|
|
340
|
+
# separate field. The raw time is always stored as a string, so that the
|
|
341
|
+
# field keeps a stable type for downstream storage. It is not put into
|
|
342
|
+
# @source_time_key, which holds a value in @source_time_format instead.
|
|
343
|
+
# @param tag [String] log/stream's tag name
|
|
344
|
+
# @param time the original (unparseable) event time
|
|
345
|
+
# @param record [Hash] the original record contents
|
|
346
|
+
# @param @bad_time_key [String] name of the field to put the raw time to.
|
|
347
|
+
# @return [Array] new event time and a modified record.
|
|
348
|
+
def do_replace_bad_timestamp(tag, time, record)
|
|
349
|
+
raw_time = time.is_a?(String) ? time : time.inspect
|
|
350
|
+
[Fluent::EventTime.now, put_time_key(tag, record, @bad_time_key, raw_time)]
|
|
351
|
+
end
|
|
352
|
+
|
|
157
353
|
# Process the "old" record according to the configuration
|
|
158
354
|
# @param tag [String] log/stream's tag name
|
|
159
355
|
# @param time [Fluent::EventTime] the original event time
|
metadata
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fluent-plugin-time-cutoff
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Qrator Labs
|
|
8
8
|
- Serge Tkatchouk
|
|
9
|
-
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: fluentd
|
|
@@ -31,34 +30,20 @@ dependencies:
|
|
|
31
30
|
- - "<"
|
|
32
31
|
- !ruby/object:Gem::Version
|
|
33
32
|
version: '2'
|
|
34
|
-
- !ruby/object:Gem::Dependency
|
|
35
|
-
name: bundler
|
|
36
|
-
requirement: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - "~>"
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: 2.6.3
|
|
41
|
-
type: :development
|
|
42
|
-
prerelease: false
|
|
43
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
44
|
-
requirements:
|
|
45
|
-
- - "~>"
|
|
46
|
-
- !ruby/object:Gem::Version
|
|
47
|
-
version: 2.6.3
|
|
48
33
|
- !ruby/object:Gem::Dependency
|
|
49
34
|
name: rake
|
|
50
35
|
requirement: !ruby/object:Gem::Requirement
|
|
51
36
|
requirements:
|
|
52
37
|
- - "~>"
|
|
53
38
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 13.
|
|
39
|
+
version: 13.2.0
|
|
55
40
|
type: :development
|
|
56
41
|
prerelease: false
|
|
57
42
|
version_requirements: !ruby/object:Gem::Requirement
|
|
58
43
|
requirements:
|
|
59
44
|
- - "~>"
|
|
60
45
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: 13.
|
|
46
|
+
version: 13.2.0
|
|
62
47
|
- !ruby/object:Gem::Dependency
|
|
63
48
|
name: test-unit
|
|
64
49
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -82,17 +67,13 @@ executables: []
|
|
|
82
67
|
extensions: []
|
|
83
68
|
extra_rdoc_files: []
|
|
84
69
|
files:
|
|
85
|
-
- ".rubocop.yml"
|
|
86
70
|
- LICENSE.txt
|
|
87
71
|
- README.md
|
|
88
|
-
- Rakefile
|
|
89
|
-
- fluent-plugin-time-cutoff.gemspec
|
|
90
72
|
- lib/fluent/plugin/filter_time_cutoff.rb
|
|
91
73
|
homepage: https://github.com/QratorLabs/fluent-plugin-time-cutoff
|
|
92
74
|
licenses:
|
|
93
75
|
- MIT
|
|
94
76
|
metadata: {}
|
|
95
|
-
post_install_message:
|
|
96
77
|
rdoc_options: []
|
|
97
78
|
require_paths:
|
|
98
79
|
- lib
|
|
@@ -100,15 +81,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
100
81
|
requirements:
|
|
101
82
|
- - ">="
|
|
102
83
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '2.
|
|
84
|
+
version: '2.7'
|
|
104
85
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
86
|
requirements:
|
|
106
87
|
- - ">="
|
|
107
88
|
- !ruby/object:Gem::Version
|
|
108
89
|
version: '0'
|
|
109
90
|
requirements: []
|
|
110
|
-
rubygems_version:
|
|
111
|
-
signing_key:
|
|
91
|
+
rubygems_version: 4.0.18
|
|
112
92
|
specification_version: 4
|
|
113
93
|
summary: Fluentd time-based filter plugin.
|
|
114
94
|
test_files: []
|
data/.rubocop.yml
DELETED
data/Rakefile
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
require 'bundler'
|
|
2
|
-
Bundler::GemHelper.install_tasks
|
|
3
|
-
|
|
4
|
-
require 'rake/testtask'
|
|
5
|
-
|
|
6
|
-
Rake::TestTask.new(:test) do |t|
|
|
7
|
-
t.libs.push('lib', 'test')
|
|
8
|
-
t.test_files = FileList['test/**/test_*.rb']
|
|
9
|
-
t.verbose = true
|
|
10
|
-
t.warning = true
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
task default: [:test]
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
lib = File.expand_path('../lib', __dir__)
|
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
-
|
|
6
|
-
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name = 'fluent-plugin-time-cutoff'
|
|
8
|
-
spec.version = '0.1.3'
|
|
9
|
-
spec.authors = ['Qrator Labs', 'Serge Tkatchouk']
|
|
10
|
-
spec.email = ['devops@qrator.net', 'st@qrator.net']
|
|
11
|
-
|
|
12
|
-
spec.summary = 'Fluentd time-based filter plugin.'
|
|
13
|
-
spec.description = 'A plugin that lets Fluentd to prune/rewrite messages '\
|
|
14
|
-
'that have a timestamp that is too old or too new.'
|
|
15
|
-
spec.homepage = 'https://github.com/QratorLabs/fluent-plugin-time-cutoff'
|
|
16
|
-
spec.license = 'MIT'
|
|
17
|
-
|
|
18
|
-
spec.files = Dir.chdir(__dir__) do
|
|
19
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
|
20
|
-
(File.expand_path(f) == __FILE__) ||
|
|
21
|
-
f.start_with?(*%w[test/ testbed/ spec/ features/ .git .circleci appveyor Gemfile])
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
26
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
27
|
-
spec.require_paths = ['lib']
|
|
28
|
-
|
|
29
|
-
spec.platform = Gem::Platform::RUBY
|
|
30
|
-
spec.required_ruby_version = Gem::Requirement.new('>= 2.3')
|
|
31
|
-
|
|
32
|
-
spec.add_runtime_dependency 'fluentd', ['>= 0.14.10', '< 2']
|
|
33
|
-
|
|
34
|
-
spec.add_development_dependency 'bundler', '~> 2.6.3'
|
|
35
|
-
spec.add_development_dependency 'rake', '~> 13.1.0'
|
|
36
|
-
spec.add_development_dependency 'test-unit', '~> 3.6.1'
|
|
37
|
-
end
|