fluent-plugin-sumologic_output 1.5.0 → 1.7.2

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: 6db47bbad47c3eb7ea578b1e894ddc972336e785c94bb8af47595481b7e934e2
4
- data.tar.gz: 3457257200adc1b655ed1820a5041e29c22531e621aa24a6dd620105ac4559f1
3
+ metadata.gz: c3bf755e8ecd488457805d948614c43b3657de815889dd341091d11f338ad995
4
+ data.tar.gz: 20163f7c5ac543a010e53fce506dbaed10bafe5d46830579a3101558f5b61fa4
5
5
  SHA512:
6
- metadata.gz: cad8b409225fdd0d96402c17a950c0fb67ad61d0f28ac98a252bac23671cee9a3152738c37f916295c116c0396ede9ea874339c8d4278daf81f698060b56f63d
7
- data.tar.gz: 619b7cc028a11d1485b158a08e5f34f00440e5410b14b4283d0dda778f80d22944be9f753275a3028c360e15a69baf437b761a09c7e6b29e2f2c784bf3c0d965
6
+ metadata.gz: 35cf3af9a561fd22e810dea880570007613b7cb9ae87307dd46ea3ff8d9e005b96c9ebf19f1aafd58b6ae4495509f51406b7788029f7fb26144f54b60f22370a
7
+ data.tar.gz: 6b5e6a13ed50d798c4c0f8225e771a2c5977373373aed316cbe1a5369a2af22aef56c86e474aefd6ca847e41c496c287a191c23c1224d2a49075794b420949e4
@@ -2,7 +2,21 @@
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.4.0"></a>
5
+ <a name="1.7.1"></a>
6
+ # [1.7.1] (2020-04-28)
7
+ - Fix configuration for older fluentd versions [#63](https://github.com/SumoLogic/fluentd-output-sumologic/pull/63)
8
+
9
+ <a name="1.7.0"></a>
10
+ # [1.7.0] (2020-04-23)
11
+ - Add option for specifing custom fields for logs: [#56](https://github.com/SumoLogic/fluentd-output-sumologic/pull/56)
12
+ - Add option for specifing custom dimensions for metrics: [#57](https://github.com/SumoLogic/fluentd-output-sumologic/pull/57)
13
+ - Add support for compression: [#58](https://github.com/SumoLogic/fluentd-output-sumologic/pull/58)
14
+
15
+ <a name="1.5.0"></a>
16
+ # [1.5.0] (2019-06-26)
17
+ - Add support for new log format fields: [#49](https://github.com/SumoLogic/fluentd-output-sumologic/pull/49)
18
+
19
+ <a name="1.4.1"></a>
6
20
  # [1.4.1] (2019-03-13)
7
21
 
8
22
  - Add option for sending metrics in Prometheus format [#39](https://github.com/SumoLogic/fluentd-output-sumologic/pull/39)
data/README.md CHANGED
@@ -4,9 +4,6 @@
4
4
 
5
5
  This plugin has been designed to output logs or metrics to [SumoLogic](http://www.sumologic.com) via a [HTTP collector endpoint](http://help.sumologic.com/Send_Data/Sources/02Sources_for_Hosted_Collectors/HTTP_Source)
6
6
 
7
- ## Support
8
- The code in this repository has been developed in collaboration with the Sumo Logic community and is not supported via standard Sumo Logic Support channels. For any issues or questions please submit an issue within the GitHub repository. The maintainers of this project will work directly with the community to answer any questions, address bugs, or review any requests for new features.
9
-
10
7
  ## License
11
8
  Released under Apache 2.0 License.
12
9
 
@@ -36,6 +33,10 @@ Configuration options for fluent.conf are:
36
33
  * `proxy_uri` - Add the `uri` of the `proxy` environment if present.
37
34
  * `metric_data_format` - The format of metrics you will be sending, either `graphite` or `carbon2` or `prometheus` (Default is `graphite `)
38
35
  * `disable_cookies` - Option to disable cookies on the HTTP Client. (Default is `false `)
36
+ * `compress` - Option to enable compression (default `false`)
37
+ * `compress_encoding` - Compression encoding format, either `gzip` or `deflate` (default `gzip`)
38
+ * `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)
39
+ * `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)
39
40
 
40
41
  __NOTE:__ <sup>*</sup> [Placeholders](https://docs.fluentd.org/v1.0/articles/buffer-section#placeholders) are supported
41
42
 
@@ -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.5.0"
7
+ gem.version = "1.7.2"
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}
@@ -2,30 +2,47 @@ require 'fluent/plugin/output'
2
2
  require 'net/https'
3
3
  require 'yajl'
4
4
  require 'httpclient'
5
+ require 'zlib'
6
+ require 'stringio'
5
7
 
6
8
  class SumologicConnection
7
9
 
8
10
  attr_reader :http
9
11
 
10
- def initialize(endpoint, verify_ssl, connect_timeout, proxy_uri, disable_cookies)
12
+ COMPRESS_DEFLATE = 'deflate'
13
+ COMPRESS_GZIP = 'gzip'
14
+
15
+ def initialize(endpoint, verify_ssl, connect_timeout, proxy_uri, disable_cookies, sumo_client, compress_enabled, compress_encoding)
11
16
  @endpoint = endpoint
17
+ @sumo_client = sumo_client
12
18
  create_http_client(verify_ssl, connect_timeout, proxy_uri, disable_cookies)
19
+ @compress = compress_enabled
20
+ @compress_encoding = (compress_encoding ||= COMPRESS_GZIP).downcase
21
+
22
+ unless [COMPRESS_DEFLATE, COMPRESS_GZIP].include? @compress_encoding
23
+ raise "Invalid compression encoding #{@compress_encoding} must be gzip or deflate"
24
+ end
13
25
  end
14
26
 
15
- def publish(raw_data, source_host=nil, source_category=nil, source_name=nil, data_type, metric_data_type, collected_fields)
16
- response = http.post(@endpoint, raw_data, request_headers(source_host, source_category, source_name, data_type, metric_data_type, collected_fields))
27
+ def publish(raw_data, source_host=nil, source_category=nil, source_name=nil, data_type, metric_data_type, collected_fields, dimensions)
28
+ response = http.post(@endpoint, compress(raw_data), request_headers(source_host, source_category, source_name, data_type, metric_data_type, collected_fields, dimensions))
17
29
  unless response.ok?
18
30
  raise RuntimeError, "Failed to send data to HTTP Source. #{response.code} - #{response.body}"
19
31
  end
20
32
  end
21
33
 
22
- def request_headers(source_host, source_category, source_name, data_type, metric_data_format, collected_fields)
34
+ def request_headers(source_host, source_category, source_name, data_type, metric_data_format, collected_fields, dimensions)
23
35
  headers = {
24
36
  'X-Sumo-Name' => source_name,
25
37
  'X-Sumo-Category' => source_category,
26
38
  'X-Sumo-Host' => source_host,
27
- 'X-Sumo-Client' => 'fluentd-output'
39
+ 'X-Sumo-Client' => @sumo_client,
28
40
  }
41
+
42
+ if @compress
43
+ headers['Content-Encoding'] = @compress_encoding
44
+ end
45
+
29
46
  if data_type == 'metrics'
30
47
  case metric_data_format
31
48
  when 'graphite'
@@ -37,6 +54,10 @@ class SumologicConnection
37
54
  else
38
55
  raise RuntimeError, "Invalid #{metric_data_format}, must be graphite or carbon2 or prometheus"
39
56
  end
57
+
58
+ unless dimensions.nil?
59
+ headers['X-Sumo-Dimensions'] = dimensions
60
+ end
40
61
  end
41
62
  unless collected_fields.nil?
42
63
  headers['X-Sumo-Fields'] = collected_fields
@@ -56,6 +77,29 @@ class SumologicConnection
56
77
  @http.cookie_manager = nil
57
78
  end
58
79
  end
80
+
81
+ def compress(content)
82
+ if @compress
83
+ if @compress_encoding == COMPRESS_GZIP
84
+ result = gzip(content)
85
+ result.bytes.to_a.pack("c*")
86
+ else
87
+ Zlib::Deflate.deflate(content)
88
+ end
89
+ else
90
+ content
91
+ end
92
+ end # def compress
93
+
94
+ def gzip(content)
95
+ stream = StringIO.new("w")
96
+ stream.set_encoding("ASCII")
97
+ gz = Zlib::GzipWriter.new(stream)
98
+ gz.mtime=1 # Ensure that for same content there is same output
99
+ gz.write(content)
100
+ gz.close
101
+ stream.string.bytes.to_a.pack("c*")
102
+ end # def gzip
59
103
  end
60
104
 
61
105
  class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
@@ -86,6 +130,18 @@ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
86
130
  config_param :timestamp_key, :string, :default => 'timestamp'
87
131
  config_param :proxy_uri, :string, :default => nil
88
132
  config_param :disable_cookies, :bool, :default => false
133
+ # https://help.sumologic.com/Manage/Fields
134
+ desc 'Fields string (eg "cluster=payment, service=credit_card") which is going to be added to every log record.'
135
+ config_param :custom_fields, :string, :default => nil
136
+ desc 'Name of sumo client which is send as X-Sumo-Client header'
137
+ config_param :sumo_client, :string, :default => 'fluentd-output'
138
+ desc 'Compress payload'
139
+ config_param :compress, :bool, :default => false
140
+ desc 'Encoding method of compresssion (either gzip or deflate)'
141
+ config_param :compress_encoding, :string, :default => SumologicConnection::COMPRESS_GZIP
142
+ # https://help.sumologic.com/03Send-Data/Sources/02Sources-for-Hosted-Collectors/HTTP-Source/Upload-Metrics-to-an-HTTP-Source#supported-http-headers
143
+ desc 'Dimensions string (eg "cluster=payment, service=credit_card") which is going to be added to every metric record.'
144
+ config_param :custom_dimensions, :string, :default => nil
89
145
 
90
146
  config_section :buffer do
91
147
  config_set_default :@type, DEFAULT_BUFFER_TYPE
@@ -129,7 +185,37 @@ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
129
185
  end
130
186
  end
131
187
 
132
- @sumo_conn = SumologicConnection.new(conf['endpoint'], conf['verify_ssl'], conf['open_timeout'].to_i, conf['proxy_uri'], conf['disable_cookies'])
188
+ conf['custom_fields'] = validate_key_value_pairs(conf['custom_fields'])
189
+ if conf['custom_fields'].nil?
190
+ conf.delete 'custom_fields'
191
+ end
192
+ unless conf['custom_fields']
193
+ @log.debug "Custom fields: #{conf['custom_fields']}"
194
+ end
195
+
196
+ conf['custom_dimensions'] = validate_key_value_pairs(conf['custom_dimensions'])
197
+ if conf['custom_dimensions'].nil?
198
+ conf.delete 'custom_dimensions'
199
+ end
200
+ unless conf['custom_dimensions']
201
+ @log.debug "Custom dimensions: #{conf['custom_dimensions']}"
202
+ end
203
+
204
+ # For some reason default is set incorrectly in unit-tests
205
+ if conf['sumo_client'].nil? || conf['sumo_client'].strip.length == 0
206
+ conf['sumo_client'] = 'fluentd-output'
207
+ end
208
+
209
+ @sumo_conn = SumologicConnection.new(
210
+ conf['endpoint'],
211
+ conf['verify_ssl'],
212
+ conf['open_timeout'].to_i,
213
+ conf['proxy_uri'],
214
+ conf['disable_cookies'],
215
+ conf['sumo_client'],
216
+ conf['compress'],
217
+ conf['compress_encoding']
218
+ )
133
219
  super
134
220
  end
135
221
 
@@ -195,7 +281,11 @@ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
195
281
  source_host = sumo_metadata['host'] || @source_host
196
282
  source_host = extract_placeholders(source_host, chunk) unless source_host.nil?
197
283
 
198
- "#{source_name}:#{source_category}:#{source_host}"
284
+ fields = sumo_metadata['fields'] || ""
285
+ fields = extract_placeholders(fields, chunk) unless fields.nil?
286
+
287
+ { :source_name => "#{source_name}", :source_category => "#{source_category}",
288
+ :source_host => "#{source_host}", :fields => "#{fields}" }
199
289
  end
200
290
 
201
291
  # Convert timestamp to 13 digit epoch if necessary
@@ -203,28 +293,22 @@ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
203
293
  time.to_s.length == 13 ? time : time * 1000
204
294
  end
205
295
 
206
- def sumo_fields(sumo_metadata)
207
- fields = sumo_metadata['fields'] || ""
208
- Hash[
209
- fields.split(',').map do |pair|
210
- k, v = pair.split('=', 2)
211
- [k, v]
212
- end
213
- ]
214
- end
296
+ # Convert log to string and strip it
297
+ def log_to_str(log)
298
+ if log.is_a?(Array) or log.is_a?(Hash)
299
+ log = Yajl.dump(log)
300
+ end
215
301
 
216
- def dump_collected_fields(log_fields)
217
- if log_fields.nil?
218
- log_fields
219
- else
220
- log_fields.map{|k,v| "#{k}=#{v}"}.join(',')
302
+ unless log.nil?
303
+ log.strip!
221
304
  end
305
+
306
+ return log
222
307
  end
223
308
 
224
309
  # This method is called every flush interval. Write the buffer chunk
225
310
  def write(chunk)
226
311
  messages_list = {}
227
- log_fields = nil
228
312
 
229
313
  # Sort messages
230
314
  chunk.msgpack_each do |time, record|
@@ -242,17 +326,13 @@ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
242
326
  when 'logs'
243
327
  case log_format
244
328
  when 'text'
245
- log = record[@log_key]
246
- unless log.nil?
247
- log.strip!
248
- end
329
+ log = log_to_str(record[@log_key])
249
330
  when 'json_merge'
250
331
  if @add_timestamp
251
332
  record = { @timestamp_key => sumo_timestamp(time) }.merge(record)
252
333
  end
253
334
  log = dump_log(merge_json(record))
254
335
  when 'fields'
255
- log_fields = sumo_fields(sumo_metadata)
256
336
  if @add_timestamp
257
337
  record = { @timestamp_key => sumo_timestamp(time) }.merge(record)
258
338
  end
@@ -264,10 +344,7 @@ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
264
344
  log = dump_log(record)
265
345
  end
266
346
  when 'metrics'
267
- log = record[@log_key]
268
- unless log.nil?
269
- log.strip!
270
- end
347
+ log = log_to_str(record[@log_key])
271
348
  end
272
349
 
273
350
  unless log.nil?
@@ -282,7 +359,16 @@ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
282
359
 
283
360
  # Push logs to sumo
284
361
  messages_list.each do |key, messages|
285
- source_name, source_category, source_host = key.split(':')
362
+ source_name, source_category, source_host, fields = key[:source_name], key[:source_category],
363
+ key[:source_host], key[:fields]
364
+
365
+ # Merge custom and record fields
366
+ if fields.nil? || fields.strip.length == 0
367
+ fields = @custom_fields
368
+ else
369
+ fields = [fields,@custom_fields].compact.join(",")
370
+ end
371
+
286
372
  @sumo_conn.publish(
287
373
  messages.join("\n"),
288
374
  source_host =source_host,
@@ -290,9 +376,26 @@ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
290
376
  source_name =source_name,
291
377
  data_type =@data_type,
292
378
  metric_data_format =@metric_data_format,
293
- collected_fields =dump_collected_fields(log_fields)
379
+ collected_fields =fields,
380
+ dimensions =@custom_dimensions
294
381
  )
295
382
  end
296
383
 
297
384
  end
385
+
386
+ def validate_key_value_pairs(fields)
387
+ if fields.nil?
388
+ return fields
389
+ end
390
+
391
+ fields = fields.split(",").select { |field|
392
+ field.split('=').length == 2
393
+ }
394
+
395
+ if fields.length == 0
396
+ return nil
397
+ end
398
+
399
+ fields.join(',')
400
+ end
298
401
  end
@@ -72,6 +72,8 @@ class SumologicOutput < Test::Unit::TestCase
72
72
  assert_equal instance.timestamp_key, 'timestamp'
73
73
  assert_equal instance.proxy_uri, nil
74
74
  assert_equal instance.disable_cookies, false
75
+ assert_equal instance.sumo_client, 'fluentd-output'
76
+ assert_equal instance.compress_encoding, 'gzip'
75
77
  end
76
78
 
77
79
  def test_emit_text
@@ -95,6 +97,28 @@ class SumologicOutput < Test::Unit::TestCase
95
97
  times:1
96
98
  end
97
99
 
100
+ def test_emit_text_custom_sumo_client
101
+ config = %{
102
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
103
+ log_format text
104
+ source_category test
105
+ source_host test
106
+ source_name test
107
+ sumo_client 'fluentd-custom-sender'
108
+
109
+ }
110
+ driver = create_driver(config)
111
+ time = event_time
112
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
113
+ driver.run do
114
+ driver.feed("output.test", time, {'foo' => 'bar', 'message' => 'test'})
115
+ end
116
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
117
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-custom-sender', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
118
+ body: "test",
119
+ times:1
120
+ end
121
+
98
122
  def test_emit_json
99
123
  config = %{
100
124
  endpoint https://collectors.sumologic.com/v1/receivers/http/1234
@@ -267,6 +291,78 @@ class SumologicOutput < Test::Unit::TestCase
267
291
  times:1
268
292
  end
269
293
 
294
+ def test_emit_with_sumo_metadata_with_fields_and_custom_fields_fields_format
295
+ config = %{
296
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
297
+ log_format fields
298
+ custom_fields "lorem=ipsum,dolor=amet"
299
+ }
300
+ driver = create_driver(config)
301
+ time = event_time
302
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
303
+ ENV['HOST'] = "foo"
304
+ driver.run do
305
+ driver.feed("output.test", time, {'foo' => 'shark', 'message' => 'test', '_sumo_metadata' => {
306
+ "host": "#{ENV['HOST']}",
307
+ "source": "${tag}",
308
+ "category": "test",
309
+ "fields": "foo=bar, sumo = logic"
310
+ }})
311
+ end
312
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
313
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'foo', 'X-Sumo-Name'=>'output.test', 'X-Sumo-Fields' => 'foo=bar, sumo = logic,lorem=ipsum,dolor=amet'},
314
+ body: /\A{"timestamp":\d+.,"foo":"shark","message":"test"}\z/,
315
+ times:1
316
+ end
317
+
318
+ def test_emit_with_sumo_metadata_with_fields_and_empty_custom_fields_fields_format
319
+ config = %{
320
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
321
+ log_format fields
322
+ custom_fields ""
323
+ }
324
+ driver = create_driver(config)
325
+ time = event_time
326
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
327
+ ENV['HOST'] = "foo"
328
+ driver.run do
329
+ driver.feed("output.test", time, {'foo' => 'shark', 'message' => 'test', '_sumo_metadata' => {
330
+ "host": "#{ENV['HOST']}",
331
+ "source": "${tag}",
332
+ "category": "test",
333
+ "fields": "foo=bar, sumo = logic"
334
+ }})
335
+ end
336
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
337
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'foo', 'X-Sumo-Name'=>'output.test', 'X-Sumo-Fields' => 'foo=bar, sumo = logic'},
338
+ body: /\A{"timestamp":\d+.,"foo":"shark","message":"test"}\z/,
339
+ times:1
340
+ end
341
+
342
+ def test_emit_with_sumo_metadata_with_empty_fields_and_custom_fields_fields_format
343
+ config = %{
344
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
345
+ log_format fields
346
+ custom_fields "lorem=ipsum,invalid"
347
+ }
348
+ driver = create_driver(config)
349
+ time = event_time
350
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
351
+ ENV['HOST'] = "foo"
352
+ driver.run do
353
+ driver.feed("output.test", time, {'foo' => 'shark', 'message' => 'test', '_sumo_metadata' => {
354
+ "host": "#{ENV['HOST']}",
355
+ "source": "${tag}",
356
+ "category": "test",
357
+ "fields": ""
358
+ }})
359
+ end
360
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
361
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'foo', 'X-Sumo-Name'=>'output.test', 'X-Sumo-Fields' => 'lorem=ipsum'},
362
+ body: /\A{"timestamp":\d+.,"foo":"shark","message":"test"}\z/,
363
+ times:1
364
+ end
365
+
270
366
  def test_emit_with_sumo_metadata
271
367
  config = %{
272
368
  endpoint https://collectors.sumologic.com/v1/receivers/http/1234
@@ -394,4 +490,227 @@ class SumologicOutput < Test::Unit::TestCase
394
490
  times:1
395
491
  end
396
492
 
397
- end
493
+ def test_emit_prometheus_with_custom_dimensions
494
+ config = %{
495
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
496
+ data_type metrics
497
+ metric_data_format prometheus
498
+ source_category test
499
+ source_host test
500
+ source_name test
501
+ custom_dimensions 'foo=bar, dolor=sit,amet,test'
502
+ }
503
+ driver = create_driver(config)
504
+ time = event_time
505
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
506
+ driver.run do
507
+ driver.feed("output.test", time, {'message' =>'cpu{cluster="prod", node="lb-1"} 87.2 1501753030'})
508
+ end
509
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
510
+ headers: {
511
+ 'X-Sumo-Category'=>'test',
512
+ 'X-Sumo-Client'=>'fluentd-output',
513
+ 'X-Sumo-Host'=>'test',
514
+ 'X-Sumo-Name'=>'test',
515
+ 'X-Sumo-Dimensions'=>'foo=bar, dolor=sit',
516
+ 'Content-Type'=>'application/vnd.sumologic.prometheus'},
517
+ body: 'cpu{cluster="prod", node="lb-1"} 87.2 1501753030',
518
+ times:1
519
+ end
520
+
521
+ def test_emit_prometheus_with_empty_custom_metadata
522
+ config = %{
523
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
524
+ data_type metrics
525
+ metric_data_format prometheus
526
+ source_category test
527
+ source_host test
528
+ source_name test
529
+ custom_metadata " "
530
+ }
531
+ driver = create_driver(config)
532
+ time = event_time
533
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
534
+ driver.run do
535
+ driver.feed("output.test", time, {'message' =>'cpu{cluster="prod", node="lb-1"} 87.2 1501753030'})
536
+ end
537
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
538
+ headers: {
539
+ 'X-Sumo-Category'=>'test',
540
+ 'X-Sumo-Client'=>'fluentd-output',
541
+ 'X-Sumo-Host'=>'test',
542
+ 'X-Sumo-Name'=>'test',
543
+ 'Content-Type'=>'application/vnd.sumologic.prometheus'},
544
+ body: 'cpu{cluster="prod", node="lb-1"} 87.2 1501753030',
545
+ times:1
546
+ end
547
+
548
+ def test_batching_same_headers
549
+ config = %{
550
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
551
+ log_format json
552
+ source_category test
553
+ source_host test
554
+ source_name test
555
+ }
556
+ driver = create_driver(config)
557
+ time = event_time
558
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
559
+ driver.run do
560
+ driver.feed("output.test", time, {'message' => 'test1'})
561
+ driver.feed("output.test", time, {'message' => 'test2'})
562
+ end
563
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
564
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
565
+ body: /\A{"timestamp":\d+.,"message":"test1"}\n{"timestamp":\d+.,"message":"test2"}\z/,
566
+ times:1
567
+ end
568
+
569
+ def test_batching_different_headers
570
+ config = %{
571
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
572
+ log_format json
573
+ source_category test
574
+ source_host test
575
+ source_name test
576
+ }
577
+ driver = create_driver(config)
578
+ time = event_time
579
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
580
+ driver.run do
581
+ driver.feed("output.test", time, {'message' => 'test1', '_sumo_metadata' => {"category": "cat1"}})
582
+ driver.feed("output.test", time, {'message' => 'test2', '_sumo_metadata' => {"category": "cat2"}})
583
+ end
584
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
585
+ headers: {'X-Sumo-Category'=>'cat1', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
586
+ body: /\A{"timestamp":\d+.,"message":"test1"}\z/,
587
+ times:1
588
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
589
+ headers: {'X-Sumo-Category'=>'cat2', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
590
+ body: /\A{"timestamp":\d+.,"message":"test2"}\z/,
591
+ times:1
592
+ end
593
+
594
+ def test_batching_different_fields
595
+ config = %{
596
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
597
+ log_format fields
598
+ source_category test
599
+ source_host test
600
+ source_name test
601
+ }
602
+ driver = create_driver(config)
603
+ time = event_time
604
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
605
+ driver.run do
606
+ driver.feed("output.test", time, {'message' => 'test1'})
607
+ driver.feed("output.test", time, {'message' => 'test2', '_sumo_metadata' => {"fields": "foo=bar"}})
608
+ driver.feed("output.test", time, {'message' => 'test3', '_sumo_metadata' => {"fields": "foo=bar,sumo=logic"}})
609
+ driver.feed("output.test", time, {'message' => 'test4', '_sumo_metadata' => {"fields": "foo=bar,master_url=https://100.64.0.1:443"}})
610
+ end
611
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
612
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
613
+ body: /\A{"timestamp":\d+.,"message":"test1"}\z/,
614
+ times:1
615
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
616
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test', 'X-Sumo-Fields' => 'foo=bar'},
617
+ body: /\A{"timestamp":\d+.,"message":"test2"}\z/,
618
+ times:1
619
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
620
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test', 'X-Sumo-Fields' => 'foo=bar,sumo=logic'},
621
+ body: /\A{"timestamp":\d+.,"message":"test3"}\z/,
622
+ times:1
623
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
624
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test', 'X-Sumo-Fields' => 'foo=bar,master_url=https://100.64.0.1:443'},
625
+ body: /\A{"timestamp":\d+.,"message":"test4"}\z/,
626
+ times:1
627
+ end
628
+
629
+ def test_emit_json_merge_timestamp_compress_deflate
630
+ config = %{
631
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
632
+ log_format json_merge
633
+ source_category test
634
+ source_host test
635
+ source_name test
636
+ compress true
637
+ compress_encoding deflate
638
+
639
+ }
640
+ driver = create_driver(config)
641
+ time = event_time
642
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
643
+ driver.run do
644
+ driver.feed("output.test", time, {'message' => '{"timestamp":123}'})
645
+ end
646
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
647
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test', 'Content-Encoding'=>'deflate'},
648
+ body: "\x78\x9c\xab\x56\x2a\xc9\xcc\x4d\x2d\x2e\x49\xcc\x2d\x50\xb2\x32\x34\x32\xae\x05\x00\x38\xb0\x05\xe1".force_encoding("ASCII-8BIT"),
649
+ times:1
650
+ end
651
+
652
+ def test_emit_json_merge_timestamp_compress_gzip
653
+ config = %{
654
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
655
+ log_format json_merge
656
+ source_category test
657
+ source_host test
658
+ source_name test
659
+ compress true
660
+
661
+ }
662
+ driver = create_driver(config)
663
+ time = event_time
664
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
665
+ driver.run do
666
+ driver.feed("output.test", time, {'message' => '{"timestamp":1234}'})
667
+ end
668
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
669
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test', 'Content-Encoding'=>'gzip'},
670
+ body: "\x1f\x8b\x08\x00\x01\x00\x00\x00\x00\x03\xab\x56\x2a\xc9\xcc\x4d\x2d\x2e\x49\xcc\x2d\x50\xb2\x32\x34\x32\x36\xa9\x05\x00\xfe\x53\xbe\x14\x12\x00\x00\x00".force_encoding("ASCII-8BIT"),
671
+ times:1
672
+ end
673
+
674
+ def test_emit_text_from_array
675
+ config = %{
676
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
677
+ log_format text
678
+ source_category test
679
+ source_host test
680
+ source_name test
681
+
682
+ }
683
+ driver = create_driver(config)
684
+ time = event_time
685
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
686
+ driver.run do
687
+ driver.feed("output.test", time, {'foo' => 'bar', 'message' => ['test', 'test2']})
688
+ end
689
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
690
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
691
+ body: '["test","test2"]',
692
+ times:1
693
+ end
694
+
695
+ def test_emit_text_from_dict
696
+ config = %{
697
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
698
+ log_format text
699
+ source_category test
700
+ source_host test
701
+ source_name test
702
+
703
+ }
704
+ driver = create_driver(config)
705
+ time = event_time
706
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
707
+ driver.run do
708
+ driver.feed("output.test", time, {'foo' => 'bar', 'message' => {'test': 'test2', 'test3': 'test4'}})
709
+ end
710
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
711
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
712
+ body: '{"test":"test2","test3":"test4"}',
713
+ times:1
714
+ end
715
+
716
+ 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.5.0
4
+ version: 1.7.2
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: 2019-06-26 00:00:00.000000000 Z
12
+ date: 2020-11-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -134,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
134
  - !ruby/object:Gem::Version
135
135
  version: '0'
136
136
  requirements: []
137
- rubygems_version: 3.0.4
137
+ rubygems_version: 3.0.8
138
138
  signing_key:
139
139
  specification_version: 4
140
140
  summary: Output plugin to SumoLogic HTTP Endpoint