fluent-plugin-sumologic_output 1.7.5 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10221368588a63fe0f97cb60695466a78a12eae80c13f736b5ae54879e4a5b4e
4
- data.tar.gz: 2b99181908e9df7b2bcae1e6534a9311d72464cb74923a77f3a7489eeeb13f94
3
+ metadata.gz: 280c08203277770f0dc9277d9df2f8249fba58283816e4fd5b511560fb533ac3
4
+ data.tar.gz: ad2b07fadad2698bf9169a0556a3c63422446267c292c27c71e0d5a8e7b5669a
5
5
  SHA512:
6
- metadata.gz: 245aa88c7c415099db251eabf2c6b9e80a64d657cdf4df90e365115e962cbeec76279cab1d4d5dc87de1b6387475c0e6363a2be24c55d21953d4bc852727d869
7
- data.tar.gz: c9a870b1252ca73b2565a4627e29ee5501ce9da6caa88834932d0edee05e45f573a5f7aeae183968e303786615622487188287236b1d12d8234ac992f25e822a
6
+ metadata.gz: 32636372bdbb936f6d3c68a223b1cdd4b9e716522fd526df80b079f1712c77f658f16c3f60d5554f80d53354006e8d11e40a9fbe68c0b4fbd767fe053a9cc8bb
7
+ data.tar.gz: 76b52ddad11c35a1e2be4a6f818e6f2f60f10ad6a74147c43fb05f2689dbc4603c9429437ff6c7cdd9a1cdf398894096adb925f1dd922b117bf509ba12c8ffa4
data/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. Tracking did not begin until version 1.10.
4
4
 
