fluent-plugin-cloudwatch-ingest-chaeyk 0.3.2 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fa4e01f170abf58d4e3b049dac9189d587b2d997
4
- data.tar.gz: 5e92f9080af46a5840a73ddb8755409d0be2d6f5
3
+ metadata.gz: 6e539d42376be0deb2bca31af801a1d18d0c2a54
4
+ data.tar.gz: 0939b1482b07c776aa3b62228f021e6a2e201bd3
5
5
  SHA512:
6
- metadata.gz: 61d65b2148af75fa53e6d334c5cac2a9b83af13288c9a7448b4cb83e1465433921f0ad02e89e15e3d568d08728ea3f57454c3aba703f03e5803076ea1197f79c
7
- data.tar.gz: 5d562ef8945fad2f3ef030e39ad2b222e1391ce1bca129ce1c31c3e12a3461c9e4d5804ef045d1a6999d4f1ca7d7d4c0ea0398eba25f458fe13b5bdf0aee7ac7
6
+ metadata.gz: 56593d2fb6a811c6199feb4ad82158a33f28d4503be0b313bbebb2e93be6ef5c33107a17c39c08d5b8d0336376df70db1b566a1cf36a8e0bac75c4e9f66cddd0
7
+ data.tar.gz: eaebcb0661295d542a1d76ac8991b8c68fd0fbe88486feca4a089d25da21755b067ded2ac36e1e2081b83768ecc479b4b8d716ce32756a5c054c6080a3f35b07
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in fluent-plugin-cloudwatch-ingest.gemspec
3
+ # Specify your gem's dependencies in fluent-plugin-cloudwatch-ingest-chaeyk.gemspec
4
4
  gemspec
data/circle.yml CHANGED
@@ -6,6 +6,6 @@ test:
6
6
  deployment:
7
7
  release:
8
8
  tag: /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$/
9
- owner: sampointer
9
+ owner: chaeyk
10
10
  commands:
11
11
  - bin/deploy
@@ -6,13 +6,13 @@ require 'fluent/plugin/cloudwatch/ingest/version'
6
6
 
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = 'fluent-plugin-cloudwatch-ingest-chaeyk'
9
- spec.version = Fluent::Plugin::Cloudwatch::Ingest::VERSION
10
- spec.authors = ['Sam Pointer']
11
- spec.email = ['san@outsidethe.net']
9
+ spec.version = Fluent::Plugin::Cloudwatch::Ingest::Chaeyk::VERSION
10
+ spec.authors = ['chaeyk']
11
+ spec.email = ['chaeyk@gmail.com']
12
12
 
13
13
  spec.summary = 'Fluentd plugin to ingest AWS Cloudwatch logs'
14
14
  spec.description = 'Fluentd plugin to ingest AWS Cloudwatch logs'
15
- spec.homepage = 'https://github.com/sampointer/fluent-plugin-cloudwatch-ingest'
15
+ spec.homepage = 'https://github.com/chaeyk/fluent-plugin-cloudwatch-ingest-chaeyk'
16
16
 
17
17
  # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
18
  # delete this section to allow pushing this gem to any host.
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.require_paths = ['lib']
29
29
 
30
30
  spec.add_development_dependency 'bundler', '~> 1.10'
31
- spec.add_development_dependency 'rake', '~> 10.0'
31
+ spec.add_development_dependency 'rake', '~> 10.5'
32
32
  spec.add_development_dependency 'rspec'
33
33
  spec.add_development_dependency 'rubocop'
34
34
 
@@ -2,7 +2,9 @@ module Fluent
2
2
  module Plugin
3
3
  module Cloudwatch
4
4
  module Ingest
5
- VERSION = '0.3.2'.freeze
5
+ module Chaeyk
6
+ VERSION = '0.4.0'.freeze
7
+ end
6
8
  end
7
9
  end
8
10
  end
@@ -8,7 +8,7 @@ require 'psych'
8
8
 
9
9
  module Fluent::Plugin
10
10
  class CloudwatchIngestInput < Fluent::Plugin::Input
11
- Fluent::Plugin.register_input('cloudwatch_ingest', self)
11
+ Fluent::Plugin.register_input('cloudwatch_ingest_chaeyk', self)
12
12
  helpers :compat_parameters, :parser
13
13
 
14
14
  desc 'The region of the source cloudwatch logs'
@@ -37,8 +37,10 @@ module Fluent::Plugin
37
37
  config_param :limit_events, :integer, default: 10_000
38
38
  desc 'Do not fetch events before this time'
39
39
  config_param :event_start_time, :integer, default: 0
40
+ desc 'Fetch the oldest logs first'
41
+ config_param :oldest_logs_first, :bool, default: false
40
42
  config_section :parse do
41
- config_set_default :@type, 'cloudwatch_ingest'
43
+ config_set_default :@type, 'cloudwatch_ingest_chaeyk'
42
44
  desc 'Regular expression with which to parse the event message'
43
45
  config_param :expression, :string, default: '^(?<message>.+)$'
44
46
  desc 'Take the timestamp from the event rather than the expression'
@@ -134,7 +136,7 @@ module Fluent::Plugin
134
136
  break unless response.next_token
135
137
  next_token = response.next_token
136
138
  rescue => boom
137
- log.error("Unable to retrieve log groups: #{boom}")
139
+ log.error("Unable to retrieve log groups: #{boom.inspect}")
138
140
  next_token = nil
139
141
  sleep @api_interval
140
142
  retry
@@ -167,7 +169,7 @@ module Fluent::Plugin
167
169
  break unless response.next_token
168
170
  next_token = response.next_token
169
171
  rescue => boom
170
- log.error("Unable to retrieve log streams for group #{log_group_name} with stream prefix #{log_stream_name_prefix}: #{boom}") # rubocop:disable all
172
+ log.error("Unable to retrieve log streams for group #{log_group_name} with stream prefix #{log_stream_name_prefix}: #{boom.inspect}") # rubocop:disable all
171
173
  log_streams = []
172
174
  next_token = nil
173
175
  sleep @api_interval
@@ -184,25 +186,36 @@ module Fluent::Plugin
184
186
  begin
185
187
  state = State.new(@state_file_name, log)
186
188
  rescue => boom
187
- log.info("Failed lock state. Sleeping for #{@interval}: #{boom}")
189
+ log.info("Failed lock state. Sleeping for #{@interval}: #{boom.inspect}")
188
190
  sleep @interval
189
- retry
191
+ next
190
192
  end
191
193
 
194
+ event_count = 0
195
+
192
196
  # Fetch the streams for each log group
193
197
  log_groups(@log_group_name_prefix).each do |group|
194
198
  # For each log stream get and emit the events
195
199
  log_streams(group, @log_stream_name_prefix).each do |stream|
200
+ if ! state.store[group][stream]
201
+ state.store[group][stream] = {}
202
+ end
203
+
196
204
  # See if we have some stored state for this group and stream.
197
205
  # If we have then use the stored forward_token to pick up
198
206
  # from that point. Otherwise start from the start.
199
- if state.store[group] && state.store[group][stream]
200
- stream_token =
201
- (state.store[group][stream] if state.store[group][stream])
207
+ if state.store[group][stream]['token']
208
+ stream_token = state.store[group][stream]['token']
202
209
  else
203
210
  stream_token = nil
204
211
  end
205
212
 
213
+ if state.store[group][stream]['timestamp']
214
+ stream_timestamp = state.store[group][stream]['timestamp']
215
+ else
216
+ stream_timestamp = @event_start_time
217
+ end
218
+
206
219
  begin
207
220
  response = @aws.get_log_events(
208
221
  log_group_name: group,
@@ -210,24 +223,57 @@ module Fluent::Plugin
210
223
  next_token: stream_token,
211
224
  limit: @limit_events,
212
225
  start_time: @event_start_time,
213
- start_from_head: true
226
+ start_from_head: @oldest_logs_first
214
227
  )
215
228
 
216
229
  response.events.each do |e|
217
230
  begin
218
231
  emit(e, group, stream)
232
+ event_count = event_count + 1
219
233
  rescue => boom
220
- log.error("Failed to emit event #{e}: #{boom}")
234
+ log.error("Failed to emit event #{e}: #{boom.inspect}")
221
235
  end
222
236
  end
223
237
 
224
238
  # Once all events for this stream have been processed,
225
239
  # in this iteration, store the forward token
226
- state.store[group][stream] = response.next_forward_token
240
+ state.store[group][stream]['token'] = response.next_forward_token
241
+ state.store[group][stream]['timestamp'] = response.events.last ? response.events.last.timestamp : stream_timestamp
242
+ rescue Aws::CloudWatchLogs::Errors::InvalidParameterException => boom
243
+ log.error("cloudwatch token is expired or broken. trying with timestamp.");
244
+
245
+ # try again with timestamp instead of forward token
246
+ begin
247
+ response = @aws.get_log_events(
248
+ log_group_name: group,
249
+ log_stream_name: stream,
250
+ limit: @limit_events,
251
+ start_time: stream_timestamp,
252
+ start_from_head: true
253
+ )
254
+
255
+ response.events.each do |e|
256
+ begin
257
+ emit(e, group, stream)
258
+ event_count = event_count + 1
259
+ rescue => boom
260
+ log.error("Failed to emit event #{e}: #{boom.inspect}")
261
+ end
262
+ end
263
+
264
+ # Once all events for this stream have been processed,
265
+ # in this iteration, store the forward token
266
+ state.store[group][stream]["token"] = response.next_forward_token
267
+ state.store[group][stream]['timestamp'] = response.events.last ? response.events.last.timestamp : steam_timestamp
268
+ rescue => boom
269
+ log.error("Unable to retrieve events for stream #{stream} in group #{group}: #{boom.inspect}") # rubocop:disable all
270
+ sleep @api_interval
271
+ next
272
+ end
227
273
  rescue => boom
228
- log.error("Unable to retrieve events for stream #{stream} in group #{group}: #{boom}") # rubocop:disable all
274
+ log.error("Unable to retrieve events for stream #{stream} in group #{group}: #{boom.inspect}") # rubocop:disable all
229
275
  sleep @api_interval
