fluent-plugin-cloudwatch-logs-foxtrot9 0.0.1
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 +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/ISSUE_TEMPLATE.md +21 -0
- data/LICENSE.txt +22 -0
- data/README.md +368 -0
- data/Rakefile +10 -0
- data/example/fluentd.conf +23 -0
- data/fluent-plugin-cloudwatch-logs-foxtrot9.gemspec +28 -0
- data/lib/fluent/plugin/cloudwatch/logs.rb +11 -0
- data/lib/fluent/plugin/cloudwatch/logs/version.rb +9 -0
- data/lib/fluent/plugin/in_cloudwatch_logs.rb +203 -0
- data/lib/fluent/plugin/out_cloudwatch_logs.rb +473 -0
- data/test/plugin/test_in_cloudwatch_logs.rb +524 -0
- data/test/plugin/test_out_cloudwatch_logs.rb +757 -0
- data/test/test_helper.rb +106 -0
- metadata +161 -0
@@ -0,0 +1,757 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'test_helper'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'fluent/test/driver/output'
|
5
|
+
require 'fluent/test/helpers'
|
6
|
+
require 'fluent/plugin/out_cloudwatch_logs'
|
7
|
+
|
8
|
+
class CloudwatchLogsOutputTest < Test::Unit::TestCase
|
9
|
+
include CloudwatchLogsTestHelper
|
10
|
+
include Fluent::Test::Helpers
|
11
|
+
|
12
|
+
def setup
|
13
|
+
Fluent::Test.setup
|
14
|
+
end
|
15
|
+
|
16
|
+
sub_test_case "configure" do
|
17
|
+
def test_configure
|
18
|
+
d = create_driver(<<-EOC)
|
19
|
+
@type cloudwatch_logs
|
20
|
+
aws_key_id test_id
|
21
|
+
aws_sec_key test_key
|
22
|
+
region us-east-1
|
23
|
+
log_group_name test_group
|
24
|
+
log_stream_name test_stream
|
25
|
+
auto_create_stream false
|
26
|
+
log_group_aws_tags { "tagkey": "tagvalue", "tagkey_2": "tagvalue_2"}
|
27
|
+
retention_in_days 5
|
28
|
+
message_keys fluentd, aws, cloudwatch
|
29
|
+
EOC
|
30
|
+
|
31
|
+
assert_equal('test_id', d.instance.aws_key_id)
|
32
|
+
assert_equal('test_key', d.instance.aws_sec_key)
|
33
|
+
assert_equal('us-east-1', d.instance.region)
|
34
|
+
assert_equal('test_group', d.instance.log_group_name)
|
35
|
+
assert_equal('test_stream', d.instance.log_stream_name)
|
36
|
+
assert_equal(false, d.instance.auto_create_stream)
|
37
|
+
assert_equal("tagvalue", d.instance.log_group_aws_tags.fetch("tagkey"))
|
38
|
+
assert_equal("tagvalue_2", d.instance.log_group_aws_tags.fetch("tagkey_2"))
|
39
|
+
assert_equal(5, d.instance.retention_in_days)
|
40
|
+
assert_equal(:yajl, d.instance.json_handler)
|
41
|
+
assert_equal(["fluentd","aws","cloudwatch"], d.instance.message_keys)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
sub_test_case "real world" do
|
46
|
+
def setup
|
47
|
+
omit if ENV["CI"] == "true"
|
48
|
+
end
|
49
|
+
|
50
|
+
def teardown
|
51
|
+
return if ENV["CI"] == "true"
|
52
|
+
clear_log_group
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_write
|
56
|
+
new_log_stream
|
57
|
+
|
58
|
+
d = create_driver
|
59
|
+
time = event_time
|
60
|
+
d.run(default_tag: fluentd_tag, flush: true) do
|
61
|
+
d.feed(time, {'cloudwatch' => 'logs1'})
|
62
|
+
# Addition converts EventTime to seconds
|
63
|
+
d.feed(time + 1, {'cloudwatch' => 'logs2'})
|
64
|
+
end
|
65
|
+
|
66
|
+
sleep 10
|
67
|
+
|
68
|
+
logs = d.logs
|
69
|
+
events = get_log_events
|
70
|
+
assert_equal(2, events.size)
|
71
|
+
assert_equal((time.to_f * 1000).floor, events[0].timestamp)
|
72
|
+
assert_equal('{"cloudwatch":"logs1"}', events[0].message)
|
73
|
+
assert_equal((time.to_i + 1) * 1000, events[1].timestamp)
|
74
|
+
assert_equal('{"cloudwatch":"logs2"}', events[1].message)
|
75
|
+
|
76
|
+
assert(logs.any?{|log| log.include?("Called PutLogEvents API") })
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_write_utf8
|
80
|
+
new_log_stream
|
81
|
+
|
82
|
+
d = create_driver
|
83
|
+
time = event_time
|
84
|
+
d.run(default_tag: fluentd_tag) do
|
85
|
+
d.feed(time, { 'cloudwatch' => 'これは日本語です'.force_encoding('UTF-8')})
|
86
|
+
end
|
87
|
+
|
88
|
+
sleep 10
|
89
|
+
|
90
|
+
events = get_log_events
|
91
|
+
assert_equal(1, events.size)
|
92
|
+
assert_equal((time.to_f * 1000).floor, events[0].timestamp)
|
93
|
+
assert_equal('{"cloudwatch":"これは日本語です"}', events[0].message)
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_write_24h_apart
|
97
|
+
new_log_stream
|
98
|
+
|
99
|
+
d = create_driver(<<-EOC)
|
100
|
+
#{default_config}
|
101
|
+
log_group_name #{log_group_name}
|
102
|
+
log_stream_name #{log_stream_name}
|
103
|
+
utc
|
104
|
+
EOC
|
105
|
+
time = event_time
|
106
|
+
d.run(default_tag: fluentd_tag) do
|
107
|
+
d.feed(time - 60 * 60 * 25, {'cloudwatch' => 'logs0'})
|
108
|
+
d.feed(time, {'cloudwatch' => 'logs1'})
|
109
|
+
d.feed(time + 1, {'cloudwatch' => 'logs2'})
|
110
|
+
end
|
111
|
+
|
112
|
+
sleep 10
|
113
|
+
|
114
|
+
events = get_log_events
|
115
|
+
assert_equal(3, events.size)
|
116
|
+
assert_equal((time.to_i - 60 * 60 * 25) * 1000, events[0].timestamp)
|
117
|
+
assert_equal('{"cloudwatch":"logs0"}', events[0].message)
|
118
|
+
assert_equal((time.to_f * 1000).floor, events[1].timestamp)
|
119
|
+
assert_equal('{"cloudwatch":"logs1"}', events[1].message)
|
120
|
+
assert_equal((time.to_i + 1) * 1000, events[2].timestamp)
|
121
|
+
assert_equal('{"cloudwatch":"logs2"}', events[2].message)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_write_with_message_keys
|
125
|
+
new_log_stream
|
126
|
+
|
127
|
+
d = create_driver(<<-EOC)
|
128
|
+
#{default_config}
|
129
|
+
message_keys message,cloudwatch
|
130
|
+
log_group_name #{log_group_name}
|
131
|
+
log_stream_name #{log_stream_name}
|
132
|
+
EOC
|
133
|
+
|
134
|
+
time = event_time
|
135
|
+
d.run(default_tag: fluentd_tag) do
|
136
|
+
d.feed(time, {'cloudwatch' => 'logs1', 'message' => 'message1'})
|
137
|
+
d.feed(time + 1, {'cloudwatch' => 'logs2', 'message' => 'message2'})
|
138
|
+
end
|
139
|
+
|
140
|
+
sleep 10
|
141
|
+
|
142
|
+
events = get_log_events
|
143
|
+
assert_equal(2, events.size)
|
144
|
+
assert_equal((time.to_f * 1000).floor, events[0].timestamp)
|
145
|
+
assert_equal('message1 logs1', events[0].message)
|
146
|
+
assert_equal((time.to_i + 1) * 1000, events[1].timestamp)
|
147
|
+
assert_equal('message2 logs2', events[1].message)
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_write_with_max_message_length
|
151
|
+
new_log_stream
|
152
|
+
|
153
|
+
d = create_driver(<<-EOC)
|
154
|
+
#{default_config}
|
155
|
+
message_keys message,cloudwatch
|
156
|
+
max_message_length 10
|
157
|
+
log_group_name #{log_group_name}
|
158
|
+
log_stream_name #{log_stream_name}
|
159
|
+
EOC
|
160
|
+
|
161
|
+
time = event_time
|
162
|
+
d.run(default_tag: fluentd_tag) do
|
163
|
+
d.feed(time, {'cloudwatch' => 'logs1', 'message' => 'message1'})
|
164
|
+
d.feed(time + 1, {'cloudwatch' => 'logs2', 'message' => 'message2'})
|
165
|
+
end
|
166
|
+
|
167
|
+
sleep 10
|
168
|
+
|
169
|
+
events = get_log_events
|
170
|
+
assert_equal(2, events.size)
|
171
|
+
assert_equal((time.to_f * 1000).floor, events[0].timestamp)
|
172
|
+
assert_equal('message1 l', events[0].message)
|
173
|
+
assert_equal((time.to_i + 1) * 1000, events[1].timestamp)
|
174
|
+
assert_equal('message2 l', events[1].message)
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_write_use_tag_as_group
|
178
|
+
new_log_stream
|
179
|
+
|
180
|
+
d = create_driver(<<-EOC)
|
181
|
+
#{default_config}
|
182
|
+
message_keys message,cloudwatch
|
183
|
+
use_tag_as_group true
|
184
|
+
log_stream_name #{log_stream_name}
|
185
|
+
EOC
|
186
|
+
|
187
|
+
time = event_time
|
188
|
+
d.run(default_tag: fluentd_tag) do
|
189
|
+
d.feed(time, {'cloudwatch' => 'logs1', 'message' => 'message1'})
|
190
|
+
d.feed(time + 1, {'cloudwatch' => 'logs2', 'message' => 'message2'})
|
191
|
+
end
|
192
|
+
|
193
|
+
sleep 10
|
194
|
+
|
195
|
+
events = get_log_events(fluentd_tag)
|
196
|
+
assert_equal(2, events.size)
|
197
|
+
assert_equal((time.to_f * 1000).floor, events[0].timestamp)
|
198
|
+
assert_equal('message1 logs1', events[0].message)
|
199
|
+
assert_equal((time.to_i + 1) * 1000, events[1].timestamp)
|
200
|
+
assert_equal('message2 logs2', events[1].message)
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_write_use_tag_as_stream
|
204
|
+
new_log_stream
|
205
|
+
|
206
|
+
d = create_driver(<<-EOC)
|
207
|
+
#{default_config}
|
208
|
+
message_keys message,cloudwatch
|
209
|
+
use_tag_as_stream true
|
210
|
+
log_group_name #{log_group_name}
|
211
|
+
EOC
|
212
|
+
|
213
|
+
time = event_time
|
214
|
+
d.run(default_tag: fluentd_tag) do
|
215
|
+
d.feed(time, {'cloudwatch' => 'logs1', 'message' => 'message1'})
|
216
|
+
d.feed(time + 1, {'cloudwatch' => 'logs2', 'message' => 'message2'})
|
217
|
+
end
|
218
|
+
|
219
|
+
sleep 10
|
220
|
+
|
221
|
+
events = get_log_events(log_group_name, fluentd_tag)
|
222
|
+
assert_equal(2, events.size)
|
223
|
+
assert_equal((time.to_f * 1000).floor, events[0].timestamp)
|
224
|
+
assert_equal('message1 logs1', events[0].message)
|
225
|
+
assert_equal((time.to_i + 1) * 1000, events[1].timestamp)
|
226
|
+
assert_equal('message2 logs2', events[1].message)
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_write_use_placeholders
|
230
|
+
new_log_stream
|
231
|
+
|
232
|
+
config = {'@type' => 'cloudwatch_logs',
|
233
|
+
'auto_create_stream' => true,
|
234
|
+
'message_keys' => ["message","cloudwatch"],
|
235
|
+
'log_stream_name' => "${tag}",
|
236
|
+
'log_group_name' => log_group_name}
|
237
|
+
config.merge!(config_elementify(aws_key_id)) if aws_key_id
|
238
|
+
config.merge!(config_elementify(aws_sec_key)) if aws_sec_key
|
239
|
+
config.merge!(config_elementify(region)) if region
|
240
|
+
config.merge!(config_elementify(endpoint)) if endpoint
|
241
|
+
|
242
|
+
d = create_driver(
|
243
|
+
Fluent::Config::Element.new('ROOT', '', config,[
|
244
|
+
Fluent::Config::Element.new('buffer', 'tag, time', {
|
245
|
+
'@type' => 'memory',
|
246
|
+
'timekey' => 3600
|
247
|
+
}, [])
|
248
|
+
])
|
249
|
+
)
|
250
|
+
|
251
|
+
time = event_time
|
252
|
+
d.run(default_tag: fluentd_tag) do
|
253
|
+
d.feed(time, {'cloudwatch' => 'logs1', 'message' => 'message1'})
|
254
|
+
d.feed(time + 1, {'cloudwatch' => 'logs2', 'message' => 'message2'})
|
255
|
+
end
|
256
|
+
|
257
|
+
sleep 10
|
258
|
+
|
259
|
+
events = get_log_events(log_group_name, fluentd_tag)
|
260
|
+
assert_equal(2, events.size)
|
261
|
+
assert_equal((time.to_f * 1000).floor, events[0].timestamp)
|
262
|
+
assert_equal('message1 logs1', events[0].message)
|
263
|
+
assert_equal((time.to_i + 1) * 1000, events[1].timestamp)
|
264
|
+
assert_equal('message2 logs2', events[1].message)
|
265
|
+
end
|
266
|
+
|
267
|
+
def test_write_use_placeholders_parts
|
268
|
+
new_log_stream
|
269
|
+
|
270
|
+
config = {'@type' => 'cloudwatch_logs',
|
271
|
+
'auto_create_stream' => true,
|
272
|
+
'message_keys' => ["message","cloudwatch"],
|
273
|
+
'log_stream_name' => "${tag[0]}-${tag[1]}-${tag[2]}-${tag[3]}",
|
274
|
+
'log_group_name' => log_group_name}
|
275
|
+
config.merge!(config_elementify(aws_key_id)) if aws_key_id
|
276
|
+
config.merge!(config_elementify(aws_sec_key)) if aws_sec_key
|
277
|
+
config.merge!(config_elementify(region)) if region
|
278
|
+
config.merge!(config_elementify(endpoint)) if endpoint
|
279
|
+
|
280
|
+
d = create_driver(
|
281
|
+
Fluent::Config::Element.new('ROOT', '', config, [
|
282
|
+
Fluent::Config::Element.new('buffer', 'tag, time', {
|
283
|
+
'@type' => 'memory',
|
284
|
+
'timekey' => 3600
|
285
|
+
}, [])
|
286
|
+
])
|
287
|
+
)
|
288
|
+
|
289
|
+
time = event_time
|
290
|
+
d.run(default_tag: fluentd_tag) do
|
291
|
+
d.feed(time, {'cloudwatch' => 'logs1', 'message' => 'message1'})
|
292
|
+
d.feed(time + 1, {'cloudwatch' => 'logs2', 'message' => 'message2'})
|
293
|
+
end
|
294
|
+
|
295
|
+
sleep 10
|
296
|
+
|
297
|
+
events = get_log_events(log_group_name, 'fluent-plugin-cloudwatch-test')
|
298
|
+
assert_equal(2, events.size)
|
299
|
+
assert_equal((time.to_f * 1000).floor, events[0].timestamp)
|
300
|
+
assert_equal('message1 logs1', events[0].message)
|
301
|
+
assert_equal((time.to_i + 1) * 1000, events[1].timestamp)
|
302
|
+
assert_equal('message2 logs2', events[1].message)
|
303
|
+
end
|
304
|
+
|
305
|
+
def test_write_use_time_placeholders
|
306
|
+
new_log_stream
|
307
|
+
|
308
|
+
config = {'@type' => 'cloudwatch_logs',
|
309
|
+
'auto_create_stream' => true,
|
310
|
+
'message_keys' => ["message","cloudwatch"],
|
311
|
+
'log_stream_name' => "fluent-plugin-cloudwatch-test-%Y%m%d",
|
312
|
+
'log_group_name' => log_group_name}
|
313
|
+
config.merge!(config_elementify(aws_key_id)) if aws_key_id
|
314
|
+
config.merge!(config_elementify(aws_sec_key)) if aws_sec_key
|
315
|
+
config.merge!(config_elementify(region)) if region
|
316
|
+
config.merge!(config_elementify(endpoint)) if endpoint
|
317
|
+
|
318
|
+
d = create_driver(
|
319
|
+
Fluent::Config::Element.new('ROOT', '', config,[
|
320
|
+
Fluent::Config::Element.new('buffer', 'tag, time', {
|
321
|
+
'@type' => 'memory',
|
322
|
+
'timekey' => 3600
|
323
|
+
}, [])
|
324
|
+
])
|
325
|
+
)
|
326
|
+
|
327
|
+
time = event_time
|
328
|
+
d.run(default_tag: fluentd_tag) do
|
329
|
+
d.feed(time, {'cloudwatch' => 'logs1', 'message' => 'message1'})
|
330
|
+
d.feed(time + 1, {'cloudwatch' => 'logs2', 'message' => 'message2'})
|
331
|
+
end
|
332
|
+
|
333
|
+
sleep 10
|
334
|
+
|
335
|
+
events = get_log_events(log_group_name, "fluent-plugin-cloudwatch-test-#{Time.at(time).strftime("%Y%m%d")}")
|
336
|
+
assert_equal(2, events.size)
|
337
|
+
assert_equal((time.to_f * 1000).floor, events[0].timestamp)
|
338
|
+
assert_equal('message1 logs1', events[0].message)
|
339
|
+
assert_equal((time.to_i + 1) * 1000, events[1].timestamp)
|
340
|
+
assert_equal('message2 logs2', events[1].message)
|
341
|
+
end
|
342
|
+
|
343
|
+
def test_include_time_key
|
344
|
+
new_log_stream
|
345
|
+
|
346
|
+
d = create_driver(<<-EOC)
|
347
|
+
#{default_config}
|
348
|
+
include_time_key true
|
349
|
+
log_group_name #{log_group_name}
|
350
|
+
log_stream_name #{log_stream_name}
|
351
|
+
utc
|
352
|
+
EOC
|
353
|
+
|
354
|
+
time = event_time
|
355
|
+
d.run(default_tag: fluentd_tag) do
|
356
|
+
d.feed(time, {'cloudwatch' => 'logs1'})
|
357
|
+
d.feed(time + 1, {'cloudwatch' => 'logs2'})
|
358
|
+
end
|
359
|
+
|
360
|
+
sleep 10
|
361
|
+
|
362
|
+
events = get_log_events
|
363
|
+
assert_equal(2, events.size)
|
364
|
+
assert_equal((time.to_f * 1000).floor, events[0].timestamp)
|
365
|
+
assert_equal("{\"cloudwatch\":\"logs1\",\"time\":\"#{Time.at(time.to_r).utc.strftime("%Y-%m-%dT%H:%M:%SZ")}\"}", events[0].message)
|
366
|
+
assert_equal((time.to_i + 1) * 1000, events[1].timestamp)
|
367
|
+
assert_equal("{\"cloudwatch\":\"logs2\",\"time\":\"#{Time.at((time+1).to_r).utc.strftime("%Y-%m-%dT%H:%M:%SZ")}\"}", events[1].message)
|
368
|
+
end
|
369
|
+
|
370
|
+
def test_include_time_key_localtime
|
371
|
+
new_log_stream
|
372
|
+
|
373
|
+
d = create_driver(<<-EOC)
|
374
|
+
#{default_config}
|
375
|
+
include_time_key true
|
376
|
+
localtime true
|
377
|
+
log_group_name #{log_group_name}
|
378
|
+
log_stream_name #{log_stream_name}
|
379
|
+
EOC
|
380
|
+
|
381
|
+
time = event_time
|
382
|
+
d.run(default_tag: fluentd_tag) do
|
383
|
+
d.feed(time, {'cloudwatch' => 'logs1'})
|
384
|
+
d.feed(time + 1, {'cloudwatch' => 'logs2'})
|
385
|
+
end
|
386
|
+
|
387
|
+
sleep 10
|
388
|
+
|
389
|
+
events = get_log_events
|
390
|
+
assert_equal(2, events.size)
|
391
|
+
assert_equal((time.to_f * 1000).floor, events[0].timestamp)
|
392
|
+
assert_equal("{\"cloudwatch\":\"logs1\",\"time\":\"#{Time.at(time.to_r).strftime("%Y-%m-%dT%H:%M:%S%:z")}\"}", events[0].message)
|
393
|
+
assert_equal((time.to_i + 1) * 1000, events[1].timestamp)
|
394
|
+
assert_equal("{\"cloudwatch\":\"logs2\",\"time\":\"#{Time.at((time+1).to_r).to_time.strftime("%Y-%m-%dT%H:%M:%S%:z")}\"}", events[1].message)
|
395
|
+
end
|
396
|
+
|
397
|
+
def test_log_group_name_key_and_log_stream_name_key
|
398
|
+
new_log_stream
|
399
|
+
|
400
|
+
d = create_driver(<<-EOC)
|
401
|
+
#{default_config}
|
402
|
+
log_group_name_key group_name_key
|
403
|
+
log_stream_name_key stream_name_key
|
404
|
+
@log_level debug
|
405
|
+
EOC
|
406
|
+
|
407
|
+
stream1 = new_log_stream
|
408
|
+
stream2 = new_log_stream
|
409
|
+
|
410
|
+
records = [
|
411
|
+
{'cloudwatch' => 'logs1', 'message' => 'message1', 'group_name_key' => log_group_name, 'stream_name_key' => stream1},
|
412
|
+
{'cloudwatch' => 'logs2', 'message' => 'message1', 'group_name_key' => log_group_name, 'stream_name_key' => stream2},
|
413
|
+
{'cloudwatch' => 'logs3', 'message' => 'message1', 'group_name_key' => log_group_name, 'stream_name_key' => stream1},
|
414
|
+
]
|
415
|
+
|
416
|
+
time = event_time
|
417
|
+
d.run(default_tag: fluentd_tag) do
|
418
|
+
records.each_with_index do |record, i|
|
419
|
+
d.feed(time + i, record)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
logs = d.logs
|
424
|
+
# Call API once for each stream
|
425
|
+
assert_equal(2, logs.select {|l| l =~ /Called PutLogEvents API/ }.size)
|
426
|
+
|
427
|
+
sleep 10
|
428
|
+
|
429
|
+
events = get_log_events(log_group_name, stream1)
|
430
|
+
assert_equal(2, events.size)
|
431
|
+
assert_equal(time.to_i * 1000, events[0].timestamp)
|
432
|
+
assert_equal((time.to_i + 2) * 1000, events[1].timestamp)
|
433
|
+
assert_equal(records[0], JSON.parse(events[0].message))
|
434
|
+
assert_equal(records[2], JSON.parse(events[1].message))
|
435
|
+
|
436
|
+
events = get_log_events(log_group_name, stream2)
|
437
|
+
assert_equal(1, events.size)
|
438
|
+
assert_equal((time.to_i + 1) * 1000, events[0].timestamp)
|
439
|
+
assert_equal(records[1], JSON.parse(events[0].message))
|
440
|
+
end
|
441
|
+
|
442
|
+
def test_remove_log_group_name_key_and_remove_log_stream_name_key
|
443
|
+
new_log_stream
|
444
|
+
|
445
|
+
d = create_driver(<<-EOC)
|
446
|
+
#{default_config}
|
447
|
+
log_group_name_key group_name_key
|
448
|
+
log_stream_name_key stream_name_key
|
449
|
+
remove_log_group_name_key true
|
450
|
+
remove_log_stream_name_key true
|
451
|
+
EOC
|
452
|
+
|
453
|
+
time = event_time
|
454
|
+
d.run(default_tag: fluentd_tag) do
|
455
|
+
d.feed(time, {'cloudwatch' => 'logs1', 'message' => 'message1', 'group_name_key' => log_group_name, 'stream_name_key' => log_stream_name})
|
456
|
+
end
|
457
|
+
|
458
|
+
sleep 10
|
459
|
+
|
460
|
+
events = get_log_events(log_group_name, log_stream_name)
|
461
|
+
assert_equal(1, events.size)
|
462
|
+
assert_equal((time.to_f * 1000).floor, events[0].timestamp)
|
463
|
+
assert_equal({'cloudwatch' => 'logs1', 'message' => 'message1'}, JSON.parse(events[0].message))
|
464
|
+
end
|
465
|
+
|
466
|
+
def test_log_group_aws_tags
|
467
|
+
clear_log_group
|
468
|
+
|
469
|
+
d = create_driver(<<-EOC)
|
470
|
+
#{default_config}
|
471
|
+
auto_create_stream true
|
472
|
+
use_tag_as_stream true
|
473
|
+
log_group_name_key group_name_key
|
474
|
+
log_group_aws_tags {"tag1": "value1", "tag2": "value2"}
|
475
|
+
EOC
|
476
|
+
|
477
|
+
records = [
|
478
|
+
{'cloudwatch' => 'logs1', 'message' => 'message1', 'group_name_key' => log_group_name},
|
479
|
+
{'cloudwatch' => 'logs2', 'message' => 'message1', 'group_name_key' => log_group_name},
|
480
|
+
{'cloudwatch' => 'logs3', 'message' => 'message1', 'group_name_key' => log_group_name},
|
481
|
+
]
|
482
|
+
|
483
|
+
time = Time.now
|
484
|
+
d.run(default_tag: fluentd_tag) do
|
485
|
+
records.each_with_index do |record, i|
|
486
|
+
d.feed(time.to_i + i, record)
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
awstags = get_log_group_tags
|
491
|
+
assert_equal("value1", awstags.fetch("tag1"))
|
492
|
+
assert_equal("value2", awstags.fetch("tag2"))
|
493
|
+
end
|
494
|
+
|
495
|
+
def test_retention_in_days
|
496
|
+
clear_log_group
|
497
|
+
|
498
|
+
d = create_driver(<<-EOC)
|
499
|
+
#{default_config}
|
500
|
+
auto_create_stream true
|
501
|
+
use_tag_as_stream true
|
502
|
+
log_group_name_key group_name_key
|
503
|
+
retention_in_days 7
|
504
|
+
EOC
|
505
|
+
|
506
|
+
records = [
|
507
|
+
{'cloudwatch' => 'logs1', 'message' => 'message1', 'group_name_key' => log_group_name},
|
508
|
+
{'cloudwatch' => 'logs2', 'message' => 'message1', 'group_name_key' => log_group_name},
|
509
|
+
{'cloudwatch' => 'logs3', 'message' => 'message1', 'group_name_key' => log_group_name},
|
510
|
+
]
|
511
|
+
|
512
|
+
time = Time.now
|
513
|
+
d.run(default_tag: fluentd_tag) do
|
514
|
+
records.each_with_index do |record, i|
|
515
|
+
d.feed(time.to_i + i, record)
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
retention = get_log_group_retention_days
|
520
|
+
assert_equal(d.instance.retention_in_days, retention)
|
521
|
+
end
|
522
|
+
|
523
|
+
def test_invalid_retention_in_days
|
524
|
+
clear_log_group
|
525
|
+
|
526
|
+
d = create_driver(<<-EOC)
|
527
|
+
#{default_config}
|
528
|
+
auto_create_stream true
|
529
|
+
use_tag_as_stream true
|
530
|
+
log_group_name_key group_name_key
|
531
|
+
retention_in_days 4
|
532
|
+
EOC
|
533
|
+
|
534
|
+
records = [
|
535
|
+
{'cloudwatch' => 'logs1', 'message' => 'message1', 'group_name_key' => log_group_name},
|
536
|
+
{'cloudwatch' => 'logs2', 'message' => 'message1', 'group_name_key' => log_group_name},
|
537
|
+
{'cloudwatch' => 'logs3', 'message' => 'message1', 'group_name_key' => log_group_name},
|
538
|
+
]
|
539
|
+
|
540
|
+
time = Time.now
|
541
|
+
d.run(default_tag: fluentd_tag) do
|
542
|
+
records.each_with_index do |record, i|
|
543
|
+
d.feed(time.to_i + i, record)
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
assert_match(/failed to set retention policy for Log group/, d.logs[0])
|
548
|
+
end
|
549
|
+
|
550
|
+
def test_log_group_aws_tags_key
|
551
|
+
clear_log_group
|
552
|
+
|
553
|
+
d = create_driver(<<-EOC)
|
554
|
+
#{default_config}
|
555
|
+
auto_create_stream true
|
556
|
+
use_tag_as_stream true
|
557
|
+
log_group_name_key group_name_key
|
558
|
+
log_group_aws_tags_key aws_tags
|
559
|
+
EOC
|
560
|
+
|
561
|
+
records = [
|
562
|
+
{'cloudwatch' => 'logs1', 'message' => 'message1', 'group_name_key' => log_group_name, 'aws_tags' => {"tag1" => "value1", "tag2" => "value2"}},
|
563
|
+
{'cloudwatch' => 'logs2', 'message' => 'message1', 'group_name_key' => log_group_name, 'aws_tags' => {"tag1" => "value1", "tag2" => "value2"}},
|
564
|
+
{'cloudwatch' => 'logs3', 'message' => 'message1', 'group_name_key' => log_group_name, 'aws_tags' => {"tag1" => "value1", "tag2" => "value2"}}
|
565
|
+
]
|
566
|
+
|
567
|
+
time = Time.now
|
568
|
+
d.run(default_tag: fluentd_tag) do
|
569
|
+
records.each_with_index do |record, i|
|
570
|
+
d.feed(time.to_i + i, record)
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
awstags = get_log_group_tags
|
575
|
+
assert_equal("value1", awstags.fetch("tag1"))
|
576
|
+
assert_equal("value2", awstags.fetch("tag2"))
|
577
|
+
end
|
578
|
+
|
579
|
+
def test_log_group_aws_tags_key_same_group_diff_tags
|
580
|
+
clear_log_group
|
581
|
+
|
582
|
+
d = create_driver(<<-EOC)
|
583
|
+
#{default_config}
|
584
|
+
auto_create_stream true
|
585
|
+
use_tag_as_stream true
|
586
|
+
log_group_name_key group_name_key
|
587
|
+
log_group_aws_tags_key aws_tags
|
588
|
+
EOC
|
589
|
+
|
590
|
+
records = [
|
591
|
+
{'cloudwatch' => 'logs1', 'message' => 'message1', 'group_name_key' => log_group_name, 'aws_tags' => {"tag1" => "value1", "tag2" => "value2"}},
|
592
|
+
{'cloudwatch' => 'logs3', 'message' => 'message1', 'group_name_key' => log_group_name, 'aws_tags' => {"tag3" => "value3", "tag4" => "value4"}}
|
593
|
+
]
|
594
|
+
|
595
|
+
time = Time.now
|
596
|
+
d.run(default_tag: fluentd_tag) do
|
597
|
+
records.each_with_index do |record, i|
|
598
|
+
d.feed(time.to_i + i, record)
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
awstags = get_log_group_tags
|
603
|
+
assert_equal("value1", awstags.fetch("tag1"))
|
604
|
+
assert_equal("value2", awstags.fetch("tag2"))
|
605
|
+
assert_raise KeyError do
|
606
|
+
awstags.fetch("tag3")
|
607
|
+
end
|
608
|
+
assert_raise KeyError do
|
609
|
+
awstags.fetch("tag4")
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
def test_log_group_aws_tags_key_no_tags
|
614
|
+
clear_log_group
|
615
|
+
|
616
|
+
d = create_driver(<<-EOC)
|
617
|
+
#{default_config}
|
618
|
+
auto_create_stream true
|
619
|
+
log_group_name_key group_name_key
|
620
|
+
log_stream_name_key stream_name_key
|
621
|
+
remove_log_group_name_key true
|
622
|
+
remove_log_stream_name_key true
|
623
|
+
log_group_aws_tags_key aws_tags
|
624
|
+
EOC
|
625
|
+
|
626
|
+
stream = log_stream_name
|
627
|
+
records = [
|
628
|
+
{'cloudwatch' => 'logs1', 'message' => 'message1', 'group_name_key' => log_group_name, 'stream_name_key' => stream},
|
629
|
+
{'cloudwatch' => 'logs2', 'message' => 'message2', 'group_name_key' => log_group_name, 'stream_name_key' => stream}
|
630
|
+
]
|
631
|
+
|
632
|
+
time = Time.now
|
633
|
+
d.run(default_tag: fluentd_tag) do
|
634
|
+
records.each_with_index do |record, i|
|
635
|
+
d.feed(time.to_i + i, record)
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
sleep 10
|
640
|
+
|
641
|
+
awstags = get_log_group_tags
|
642
|
+
|
643
|
+
assert_raise KeyError do
|
644
|
+
awstags.fetch("tag1")
|
645
|
+
end
|
646
|
+
|
647
|
+
events = get_log_events(log_group_name, stream)
|
648
|
+
assert_equal(2, events.size)
|
649
|
+
assert_equal(time.to_i * 1000, events[0].timestamp)
|
650
|
+
assert_equal({'cloudwatch' => 'logs1', 'message' => 'message1'}, JSON.parse(events[0].message))
|
651
|
+
assert_equal({'cloudwatch' => 'logs2', 'message' => 'message2'}, JSON.parse(events[1].message))
|
652
|
+
end
|
653
|
+
|
654
|
+
def test_retrying_on_throttling_exception
|
655
|
+
resp = mock()
|
656
|
+
resp.expects(:rejected_log_events_info)
|
657
|
+
resp.expects(:next_sequence_token)
|
658
|
+
client = Aws::CloudWatchLogs::Client.new
|
659
|
+
client.stubs(:put_log_events).
|
660
|
+
raises(Aws::CloudWatchLogs::Errors::ThrottlingException.new(nil, "error")).then.returns(resp)
|
661
|
+
|
662
|
+
d = create_driver
|
663
|
+
time = event_time
|
664
|
+
d.instance.instance_variable_set(:@logs, client)
|
665
|
+
d.run(default_tag: fluentd_tag) do
|
666
|
+
d.feed(time, {'message' => 'message1'})
|
667
|
+
end
|
668
|
+
|
669
|
+
logs = d.logs
|
670
|
+
assert_equal(1, logs.select {|l| l =~ /Called PutLogEvents API/ }.size)
|
671
|
+
assert_equal(1, logs.select {|l| l =~ /failed to PutLogEvents/ }.size)
|
672
|
+
assert_equal(1, logs.select {|l| l =~ /retry succeeded/ }.size)
|
673
|
+
end
|
674
|
+
|
675
|
+
def test_retrying_on_throttling_exception_and_throw_away
|
676
|
+
client = Aws::CloudWatchLogs::Client.new
|
677
|
+
client.stubs(:put_log_events).
|
678
|
+
raises(Aws::CloudWatchLogs::Errors::ThrottlingException.new(nil, "error"))
|
679
|
+
time = Fluent::Engine.now
|
680
|
+
d = create_driver(<<-EOC)
|
681
|
+
#{default_config}
|
682
|
+
log_group_name #{log_group_name}
|
683
|
+
log_stream_name #{log_stream_name}
|
684
|
+
put_log_events_retry_limit 1
|
685
|
+
@log_level debug
|
686
|
+
EOC
|
687
|
+
d.instance.instance_variable_set(:@logs, client)
|
688
|
+
d.run(default_tag: fluentd_tag) do
|
689
|
+
d.feed(time, {'message' => 'message1'})
|
690
|
+
end
|
691
|
+
|
692
|
+
logs = d.logs
|
693
|
+
assert_equal(0, logs.select {|l| l =~ /Called PutLogEvents API/ }.size)
|
694
|
+
assert_equal(3, logs.select {|l| l =~ /failed to PutLogEvents/ }.size)
|
695
|
+
assert_equal(1, logs.select {|l| l =~ /failed to PutLogEvents and discard logs/ }.size)
|
696
|
+
end
|
697
|
+
|
698
|
+
def test_too_large_event
|
699
|
+
time = Fluent::Engine.now
|
700
|
+
d = create_driver(<<-EOC)
|
701
|
+
#{default_config}
|
702
|
+
log_group_name #{log_group_name}
|
703
|
+
log_stream_name #{log_stream_name}
|
704
|
+
@log_level debug
|
705
|
+
EOC
|
706
|
+
d.run(default_tag: fluentd_tag) do
|
707
|
+
d.feed(time, {'message' => '*' * 256 * 1024})
|
708
|
+
end
|
709
|
+
|
710
|
+
logs = d.logs
|
711
|
+
assert(logs.any?{|log| log.include?("Log event is discarded because it is too large: 262184 bytes exceeds limit of 262144")})
|
712
|
+
end
|
713
|
+
end
|
714
|
+
|
715
|
+
def test_scrub_record
|
716
|
+
record = {
|
717
|
+
"hash" => {
|
718
|
+
"str" => "\xAE",
|
719
|
+
},
|
720
|
+
"array" => [
|
721
|
+
"\xAE",
|
722
|
+
],
|
723
|
+
"str" => "\xAE",
|
724
|
+
}
|
725
|
+
|
726
|
+
d = create_driver
|
727
|
+
d.instance.send(:scrub_record!, record)
|
728
|
+
|
729
|
+
assert_equal("�", record["hash"]["str"])
|
730
|
+
assert_equal("�", record["array"][0])
|
731
|
+
assert_equal("�", record["str"])
|
732
|
+
end
|
733
|
+
|
734
|
+
private
|
735
|
+
def default_config
|
736
|
+
<<-EOC
|
737
|
+
@type cloudwatch_logs
|
738
|
+
auto_create_stream true
|
739
|
+
#{aws_key_id}
|
740
|
+
#{aws_sec_key}
|
741
|
+
#{region}
|
742
|
+
#{endpoint}
|
743
|
+
EOC
|
744
|
+
end
|
745
|
+
|
746
|
+
def create_driver(conf = nil)
|
747
|
+
unless conf
|
748
|
+
conf = <<-EOC
|
749
|
+
#{default_config}
|
750
|
+
log_group_name #{log_group_name}
|
751
|
+
log_stream_name #{log_stream_name}
|
752
|
+
@log_level debug
|
753
|
+
EOC
|
754
|
+
end
|
755
|
+
Fluent::Test::Driver::Output.new(Fluent::Plugin::CloudwatchLogsOutput).configure(conf)
|
756
|
+
end
|
757
|
+
end
|