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 +4 -4
- data/CHANGELOG.md +15 -1
- data/README.md +4 -3
- data/fluent-plugin-sumologic_output.gemspec +1 -1
- data/lib/fluent/plugin/out_sumologic.rb +136 -33
- data/test/plugin/test_out_sumologic.rb +320 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3bf755e8ecd488457805d948614c43b3657de815889dd341091d11f338ad995
|
4
|
+
data.tar.gz: 20163f7c5ac543a010e53fce506dbaed10bafe5d46830579a3101558f5b61fa4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35cf3af9a561fd22e810dea880570007613b7cb9ae87307dd46ea3ff8d9e005b96c9ebf19f1aafd58b6ae4495509f51406b7788029f7fb26144f54b60f22370a
|
7
|
+
data.tar.gz: 6b5e6a13ed50d798c4c0f8225e771a2c5977373373aed316cbe1a5369a2af22aef56c86e474aefd6ca847e41c496c287a191c23c1224d2a49075794b420949e4
|
data/CHANGELOG.md
CHANGED
@@ -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.
|
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.
|
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
|
-
|
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' =>
|
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
|
-
|
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
|
-
"
|
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
|
-
|
207
|
-
|
208
|
-
Hash
|
209
|
-
|
210
|
-
|
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
|
-
|
217
|
-
|
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
|
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 =
|
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
|
-
|
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.
|
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:
|
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.
|
137
|
+
rubygems_version: 3.0.8
|
138
138
|
signing_key:
|
139
139
|
specification_version: 4
|
140
140
|
summary: Output plugin to SumoLogic HTTP Endpoint
|