230
- retry
276
+ next
231
277
  end
232
278
  end
233
279
  end
@@ -238,10 +284,18 @@ module Fluent::Plugin
238
284
  state.save
239
285
  state.close
240
286
  rescue
241
- log.error("Unable to save state file: #{boom}")
287
+ log.error("Unable to save state file: #{boom.inspect}")
242
288
  end
243
- log.info("Pausing for #{@interval}")
244
- sleep @interval
289
+
290
+ if event_count > 0
291
+ sleep_interval = @interval
292
+ else
293
+ sleep_interval = @api_interval # when there is no events, slow down
294
+ end
295
+
296
+ log.info("#{event_count} events processed.")
297
+ log.info("Pausing for #{sleep_interval}")
298
+ sleep sleep_interval
245
299
  end
246
300
  end
247
301
 
@@ -252,7 +306,7 @@ module Fluent::Plugin
252
306
  def initialize(filepath, log)
253
307
  @filepath = filepath
254
308
  @log = log
255
- @store = Hash.new { |h, k| h[k] = {} }
309
+ @store = Hash.new { |h, k| h[k] = Hash.new { |h1, k1| h1[k1] = {} } }
256
310
 
257
311
  if File.exist?(filepath)
258
312
  self.statefile = Pathname.new(@filepath).open('r+')
@@ -262,7 +316,7 @@ module Fluent::Plugin
262
316
  self.statefile = Pathname.new(@filepath).open('w+')
263
317
  save
264
318
  rescue => boom
265
- @log.error("Unable to create new file #{statefile.path}: #{boom}")
319
+ @log.error("Unable to create new file #{statefile.path}: #{boom.inspect}")
266
320
  end
267
321
  end
268
322
 
@@ -272,12 +326,26 @@ module Fluent::Plugin
272
326
  lockstatus = statefile.flock(File::LOCK_EX | File::LOCK_NB)
273
327
  raise CloudwatchIngestInput::State::LockFailed if lockstatus == false
274
328
 
275
- @store.merge!(Psych.safe_load(statefile.read))
276
- @log.info("Loaded #{@store.keys.size} groups from #{statefile.path}")
329
+ begin
330
+ @store.merge!(Psych.safe_load(statefile.read))
331
+
332
+ # Migrate old state file
333
+ @store.each { |group, streams|
334
+ streams.update(streams) { |name, stream|
335
+ (stream.is_a? String) ? { 'token' => stream, 'timestamp' => Time.now.to_i } : stream
336
+ }
337
+ }
338
+
339
+ @log.info("Loaded #{@store.keys.size} groups from #{statefile.path}")
340
+ rescue
341
+ statefile.close
342
+ raise
343
+ end
277
344
  end
278
345
 
279
346
  def save
280
347
  statefile.rewind
348
+ statefile.truncate(0)
281
349
  statefile.write(Psych.dump(@store))
282
350
  @log.info("Saved state to #{statefile.path}")
283
351
  statefile.rewind
@@ -4,7 +4,7 @@ require 'fluent/time'
4
4
  module Fluent
5
5
  module Plugin
6
6
  class CloudwatchIngestParser < RegexpParser
7
- Plugin.register_parser('cloudwatch_ingest', self)
7
+ Plugin.register_parser('cloudwatch_ingest_chaeyk', self)
8
8
 
9
9
  config_param :expression, :string, default: '^(?<message>.+)$'
10
10
  config_param :time_format, :string, default: '%Y-%m-%d %H:%M:%S.%L'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-cloudwatch-ingest-chaeyk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
- - Sam Pointer
7
+ - chaeyk
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-05-13 00:00:00.000000000 Z
11
+ date: 2017-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '10.5'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '10.5'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -96,7 +96,7 @@ dependencies:
96
96
  version: 2.8.4
97
97
  description: Fluentd plugin to ingest AWS Cloudwatch logs
98
98
  email:
99
- - san@outsidethe.net
99
+ - chaeyk@gmail.com
100
100
  executables: []
101
101
  extensions: []
102
102
  extra_rdoc_files: []
@@ -114,12 +114,12 @@ files:
114
114
  - bin/deploy
115
115
  - bin/setup
116
116
  - circle.yml
117
- - fluent-plugin-cloudwatch-ingest.gemspec
117
+ - fluent-plugin-cloudwatch-ingest-chaeyk.gemspec
118
118
  - lib/fluent/plugin/cloudwatch/ingest.rb
119
119
  - lib/fluent/plugin/cloudwatch/ingest/version.rb
120
- - lib/fluent/plugin/in_cloudwatch_ingest.rb
121
- - lib/fluent/plugin/parser_cloudwatch_ingest.rb
122
- homepage: https://github.com/sampointer/fluent-plugin-cloudwatch-ingest
120
+ - lib/fluent/plugin/in_cloudwatch_ingest_chaeyk.rb
121
+ - lib/fluent/plugin/parser_cloudwatch_ingest_chaeyk.rb
122
+ homepage: https://github.com/chaeyk/fluent-plugin-cloudwatch-ingest-chaeyk
123
123
  licenses: []
124
124
  metadata:
125
125
  allowed_push_host: https://rubygems.org