fluent-plugin-google-cloud 0.5.1 → 0.5.2
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 +4 -4
- data/Gemfile.lock +19 -19
- data/fluent-plugin-google-cloud.gemspec +2 -2
- data/lib/fluent/plugin/out_google_cloud.rb +69 -33
- data/test/plugin/test_out_google_cloud.rb +112 -9
- metadata +8 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8109f72f6f16a0756b3a30c911e9343392051b96
|
|
4
|
+
data.tar.gz: e76c44a9c3e8cb63c6125f1b621e7985e3050918
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aad0d625ddb42768a112e887bae953d601bd646d9003d7a7308a19a3e9e4afdbd61725bd56b844cefc7626a99dad067ea3ef6d68e44f06bc324ab7abe937bcd2
|
|
7
|
+
data.tar.gz: c880a81905b4ce2535f247a7bd1938e46082461f8c9f48a03716908219e6fe95234397a09ee4975ed21dc5c196b782d1efd1ebf499617c7fb989aa234efbf60e
|
data/Gemfile.lock
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
fluent-plugin-google-cloud (0.5.
|
|
5
|
-
fluentd (~> 0.10)
|
|
4
|
+
fluent-plugin-google-cloud (0.5.2)
|
|
5
|
+
fluentd (~> 0.10, <= 0.13)
|
|
6
6
|
google-api-client (> 0.9)
|
|
7
7
|
googleauth (~> 0.4)
|
|
8
8
|
json (~> 1.8)
|
|
@@ -11,25 +11,25 @@ GEM
|
|
|
11
11
|
remote: https://rubygems.org/
|
|
12
12
|
specs:
|
|
13
13
|
addressable (2.4.0)
|
|
14
|
-
ast (2.
|
|
14
|
+
ast (2.3.0)
|
|
15
15
|
astrolabe (1.3.1)
|
|
16
16
|
parser (~> 2.2)
|
|
17
|
-
cool.io (1.4.
|
|
17
|
+
cool.io (1.4.4)
|
|
18
18
|
crack (0.4.3)
|
|
19
19
|
safe_yaml (~> 1.0.0)
|
|
20
20
|
faraday (0.9.2)
|
|
21
21
|
multipart-post (>= 1.2, < 3)
|
|
22
|
-
fluentd (0.12.
|
|
22
|
+
fluentd (0.12.26)
|
|
23
23
|
cool.io (>= 1.2.2, < 2.0.0)
|
|
24
24
|
http_parser.rb (>= 0.5.1, < 0.7.0)
|
|
25
25
|
json (>= 1.4.3)
|
|
26
26
|
msgpack (>= 0.5.11, < 0.6.0)
|
|
27
27
|
sigdump (~> 0.2.2)
|
|
28
|
-
string-scrub (>= 0.0.3)
|
|
28
|
+
string-scrub (>= 0.0.3, <= 0.0.5)
|
|
29
29
|
tzinfo (>= 1.0.0)
|
|
30
30
|
tzinfo-data (>= 1.0.0)
|
|
31
31
|
yajl-ruby (~> 1.0)
|
|
32
|
-
google-api-client (0.9.
|
|
32
|
+
google-api-client (0.9.9)
|
|
33
33
|
addressable (~> 2.3)
|
|
34
34
|
googleauth (~> 0.5)
|
|
35
35
|
httpclient (~> 2.7)
|
|
@@ -49,7 +49,7 @@ GEM
|
|
|
49
49
|
signet (~> 0.7)
|
|
50
50
|
hashdiff (0.3.0)
|
|
51
51
|
http_parser.rb (0.6.0)
|
|
52
|
-
httpclient (2.
|
|
52
|
+
httpclient (2.8.0)
|
|
53
53
|
hurley (0.2)
|
|
54
54
|
json (1.8.3)
|
|
55
55
|
jwt (1.5.4)
|
|
@@ -59,18 +59,18 @@ GEM
|
|
|
59
59
|
multi_json (~> 1.10)
|
|
60
60
|
memoist (0.14.0)
|
|
61
61
|
metaclass (0.0.4)
|
|
62
|
-
mime-types (3.
|
|
62
|
+
mime-types (3.1)
|
|
63
63
|
mime-types-data (~> 3.2015)
|
|
64
|
-
mime-types-data (3.2016.
|
|
64
|
+
mime-types-data (3.2016.0521)
|
|
65
65
|
mocha (1.1.0)
|
|
66
66
|
metaclass (~> 0.0.1)
|
|
67
67
|
msgpack (0.5.12)
|
|
68
|
-
multi_json (1.
|
|
68
|
+
multi_json (1.12.1)
|
|
69
69
|
multipart-post (2.0.0)
|
|
70
70
|
os (0.9.6)
|
|
71
|
-
parser (2.3.
|
|
71
|
+
parser (2.3.1.2)
|
|
72
72
|
ast (~> 2.2)
|
|
73
|
-
power_assert (0.
|
|
73
|
+
power_assert (0.3.0)
|
|
74
74
|
powerpack (0.1.1)
|
|
75
75
|
rainbow (2.1.0)
|
|
76
76
|
rake (10.5.0)
|
|
@@ -83,25 +83,25 @@ GEM
|
|
|
83
83
|
powerpack (~> 0.1)
|
|
84
84
|
rainbow (>= 1.99.1, < 3.0)
|
|
85
85
|
ruby-progressbar (~> 1.7)
|
|
86
|
-
ruby-progressbar (1.
|
|
86
|
+
ruby-progressbar (1.8.1)
|
|
87
87
|
safe_yaml (1.0.4)
|
|
88
88
|
sigdump (0.2.4)
|
|
89
|
-
signet (0.7.
|
|
89
|
+
signet (0.7.3)
|
|
90
90
|
addressable (~> 2.3)
|
|
91
91
|
faraday (~> 0.9)
|
|
92
92
|
jwt (~> 1.5)
|
|
93
93
|
multi_json (~> 1.10)
|
|
94
94
|
string-scrub (0.0.5)
|
|
95
|
-
test-unit (3.
|
|
95
|
+
test-unit (3.2.0)
|
|
96
96
|
power_assert
|
|
97
97
|
thor (0.19.1)
|
|
98
98
|
thread_safe (0.3.5)
|
|
99
99
|
tzinfo (1.2.2)
|
|
100
100
|
thread_safe (~> 0.1)
|
|
101
|
-
tzinfo-data (1.2016.
|
|
101
|
+
tzinfo-data (1.2016.5)
|
|
102
102
|
tzinfo (>= 1.0.0)
|
|
103
103
|
uber (0.0.15)
|
|
104
|
-
webmock (1.24.
|
|
104
|
+
webmock (1.24.6)
|
|
105
105
|
addressable (>= 2.3.6)
|
|
106
106
|
crack (>= 0.3.2)
|
|
107
107
|
hashdiff
|
|
@@ -119,4 +119,4 @@ DEPENDENCIES
|
|
|
119
119
|
webmock (~> 1.17)
|
|
120
120
|
|
|
121
121
|
BUNDLED WITH
|
|
122
|
-
1.
|
|
122
|
+
1.12.5
|
|
@@ -10,7 +10,7 @@ eos
|
|
|
10
10
|
gem.homepage = \
|
|
11
11
|
'https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud'
|
|
12
12
|
gem.license = 'Apache-2.0'
|
|
13
|
-
gem.version = '0.5.
|
|
13
|
+
gem.version = '0.5.2'
|
|
14
14
|
gem.authors = ['Todd Derr', 'Alex Robinson']
|
|
15
15
|
gem.email = ['salty@google.com']
|
|
16
16
|
gem.required_ruby_version = Gem::Requirement.new('>= 2.0')
|
|
@@ -19,7 +19,7 @@ eos
|
|
|
19
19
|
gem.test_files = gem.files.grep(/^(test)/)
|
|
20
20
|
gem.require_paths = ['lib']
|
|
21
21
|
|
|
22
|
-
gem.add_runtime_dependency 'fluentd', '~> 0.10'
|
|
22
|
+
gem.add_runtime_dependency 'fluentd', '~> 0.10', '<= 0.13'
|
|
23
23
|
gem.add_runtime_dependency 'google-api-client', '> 0.9'
|
|
24
24
|
gem.add_runtime_dependency 'googleauth', '~> 0.4'
|
|
25
25
|
gem.add_runtime_dependency 'json', '~> 1.8'
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
require 'json'
|
|
15
15
|
require 'open-uri'
|
|
16
16
|
require 'socket'
|
|
17
|
+
require 'time'
|
|
17
18
|
require 'yaml'
|
|
18
19
|
require 'google/apis'
|
|
19
20
|
require 'google/apis/logging_v1beta3'
|
|
@@ -25,7 +26,7 @@ module Fluent
|
|
|
25
26
|
Fluent::Plugin.register_output('google_cloud', self)
|
|
26
27
|
|
|
27
28
|
PLUGIN_NAME = 'Fluentd Google Cloud Logging plugin'
|
|
28
|
-
PLUGIN_VERSION = '0.5.
|
|
29
|
+
PLUGIN_VERSION = '0.5.2'
|
|
29
30
|
|
|
30
31
|
# Constants for service names.
|
|
31
32
|
APPENGINE_SERVICE = 'appengine.googleapis.com'
|
|
@@ -347,7 +348,6 @@ module Fluent
|
|
|
347
348
|
end
|
|
348
349
|
end
|
|
349
350
|
end
|
|
350
|
-
is_container_json = nil
|
|
351
351
|
arr.each do |time, record|
|
|
352
352
|
next unless record.is_a?(Hash)
|
|
353
353
|
|
|
@@ -373,24 +373,27 @@ module Fluent
|
|
|
373
373
|
if record.key?('kubernetes')
|
|
374
374
|
handle_container_metadata(record, entry)
|
|
375
375
|
end
|
|
376
|
-
|
|
377
|
-
#
|
|
378
|
-
#
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
# the
|
|
382
|
-
#
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
if record_json.nil?
|
|
386
|
-
is_container_json = false
|
|
387
|
-
else
|
|
388
|
-
record = record_json
|
|
389
|
-
is_container_json = true
|
|
390
|
-
end
|
|
391
|
-
elsif is_container_json && record.key?('log')
|
|
376
|
+
|
|
377
|
+
# Save the timestamp if available, then clear it out to allow for
|
|
378
|
+
# determining whether we should parse the log or message field.
|
|
379
|
+
timestamp = record.key?('time') ? record['time'] : nil
|
|
380
|
+
record.delete('time')
|
|
381
|
+
# If the log is json, we want to export it as a structured log
|
|
382
|
+
# unless there is additional metadata that would be lost.
|
|
383
|
+
is_json = false
|
|
384
|
+
if record.length == 1 && record.key?('log')
|
|
392
385
|
record_json = parse_json_or_nil(record['log'])
|
|
393
|
-
|
|
386
|
+
end
|
|
387
|
+
if record.length == 1 && record.key?('message')
|
|
388
|
+
record_json = parse_json_or_nil(record['message'])
|
|
389
|
+
end
|
|
390
|
+
unless record_json.nil?
|
|
391
|
+
record = record_json
|
|
392
|
+
is_json = true
|
|
393
|
+
end
|
|
394
|
+
# Restore timestamp if necessary.
|
|
395
|
+
unless record.key?('time') || timestamp.nil?
|
|
396
|
+
record['time'] = timestamp
|
|
394
397
|
end
|
|
395
398
|
end
|
|
396
399
|
|
|
@@ -414,7 +417,7 @@ module Fluent
|
|
|
414
417
|
@cloudfunctions_log_match['execution_id']
|
|
415
418
|
end
|
|
416
419
|
|
|
417
|
-
set_payload(record, entry,
|
|
420
|
+
set_payload(record, entry, is_json)
|
|
418
421
|
entry.metadata.labels = nil if entry.metadata.labels.empty?
|
|
419
422
|
|
|
420
423
|
entries.push(entry)
|
|
@@ -476,11 +479,23 @@ module Fluent
|
|
|
476
479
|
# Only here to please rubocop...
|
|
477
480
|
return nil if input.nil?
|
|
478
481
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
482
|
+
input.each_codepoint do |c|
|
|
483
|
+
if c == 123
|
|
484
|
+
# left curly bracket (U+007B)
|
|
485
|
+
begin
|
|
486
|
+
return JSON.parse(input)
|
|
487
|
+
rescue JSON::ParserError
|
|
488
|
+
return nil
|
|
489
|
+
end
|
|
490
|
+
else
|
|
491
|
+
# Break (and return nil) unless the current character is whitespace,
|
|
492
|
+
# in which case we continue to look for a left curly bracket.
|
|
493
|
+
# Whitespace as per the JSON spec are: tabulation (U+0009),
|
|
494
|
+
# line feed (U+000A), carriage return (U+000D), and space (U+0020).
|
|
495
|
+
break unless c == 9 || c == 10 || c == 13 || c == 32
|
|
496
|
+
end # case
|
|
497
|
+
end # do
|
|
498
|
+
nil
|
|
484
499
|
end
|
|
485
500
|
|
|
486
501
|
# "enum" of Platform values
|
|
@@ -616,6 +631,15 @@ module Fluent
|
|
|
616
631
|
timestamp = DateTime.parse(@cloudfunctions_log_match['timestamp'])
|
|
617
632
|
ts_secs = timestamp.strftime('%s')
|
|
618
633
|
ts_nanos = timestamp.strftime('%N')
|
|
634
|
+
elsif record.key?('time')
|
|
635
|
+
# k8s ISO8601 timestamp
|
|
636
|
+
begin
|
|
637
|
+
timestamp = Time.iso8601(record.delete('time'))
|
|
638
|
+
rescue
|
|
639
|
+
timestamp = Time.at(time)
|
|
640
|
+
end
|
|
641
|
+
ts_secs = timestamp.tv_sec
|
|
642
|
+
ts_nanos = timestamp.tv_nsec
|
|
619
643
|
else
|
|
620
644
|
timestamp = Time.at(time)
|
|
621
645
|
ts_secs = timestamp.tv_sec
|
|
@@ -644,6 +668,16 @@ module Fluent
|
|
|
644
668
|
elsif record.key?('severity')
|
|
645
669
|
entry.metadata.severity = parse_severity(record['severity'])
|
|
646
670
|
record.delete('severity')
|
|
671
|
+
elsif @service_name == CONTAINER_SERVICE && \
|
|
672
|
+
entry.metadata.labels.key?("#{CONTAINER_SERVICE}/stream")
|
|
673
|
+
stream = entry.metadata.labels["#{CONTAINER_SERVICE}/stream"]
|
|
674
|
+
if stream == 'stdout'
|
|
675
|
+
entry.metadata.severity = 'INFO'
|
|
676
|
+
elsif stream == 'stderr'
|
|
677
|
+
entry.metadata.severity = 'ERROR'
|
|
678
|
+
else
|
|
679
|
+
entry.metadata.severity = 'DEFAULT'
|
|
680
|
+
end
|
|
647
681
|
else
|
|
648
682
|
entry.metadata.severity = 'DEFAULT'
|
|
649
683
|
end
|
|
@@ -759,18 +793,20 @@ module Fluent
|
|
|
759
793
|
record.delete(field)
|
|
760
794
|
end
|
|
761
795
|
|
|
762
|
-
def set_payload(record, entry,
|
|
763
|
-
#
|
|
764
|
-
#
|
|
765
|
-
#
|
|
766
|
-
#
|
|
767
|
-
#
|
|
796
|
+
def set_payload(record, entry, is_json)
|
|
797
|
+
# If this is a Cloud Functions log that matched the expected regexp,
|
|
798
|
+
# use text payload. Otherwise, use JSON if we found valid JSON, or text
|
|
799
|
+
# payload in the following cases:
|
|
800
|
+
# 1. This is a Cloud Functions log and the 'log' key is available
|
|
801
|
+
# 2. This is an unstructured Container log and the 'log' key is available
|
|
802
|
+
# 3. The only remaining key is 'message'
|
|
768
803
|
if @service_name == CLOUDFUNCTIONS_SERVICE && @cloudfunctions_log_match
|
|
769
804
|
entry.text_payload = @cloudfunctions_log_match['text']
|
|
770
805
|
elsif @service_name == CLOUDFUNCTIONS_SERVICE && record.key?('log')
|
|
771
806
|
entry.text_payload = record['log']
|
|
772
|
-
elsif
|
|
773
|
-
|
|
807
|
+
elsif is_json
|
|
808
|
+
entry.struct_payload = record
|
|
809
|
+
elsif @service_name == CONTAINER_SERVICE && record.key?('log')
|
|
774
810
|
entry.text_payload = record['log']
|
|
775
811
|
elsif record.size == 1 && record.key?('message')
|
|
776
812
|
entry.text_payload = record['message']
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
require 'helper'
|
|
16
16
|
require 'json'
|
|
17
|
+
require 'time'
|
|
17
18
|
require 'mocha/test_unit'
|
|
18
19
|
require 'webmock/test_unit'
|
|
19
20
|
require 'google/apis'
|
|
@@ -82,6 +83,11 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
82
83
|
CONTAINER_LABEL_KEY = 'component'
|
|
83
84
|
CONTAINER_LABEL_VALUE = 'redis-component'
|
|
84
85
|
CONTAINER_STREAM = 'stdout'
|
|
86
|
+
CONTAINER_SEVERITY = 'INFO'
|
|
87
|
+
# Timestamp for 1234567890 seconds and 987654321 nanoseconds since epoch
|
|
88
|
+
CONTAINER_TIMESTAMP = '2009-02-13T23:31:30.987654321Z'
|
|
89
|
+
CONTAINER_SECONDS_EPOCH = 1_234_567_890
|
|
90
|
+
CONTAINER_NANOS = 987_654_321
|
|
85
91
|
|
|
86
92
|
# Cloud Functions specific labels
|
|
87
93
|
CLOUDFUNCTIONS_FUNCTION_NAME = '$My_Function.Name-@1'
|
|
@@ -583,6 +589,46 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
583
589
|
end
|
|
584
590
|
end
|
|
585
591
|
|
|
592
|
+
def test_struct_payload_json_log
|
|
593
|
+
setup_gce_metadata_stubs
|
|
594
|
+
setup_logging_stubs
|
|
595
|
+
d = create_driver
|
|
596
|
+
json_string = '{"msg": "test log entry 0", "tag2": "test", "data": 5000}'
|
|
597
|
+
d.emit('message' => 'notJSON ' + json_string)
|
|
598
|
+
d.emit('message' => json_string)
|
|
599
|
+
d.emit('message' => "\t" + json_string)
|
|
600
|
+
d.emit('message' => ' ' + json_string)
|
|
601
|
+
d.run
|
|
602
|
+
verify_log_entries(4, COMPUTE_PARAMS, '') do |entry|
|
|
603
|
+
assert entry.key?('textPayload'), 'Entry did not have textPayload'
|
|
604
|
+
end
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
def test_struct_payload_json_container_log
|
|
608
|
+
setup_gce_metadata_stubs
|
|
609
|
+
setup_container_metadata_stubs
|
|
610
|
+
setup_logging_stubs
|
|
611
|
+
d = create_driver(APPLICATION_DEFAULT_CONFIG, CONTAINER_TAG)
|
|
612
|
+
json_string = '{"msg": "test log entry 0", "tag2": "test", "data": 5000}'
|
|
613
|
+
d.emit(container_log_entry_with_metadata('notJSON' + json_string))
|
|
614
|
+
d.emit(container_log_entry_with_metadata(json_string))
|
|
615
|
+
d.emit(container_log_entry_with_metadata(" \r\n \t" + json_string))
|
|
616
|
+
d.run
|
|
617
|
+
log_index = 0
|
|
618
|
+
verify_log_entries(3, CONTAINER_FROM_METADATA_PARAMS, '') do |entry|
|
|
619
|
+
log_index += 1
|
|
620
|
+
if log_index == 1
|
|
621
|
+
assert entry.key?('textPayload'), 'Entry did not have textPayload'
|
|
622
|
+
else
|
|
623
|
+
assert entry.key?('structPayload'), 'Entry did not have structPayload'
|
|
624
|
+
assert_equal 3, entry['structPayload'].size, entry
|
|
625
|
+
assert_equal 'test log entry 0', entry['structPayload']['msg'], entry
|
|
626
|
+
assert_equal 'test', entry['structPayload']['tag2'], entry
|
|
627
|
+
assert_equal 5000, entry['structPayload']['data'], entry
|
|
628
|
+
end
|
|
629
|
+
end
|
|
630
|
+
end
|
|
631
|
+
|
|
586
632
|
def test_timestamps
|
|
587
633
|
setup_gce_metadata_stubs
|
|
588
634
|
setup_logging_stubs
|
|
@@ -843,7 +889,13 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
843
889
|
d = create_driver(APPLICATION_DEFAULT_CONFIG, CONTAINER_TAG)
|
|
844
890
|
d.emit(container_log_entry_with_metadata(log_entry(0)))
|
|
845
891
|
d.run
|
|
846
|
-
verify_log_entries(1, CONTAINER_FROM_METADATA_PARAMS)
|
|
892
|
+
verify_log_entries(1, CONTAINER_FROM_METADATA_PARAMS) do |entry|
|
|
893
|
+
assert_equal CONTAINER_SECONDS_EPOCH, \
|
|
894
|
+
entry['metadata']['timestamp']['seconds'], entry
|
|
895
|
+
assert_equal CONTAINER_NANOS, \
|
|
896
|
+
entry['metadata']['timestamp']['nanos'], entry
|
|
897
|
+
assert_equal CONTAINER_SEVERITY, entry['metadata']['severity'], entry
|
|
898
|
+
end
|
|
847
899
|
end
|
|
848
900
|
|
|
849
901
|
def test_multiple_container_logs_metadata_from_plugin
|
|
@@ -858,7 +910,13 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
858
910
|
@logs_sent = []
|
|
859
911
|
n.times { |i| d.emit(container_log_entry_with_metadata(log_entry(i))) }
|
|
860
912
|
d.run
|
|
861
|
-
verify_log_entries(n, CONTAINER_FROM_METADATA_PARAMS)
|
|
913
|
+
verify_log_entries(n, CONTAINER_FROM_METADATA_PARAMS) do |entry|
|
|
914
|
+
assert_equal CONTAINER_SECONDS_EPOCH, \
|
|
915
|
+
entry['metadata']['timestamp']['seconds'], entry
|
|
916
|
+
assert_equal CONTAINER_NANOS, \
|
|
917
|
+
entry['metadata']['timestamp']['nanos'], entry
|
|
918
|
+
assert_equal CONTAINER_SEVERITY, entry['metadata']['severity'], entry
|
|
919
|
+
end
|
|
862
920
|
end
|
|
863
921
|
end
|
|
864
922
|
|
|
@@ -869,7 +927,13 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
869
927
|
d = create_driver(APPLICATION_DEFAULT_CONFIG, CONTAINER_TAG)
|
|
870
928
|
d.emit(container_log_entry(log_entry(0)))
|
|
871
929
|
d.run
|
|
872
|
-
verify_log_entries(1, CONTAINER_FROM_TAG_PARAMS)
|
|
930
|
+
verify_log_entries(1, CONTAINER_FROM_TAG_PARAMS) do |entry|
|
|
931
|
+
assert_equal CONTAINER_SECONDS_EPOCH, \
|
|
932
|
+
entry['metadata']['timestamp']['seconds'], entry
|
|
933
|
+
assert_equal CONTAINER_NANOS, \
|
|
934
|
+
entry['metadata']['timestamp']['nanos'], entry
|
|
935
|
+
assert_equal CONTAINER_SEVERITY, entry['metadata']['severity'], entry
|
|
936
|
+
end
|
|
873
937
|
end
|
|
874
938
|
|
|
875
939
|
def test_multiple_container_logs_metadata_from_tag
|
|
@@ -884,7 +948,32 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
884
948
|
@logs_sent = []
|
|
885
949
|
n.times { |i| d.emit(container_log_entry(log_entry(i))) }
|
|
886
950
|
d.run
|
|
887
|
-
verify_log_entries(n, CONTAINER_FROM_TAG_PARAMS)
|
|
951
|
+
verify_log_entries(n, CONTAINER_FROM_TAG_PARAMS) do |entry|
|
|
952
|
+
assert_equal CONTAINER_SECONDS_EPOCH, \
|
|
953
|
+
entry['metadata']['timestamp']['seconds'], entry
|
|
954
|
+
assert_equal CONTAINER_NANOS, \
|
|
955
|
+
entry['metadata']['timestamp']['nanos'], entry
|
|
956
|
+
assert_equal CONTAINER_SEVERITY, entry['metadata']['severity'], entry
|
|
957
|
+
end
|
|
958
|
+
end
|
|
959
|
+
end
|
|
960
|
+
|
|
961
|
+
def test_one_container_log_from_tag_stderr
|
|
962
|
+
setup_gce_metadata_stubs
|
|
963
|
+
setup_container_metadata_stubs
|
|
964
|
+
setup_logging_stubs
|
|
965
|
+
d = create_driver(APPLICATION_DEFAULT_CONFIG, CONTAINER_TAG)
|
|
966
|
+
d.emit(container_log_entry(log_entry(0), 'stderr'))
|
|
967
|
+
d.run
|
|
968
|
+
expected_params = CONTAINER_FROM_TAG_PARAMS.merge(
|
|
969
|
+
labels: { "#{CONTAINER_SERVICE_NAME}/stream" => 'stderr' }
|
|
970
|
+
) { |_, oldval, newval| oldval.merge(newval) }
|
|
971
|
+
verify_log_entries(1, expected_params) do |entry|
|
|
972
|
+
assert_equal CONTAINER_SECONDS_EPOCH, \
|
|
973
|
+
entry['metadata']['timestamp']['seconds'], entry
|
|
974
|
+
assert_equal CONTAINER_NANOS, \
|
|
975
|
+
entry['metadata']['timestamp']['nanos'], entry
|
|
976
|
+
assert_equal 'ERROR', entry['metadata']['severity'], entry
|
|
888
977
|
end
|
|
889
978
|
end
|
|
890
979
|
|
|
@@ -894,7 +983,8 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
894
983
|
setup_logging_stubs
|
|
895
984
|
d = create_driver(APPLICATION_DEFAULT_CONFIG, CONTAINER_TAG)
|
|
896
985
|
d.emit(container_log_entry_with_metadata('{"msg": "test log entry 0", ' \
|
|
897
|
-
'"tag2": "test", "data": 5000
|
|
986
|
+
'"tag2": "test", "data": 5000, ' \
|
|
987
|
+
'"severity": "WARNING"}'))
|
|
898
988
|
d.run
|
|
899
989
|
verify_log_entries(1, CONTAINER_FROM_METADATA_PARAMS,
|
|
900
990
|
'structPayload') do |entry|
|
|
@@ -902,6 +992,11 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
902
992
|
assert_equal 'test log entry 0', entry['structPayload']['msg'], entry
|
|
903
993
|
assert_equal 'test', entry['structPayload']['tag2'], entry
|
|
904
994
|
assert_equal 5000, entry['structPayload']['data'], entry
|
|
995
|
+
assert_equal CONTAINER_SECONDS_EPOCH, \
|
|
996
|
+
entry['metadata']['timestamp']['seconds'], entry
|
|
997
|
+
assert_equal CONTAINER_NANOS, \
|
|
998
|
+
entry['metadata']['timestamp']['nanos'], entry
|
|
999
|
+
assert_equal 'WARNING', entry['metadata']['severity'], entry
|
|
905
1000
|
end
|
|
906
1001
|
end
|
|
907
1002
|
|
|
@@ -911,7 +1006,8 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
911
1006
|
setup_logging_stubs
|
|
912
1007
|
d = create_driver(APPLICATION_DEFAULT_CONFIG, CONTAINER_TAG)
|
|
913
1008
|
d.emit(container_log_entry('{"msg": "test log entry 0", ' \
|
|
914
|
-
'"tag2": "test", "data": 5000
|
|
1009
|
+
'"tag2": "test", "data": 5000, ' \
|
|
1010
|
+
'"severity": "W"}'))
|
|
915
1011
|
d.run
|
|
916
1012
|
verify_log_entries(1, CONTAINER_FROM_TAG_PARAMS,
|
|
917
1013
|
'structPayload') do |entry|
|
|
@@ -919,6 +1015,11 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
919
1015
|
assert_equal 'test log entry 0', entry['structPayload']['msg'], entry
|
|
920
1016
|
assert_equal 'test', entry['structPayload']['tag2'], entry
|
|
921
1017
|
assert_equal 5000, entry['structPayload']['data'], entry
|
|
1018
|
+
assert_equal CONTAINER_SECONDS_EPOCH, \
|
|
1019
|
+
entry['metadata']['timestamp']['seconds'], entry
|
|
1020
|
+
assert_equal CONTAINER_NANOS, \
|
|
1021
|
+
entry['metadata']['timestamp']['nanos'], entry
|
|
1022
|
+
assert_equal 'WARNING', entry['metadata']['severity'], entry
|
|
922
1023
|
end
|
|
923
1024
|
end
|
|
924
1025
|
|
|
@@ -1250,7 +1351,8 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
1250
1351
|
def container_log_entry_with_metadata(log)
|
|
1251
1352
|
{
|
|
1252
1353
|
log: log,
|
|
1253
|
-
stream:
|
|
1354
|
+
stream: CONTAINER_STREAM,
|
|
1355
|
+
time: CONTAINER_TIMESTAMP,
|
|
1254
1356
|
kubernetes: {
|
|
1255
1357
|
namespace_id: CONTAINER_NAMESPACE_ID,
|
|
1256
1358
|
namespace_name: CONTAINER_NAMESPACE_NAME,
|
|
@@ -1264,10 +1366,11 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
1264
1366
|
}
|
|
1265
1367
|
end
|
|
1266
1368
|
|
|
1267
|
-
def container_log_entry(log)
|
|
1369
|
+
def container_log_entry(log, stream = CONTAINER_STREAM)
|
|
1268
1370
|
{
|
|
1269
1371
|
log: log,
|
|
1270
|
-
stream:
|
|
1372
|
+
stream: stream,
|
|
1373
|
+
time: CONTAINER_TIMESTAMP
|
|
1271
1374
|
}
|
|
1272
1375
|
end
|
|
1273
1376
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fluent-plugin-google-cloud
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Todd Derr
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2016-
|
|
12
|
+
date: 2016-06-23 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: fluentd
|
|
@@ -18,6 +18,9 @@ dependencies:
|
|
|
18
18
|
- - "~>"
|
|
19
19
|
- !ruby/object:Gem::Version
|
|
20
20
|
version: '0.10'
|
|
21
|
+
- - "<="
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: '0.13'
|
|
21
24
|
type: :runtime
|
|
22
25
|
prerelease: false
|
|
23
26
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -25,6 +28,9 @@ dependencies:
|
|
|
25
28
|
- - "~>"
|
|
26
29
|
- !ruby/object:Gem::Version
|
|
27
30
|
version: '0.10'
|
|
31
|
+
- - "<="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0.13'
|
|
28
34
|
- !ruby/object:Gem::Dependency
|
|
29
35
|
name: google-api-client
|
|
30
36
|
requirement: !ruby/object:Gem::Requirement
|