5
+ <a name="1.8.0"></a>
6
+ # [1.8.0] (2022-04-22)
7
+
8
+ - feat: add exponential backoff for sending data [#76](https://github.com/SumoLogic/fluentd-output-sumologic/pull/76)
9
+ - feat(max_request_size): add max_request_size to limit size of requests [#78](https://github.com/SumoLogic/fluentd-output-sumologic/pull/78)
10
+
11
+ <a name="1.7.5"></a>
12
+ # [1.7.5] (2022-04-11)
13
+
14
+ - refactor: add a debug log on sending [#75](https://github.com/SumoLogic/fluentd-output-sumologic/pull/75)
15
+
16
+ <a name="1.7.4"></a>
17
+ # [1.7.4] (2021-04-08)
18
+
19
+ - fix: handle receiver warning messages [#73](https://github.com/SumoLogic/fluentd-output-sumologic/pull/73)
20
+
5
21
  <a name="1.7.3"></a>
6
22
  # [1.7.3] (2021-10-19)
7
23
  - Expose httpclient send_timeout [#66](https://github.com/SumoLogic/fluentd-output-sumologic/pull/68)
data/README.md CHANGED
@@ -38,6 +38,13 @@ Configuration options for fluent.conf are:
38
38
  * `compress_encoding` - Compression encoding format, either `gzip` or `deflate` (default `gzip`)
39
39
  * `custom_fields` - Comma-separated key=value list of fields to apply to every log. [more information](https://help.sumologic.com/Manage/Fields#http-source-fields)
40
40
  * `custom_dimensions` - Comma-separated key=value list of dimensions to apply to every metric. [more information](https://help.sumologic.com/03Send-Data/Sources/02Sources-for-Hosted-Collectors/HTTP-Source/Upload-Metrics-to-an-HTTP-Source#supported-http-headers)
41
+ * `use_internal_retry` - Enable custom retry mechanism. As this is `false` by default due to backward compatibility,
42
+ we recommend to enable it and configure the following parameters (`retry_min_interval`, `retry_max_interval`, `retry_timeout`, `retry_max_times`)
43
+ * `retry_min_interval` - Minimum interval to wait between sending tries (default is `1s`)
44
+ * `retry_max_interval` - Maximum interval to wait between sending tries (default is `5m`)
45
+ * `retry_timeout` - Time after which the data is going to be dropped (default is `72h`) (`0s` means that there is no timeout)
46
+ * `retry_max_times` - Maximum number of retries (default is `0`) (`0` means that there is no max retry times, retries will happen forever)
47
+ * `max_request_size` - Maximum request size (before applying compression). Default is `0k` which means no limit
41
48
 
42
49
  __NOTE:__ <sup>*</sup> [Placeholders](https://docs.fluentd.org/v1.0/articles/buffer-section#placeholders) are supported
43
50
 
@@ -137,6 +144,14 @@ Example
137
144
  }
138
145
  ```
139
146
 
147
+ ## Retry Mechanism
148
+
149
+ `retry_min_interval`, `retry_max_interval`, `retry_timeout`, `retry_max_times` are not the [buffer retries parameters][buffer_retries].
150
+ Due to technical reason, this plugin implements it's own retrying back-off exponential mechanism.
151
+ It is disabled by default, but we recommend to enable it by setting `use_internal_retry` to `true`.
152
+
153
+ [buffer_retries]: https://docs.fluentd.org/configuration/buffer-section#retries-parameters
154
+
140
155
  ### TLS 1.2 Requirement
141
156
 
142
157
  Sumo Logic only accepts connections from clients using TLS version 1.2 or greater. To utilize the content of this repo, ensure that it's running in an execution environment that is configured to use TLS 1.2 or greater.
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |gem|
6
6
  gem.name = "fluent-plugin-sumologic_output"
7
- gem.version = "1.7.5"
7
+ gem.version = "1.8.0"
8
8
  gem.authors = ["Steven Adams", "Frank Reno"]
9
9
  gem.email = ["stevezau@gmail.com", "frank.reno@me.com"]
10
10
  gem.description = %q{Output plugin to SumoLogic HTTP Endpoint}
@@ -157,6 +157,15 @@ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
157
157
  config_param :timestamp_key, :string, :default => 'timestamp'
158
158
  config_param :proxy_uri, :string, :default => nil
159
159
  config_param :disable_cookies, :bool, :default => false
160
+
161
+ config_param :use_internal_retry, :bool, :default => false
162
+ config_param :retry_timeout, :time, :default => 72 * 3600 # 72h
163
+ config_param :retry_max_times, :integer, :default => 0
164
+ config_param :retry_min_interval, :time, :default => 1 # 1s
165
+ config_param :retry_max_interval, :time, :default => 5*60 # 5m
166
+
167
+ config_param :max_request_size, :size, :default => 0
168
+
160
169
  # https://help.sumologic.com/Manage/Fields
161
170
  desc 'Fields string (eg "cluster=payment, service=credit_card") which is going to be added to every log record.'
162
171
  config_param :custom_fields, :string, :default => nil
@@ -245,6 +254,10 @@ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
245
254
  conf['compress_encoding'],
246
255
  log,
247
256
  )
257
+
258
+ if !conf['max_request_size'].nil? && conf['max_request_size'].to_i <= 0
259
+ conf['max_request_size'] = '0'
260
+ end
248
261
  super
249
262
  end
250
263
 
@@ -385,6 +398,7 @@ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
385
398
 
386
399
  end
387
400
 
401
+ chunk_id = "##{chunk.dump_unique_id_hex(chunk.unique_id)}"
388
402
  # Push logs to sumo
389
403
  messages_list.each do |key, messages|
390
404
  source_name, source_category, source_host, fields = key[:source_name], key[:source_category],
@@ -397,18 +411,78 @@ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
397
411
  fields = [fields,@custom_fields].compact.join(",")
398
412
  end
399
413
 
400
- @log.debug { "Sending #{messages.count} #{@data_type} records with source category '#{source_category}', source host '#{source_host}', source name '#{source_name}'." }
401
-
402
- @sumo_conn.publish(
403
- messages.join("\n"),
404
- source_host =source_host,
405
- source_category =source_category,
406
- source_name =source_name,
407
- data_type =@data_type,
408
- metric_data_format =@metric_data_format,
409
- collected_fields =fields,
410
- dimensions =@custom_dimensions
411
- )
414
+ if @max_request_size <= 0
415
+ messages_to_send = [messages]
416
+ else
417
+ messages_to_send = []
418
+ current_message = []
419
+ current_length = 0
420
+ messages.each do |message|
421
+ current_message.push message
422
+ current_length += message.length
423
+
424
+ if current_length > @max_request_size
425
+ messages_to_send.push(current_message)
426
+ current_message = []
427
+ current_length = 0
428
+ end
429
+ current_length += 1 # this is for newline
430
+ end
431
+ if current_message.length > 0
432
+ messages_to_send.push(current_message)
433
+ end
434
+ end
435
+
436
+ messages_to_send.each_with_index do |message, i|
437
+ retries = 0
438
+ start_time = Time.now
439
+ sleep_time = @retry_min_interval
440
+
441
+ while true
442
+ common_log_part = "#{@data_type} records with source category '#{source_category}', source host '#{source_host}', source name '#{source_name}', chunk #{chunk_id}, try #{retries}, batch #{i}"
443
+
444
+ begin
445
+ @log.debug { "Sending #{message.count}; #{common_log_part}" }
446
+
447
+ @sumo_conn.publish(
448
+ message.join("\n"),
449
+ source_host =source_host,
450
+ source_category =source_category,
451
+ source_name =source_name,
452
+ data_type =@data_type,
453
+ metric_data_format =@metric_data_format,
454
+ collected_fields =fields,
455
+ dimensions =@custom_dimensions
456
+ )
457
+ break
458
+ rescue => e
459
+ if !@use_internal_retry
460
+ raise e
461
+ end
462
+ # increment retries
463
+ retries += 1
464
+
465
+ log.warn "error while sending request to sumo: #{e}; #{common_log_part}"
466
+ log.warn_backtrace e.backtrace
467
+
468
+ # drop data if
469
+ # - we reached out the @retry_max_times retries
470
+ # - or we exceeded @retry_timeout
471
+ if (retries >= @retry_max_times && @retry_max_times > 0) || (Time.now > start_time + @retry_timeout && @retry_timeout > 0)
472
+ log.warn "dropping records; #{common_log_part}"
473
+ break
474
+ end
475
+
476
+ log.info "going to retry to send data at #{Time.now + sleep_time}; #{common_log_part}"
477
+ sleep sleep_time
478
+
479
+ sleep_time *= 2
480
+ if sleep_time > @retry_max_interval
481
+ sleep_time = @retry_max_interval
482
+ end
483
+ end
484
+ end
485
+ end
412
486
  end
413
487
 
414
488
  end
@@ -825,4 +825,157 @@ class SumologicOutput < Test::Unit::TestCase
825
825
  end
826
826
  end
827
827
 
828
+ def test_resend
829
+ endpoint = "https://collectors.sumologic.com/v1/receivers/http/1234"
830
+ config = %{
831
+ endpoint #{endpoint}
832
+ retry_min_interval 0s
833
+ retry_max_times 3
834
+ use_internal_retry true
835
+ }
836
+ time = event_time
837
+
838
+ driver = create_driver(config)
839
+ stub_request(:post, endpoint).to_return(
840
+ {status: 500, headers: {content_type: 'application/json'}},
841
+ {status: 200, headers: {content_type: 'application/json'}}
842
+ )
843
+ driver.run do
844
+ driver.feed("test", time, {"message": "test"})
845
+ end
846
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
847
+ body: /\A{"timestamp":\d+.,"message":"test"}\z/,
848
+ times:2
849
+ end
850
+
851
+ def test_resend_failed
852
+ endpoint = "https://collectors.sumologic.com/v1/receivers/http/1234"
853
+ config = %{
854
+ endpoint #{endpoint}
855
+ retry_min_interval 0s
856
+ retry_max_times 15
857
+ use_internal_retry true
858
+ }
859
+ time = event_time
860
+
861
+ driver = create_driver(config)
862
+ stub_request(:post, endpoint).to_return(
863
+ status: 500, headers: {content_type: 'application/json'}
864
+ )
865
+ driver.run do
866
+ driver.feed("test", time, {"message": "test"})
867
+ end
868
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
869
+ body: /\A{"timestamp":\d+.,"message":"test"}\z/,
870
+ times:15
871
+ end
872
+
873
+ def test_resend_forever
874
+ endpoint = "https://collectors.sumologic.com/v1/receivers/http/1234"
875
+ config = %{
876
+ endpoint #{endpoint}
877
+ retry_min_interval 0s
878
+ retry_max_times 0
879
+ retry_timeout 0s
880
+ use_internal_retry true
881
+ }
882
+ time = event_time
883
+
884
+ driver = create_driver(config)
885
+ stub_request(:post, endpoint).to_return(
886
+ *[{status: 500, headers: {content_type: 'application/json'}}]*123,
887
+ {status: 200, headers: {content_type: 'application/json'}}
888
+ )
889
+ driver.run do
890
+ driver.feed("test", time, {"message": "test"})
891
+ end
892
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
893
+ body: /\A{"timestamp":\d+.,"message":"test"}\z/,
894
+ times:124
895
+ end
896
+
897
+ def test_skip_retry
898
+ endpoint = "https://collectors.sumologic.com/v1/receivers/http/1234"
899
+ config = %{
900
+ endpoint #{endpoint}
901
+ }
902
+ time = event_time
903
+
904
+ driver = create_driver(config)
905
+ stub_request(:post, endpoint).to_return(status: 500, headers: {content_type: 'application/json'})
906
+
907
+ exception = assert_raise(RuntimeError) {
908
+ driver.run do
909
+ driver.feed("test", time, {"message": "test"})
910
+ end
911
+ }
912
+ assert_equal("Failed to send data to HTTP Source. 500 - ", exception.message)
913
+ end
914
+
915
+ def test_split_negative_or_zero
916
+ endpoint = "https://collectors.sumologic.com/v1/receivers/http/1234"
917
+
918
+ configs = [
919
+ %{
920
+ endpoint #{endpoint}
921
+ max_request_size -5
922
+ },
923
+ %{
924
+ endpoint #{endpoint}
925
+ max_request_size 0
926
+ }
927
+ ]
928
+
929
+ time = event_time
930
+
931
+ configs.each do |config|
932
+ WebMock.reset_executed_requests!
933
+ driver = create_driver(config)
934
+ stub_request(:post, endpoint).to_return(status: 200, headers: {content_type: 'application/json'})
935
+
936
+ driver.run do
937
+ driver.feed("test", time, {"message": "test"})
938
+ driver.feed("test", time, {"message": "test"})
939
+ driver.feed("test", time, {"message": "test"})
940
+ end
941
+
942
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
943
+ body: /\A{"timestamp":\d+.,"message":"test"}\n{"timestamp":\d+.,"message":"test"}\n{"timestamp":\d+.,"message":"test"}\z/,
944
+ times:1
945
+ end
946
+ end
947
+
948
+ def test_split
949
+ endpoint = "https://collectors.sumologic.com/v1/receivers/http/1234"
950
+
951
+ config = %{
952
+ endpoint #{endpoint}
953
+ max_request_size 80
954
+ }
955
+
956
+ time = event_time
957
+
958
+ WebMock.reset_executed_requests!
959
+ driver = create_driver(config)
960
+ stub_request(:post, endpoint).to_return(status: 200, headers: {content_type: 'application/json'})
961
+
962
+ driver.run do
963
+ driver.feed("test", time, {"message": "test1"})
964
+ driver.feed("test", time, {"message": "test2"})
965
+ driver.feed("test", time, {"message": "test3"})
966
+ driver.feed("test", time, {"message": "test4"})
967
+ driver.feed("test", time, {"message": "test5"})
968
+ end
969
+
970
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
971
+ body: /\A{"timestamp":\d+.,"message":"test1"}\n{"timestamp":\d+.,"message":"test2"}\z/,
972
+ times:1
973
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
974
+ body: /\A{"timestamp":\d+.,"message":"test3"}\n{"timestamp":\d+.,"message":"test4"}\z/,
975
+ times:1
976
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
977
+ body: /\A{"timestamp":\d+.,"message":"test5"}\z/,
978
+ times:1
979
+ end
980
+
828
981
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-sumologic_output
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.5
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Adams
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-04-11 00:00:00.000000000 Z
12
+ date: 2022-04-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler