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.
@@ -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