fluent-plugin-google-cloud 0.6.13 → 0.6.14
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 +22 -21
- data/fluent-plugin-google-cloud.gemspec +5 -5
- data/lib/fluent/plugin/out_google_cloud.rb +147 -33
- data/test/plugin/base_test.rb +84 -50
- data/test/plugin/constants.rb +69 -2
- data/test/plugin/test_out_google_cloud_grpc.rb +53 -12
- metadata +16 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f370253a680adefd979f61cee26d87eedb36e3f8
|
|
4
|
+
data.tar.gz: bfd12ef42e11ce1cd51bee4bf356f9014ad07a67
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 671183d082caca469f7ded93eb737d07658beed0cce472806efeac2f303e810bd86049461a5ec5daef1d6d68436355bc4af81056ca0ee0c30a10f2a0047d86b9
|
|
7
|
+
data.tar.gz: d99f68afa553f93a280d0c648a24565c16bc1449af6d045cb31efc666e98c6c2d3406c1cf6879d77957a0513906fb87eb53a67c6133d37df523b81652aba87d9
|
data/Gemfile.lock
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
fluent-plugin-google-cloud (0.6.
|
|
4
|
+
fluent-plugin-google-cloud (0.6.14)
|
|
5
5
|
fluentd (~> 0.10)
|
|
6
|
-
google-api-client (~> 0.
|
|
7
|
-
google-cloud-logging (~> 1.
|
|
6
|
+
google-api-client (~> 0.17)
|
|
7
|
+
google-cloud-logging (~> 1.3, >= 1.3.2)
|
|
8
8
|
googleapis-common-protos (~> 1.3)
|
|
9
|
-
googleauth (~> 0.
|
|
10
|
-
grpc (~> 1.
|
|
9
|
+
googleauth (~> 0.6)
|
|
10
|
+
grpc (~> 1.0)
|
|
11
11
|
json (~> 1.8)
|
|
12
12
|
|
|
13
13
|
GEM
|
|
@@ -15,13 +15,13 @@ GEM
|
|
|
15
15
|
specs:
|
|
16
16
|
addressable (2.5.2)
|
|
17
17
|
public_suffix (>= 2.0.2, < 4.0)
|
|
18
|
-
ast (2.
|
|
18
|
+
ast (2.4.0)
|
|
19
19
|
cool.io (1.5.3)
|
|
20
20
|
crack (0.4.3)
|
|
21
21
|
safe_yaml (~> 1.0.0)
|
|
22
22
|
declarative (0.0.10)
|
|
23
23
|
declarative-option (0.1.0)
|
|
24
|
-
faraday (0.
|
|
24
|
+
faraday (0.14.0)
|
|
25
25
|
multipart-post (>= 1.2, < 3)
|
|
26
26
|
fluentd (0.14.25)
|
|
27
27
|
cool.io (>= 1.4.5, < 2.0.0)
|
|
@@ -34,7 +34,7 @@ GEM
|
|
|
34
34
|
tzinfo (~> 1.0)
|
|
35
35
|
tzinfo-data (~> 1.0)
|
|
36
36
|
yajl-ruby (~> 1.0)
|
|
37
|
-
google-api-client (0.19.
|
|
37
|
+
google-api-client (0.19.4)
|
|
38
38
|
addressable (~> 2.5, >= 2.5.1)
|
|
39
39
|
googleauth (>= 0.5, < 0.7.0)
|
|
40
40
|
httpclient (>= 2.8.1, < 3.0)
|
|
@@ -45,15 +45,15 @@ GEM
|
|
|
45
45
|
google-cloud-env (~> 1.0)
|
|
46
46
|
google-cloud-env (1.0.1)
|
|
47
47
|
faraday (~> 0.11)
|
|
48
|
-
google-cloud-logging (1.
|
|
49
|
-
google-cloud-core (~> 1.
|
|
50
|
-
google-gax (~>
|
|
48
|
+
google-cloud-logging (1.4.0)
|
|
49
|
+
google-cloud-core (~> 1.1)
|
|
50
|
+
google-gax (~> 1.0)
|
|
51
51
|
stackdriver-core (~> 1.2)
|
|
52
|
-
google-gax (0.
|
|
52
|
+
google-gax (1.0.1)
|
|
53
53
|
google-protobuf (~> 3.2)
|
|
54
|
-
googleapis-common-protos (
|
|
55
|
-
googleauth (~> 0.
|
|
56
|
-
grpc (
|
|
54
|
+
googleapis-common-protos (>= 1.3.5, < 2.0)
|
|
55
|
+
googleauth (~> 0.6.2)
|
|
56
|
+
grpc (>= 1.7.2, < 2.0)
|
|
57
57
|
rly (~> 0.2.3)
|
|
58
58
|
google-protobuf (3.5.1.1)
|
|
59
59
|
googleapis-common-protos (1.3.7)
|
|
@@ -62,22 +62,23 @@ GEM
|
|
|
62
62
|
grpc (~> 1.0)
|
|
63
63
|
googleapis-common-protos-types (1.0.1)
|
|
64
64
|
google-protobuf (~> 3.0)
|
|
65
|
-
googleauth (0.
|
|
65
|
+
googleauth (0.6.2)
|
|
66
66
|
faraday (~> 0.12)
|
|
67
|
-
jwt (
|
|
67
|
+
jwt (>= 1.4, < 3.0)
|
|
68
68
|
logging (~> 2.0)
|
|
69
69
|
memoist (~> 0.12)
|
|
70
70
|
multi_json (~> 1.11)
|
|
71
71
|
os (~> 0.9)
|
|
72
72
|
signet (~> 0.7)
|
|
73
|
-
grpc (1.
|
|
73
|
+
grpc (1.8.3)
|
|
74
74
|
google-protobuf (~> 3.1)
|
|
75
|
-
|
|
75
|
+
googleapis-common-protos-types (~> 1.0.0)
|
|
76
|
+
googleauth (>= 0.5.1, < 0.7)
|
|
76
77
|
hashdiff (0.3.7)
|
|
77
78
|
http_parser.rb (0.6.0)
|
|
78
79
|
httpclient (2.8.3)
|
|
79
80
|
json (1.8.6)
|
|
80
|
-
jwt (1.
|
|
81
|
+
jwt (2.1.0)
|
|
81
82
|
little-plugger (1.1.4)
|
|
82
83
|
logging (2.2.2)
|
|
83
84
|
little-plugger (~> 1.1)
|
|
@@ -134,7 +135,7 @@ GEM
|
|
|
134
135
|
thread_safe (0.3.6)
|
|
135
136
|
tzinfo (1.2.4)
|
|
136
137
|
thread_safe (~> 0.1)
|
|
137
|
-
tzinfo-data (1.
|
|
138
|
+
tzinfo-data (1.2018.3)
|
|
138
139
|
tzinfo (>= 1.0.0)
|
|
139
140
|
uber (0.1.0)
|
|
140
141
|
unicode-display_width (1.3.0)
|
|
@@ -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.6.
|
|
13
|
+
gem.version = '0.6.14'
|
|
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')
|
|
@@ -21,10 +21,10 @@ eos
|
|
|
21
21
|
|
|
22
22
|
gem.add_runtime_dependency 'fluentd', '~> 0.10'
|
|
23
23
|
gem.add_runtime_dependency 'googleapis-common-protos', '~> 1.3'
|
|
24
|
-
gem.add_runtime_dependency 'google-api-client', '~> 0.
|
|
25
|
-
gem.add_runtime_dependency 'google-cloud-logging', '~> 1.
|
|
26
|
-
gem.add_runtime_dependency 'googleauth', '~> 0.
|
|
27
|
-
gem.add_runtime_dependency 'grpc', '~> 1.
|
|
24
|
+
gem.add_runtime_dependency 'google-api-client', '~> 0.17'
|
|
25
|
+
gem.add_runtime_dependency 'google-cloud-logging', '~> 1.3', '>= 1.3.2'
|
|
26
|
+
gem.add_runtime_dependency 'googleauth', '~> 0.6'
|
|
27
|
+
gem.add_runtime_dependency 'grpc', '~> 1.0'
|
|
28
28
|
gem.add_runtime_dependency 'json', '~> 1.8'
|
|
29
29
|
|
|
30
30
|
gem.add_development_dependency 'mocha', '~> 1.1'
|
|
@@ -120,6 +120,7 @@ module Fluent
|
|
|
120
120
|
DEFAULT_SOURCE_LOCATION_KEY =
|
|
121
121
|
'logging.googleapis.com/sourceLocation'.freeze
|
|
122
122
|
DEFAULT_TRACE_KEY = 'logging.googleapis.com/trace'.freeze
|
|
123
|
+
DEFAULT_SPAN_ID_KEY = 'logging.googleapis.com/spanId'.freeze
|
|
123
124
|
|
|
124
125
|
DEFAULT_METADATA_AGENT_URL =
|
|
125
126
|
'http://local-metadata-agent.stackdriver.com:8000'.freeze
|
|
@@ -127,6 +128,8 @@ module Fluent
|
|
|
127
128
|
|
|
128
129
|
# Internal constants.
|
|
129
130
|
module InternalConstants
|
|
131
|
+
DEFAULT_LOGGING_API_URL = 'https://logging.googleapis.com'.freeze
|
|
132
|
+
|
|
130
133
|
# The label name of local_resource_id in the json payload. When a record
|
|
131
134
|
# has this field in the payload, we will use the value to retrieve
|
|
132
135
|
# monitored resource from Stackdriver Metadata agent.
|
|
@@ -195,7 +198,7 @@ module Fluent
|
|
|
195
198
|
Fluent::Plugin.register_output('google_cloud', self)
|
|
196
199
|
|
|
197
200
|
PLUGIN_NAME = 'Fluentd Google Cloud Logging plugin'.freeze
|
|
198
|
-
PLUGIN_VERSION = '0.6.
|
|
201
|
+
PLUGIN_VERSION = '0.6.14'.freeze
|
|
199
202
|
|
|
200
203
|
# Name of the the Google cloud logging write scope.
|
|
201
204
|
LOGGING_SCOPE = 'https://www.googleapis.com/auth/logging.write'.freeze
|
|
@@ -219,6 +222,9 @@ module Fluent
|
|
|
219
222
|
# Whether to attempt to obtain metadata from the local metadata service.
|
|
220
223
|
# It is safe to specify 'true' even on platforms with no metadata service.
|
|
221
224
|
config_param :use_metadata_service, :bool, :default => true
|
|
225
|
+
# A compatibility option to enable the legacy behavior of setting the AWS
|
|
226
|
+
# location to the availability zone rather than the region.
|
|
227
|
+
config_param :use_aws_availability_zone, :bool, :default => true
|
|
222
228
|
# These parameters override any values obtained from the metadata service.
|
|
223
229
|
config_param :project_id, :string, :default => nil
|
|
224
230
|
config_param :zone, :string, :default => nil
|
|
@@ -232,6 +238,7 @@ module Fluent
|
|
|
232
238
|
config_param :source_location_key, :string, :default =>
|
|
233
239
|
DEFAULT_SOURCE_LOCATION_KEY
|
|
234
240
|
config_param :trace_key, :string, :default => DEFAULT_TRACE_KEY
|
|
241
|
+
config_param :span_id_key, :string, :default => DEFAULT_SPAN_ID_KEY
|
|
235
242
|
|
|
236
243
|
# Whether to try to detect if the record is a text log entry with JSON
|
|
237
244
|
# content that needs to be parsed.
|
|
@@ -323,6 +330,12 @@ module Fluent
|
|
|
323
330
|
:default => nil,
|
|
324
331
|
:secret => true
|
|
325
332
|
|
|
333
|
+
# The URL of Stackdriver Logging API. Right now this only works with the
|
|
334
|
+
# gRPC path (use_grpc = true). An unsecured channel is used if the URL
|
|
335
|
+
# scheme is 'http' instead of 'https'. One common use case of this config is
|
|
336
|
+
# to provide a mocked / stubbed Logging API, e.g., http://localhost:52000.
|
|
337
|
+
config_param :logging_api_url, :string, :default => DEFAULT_LOGGING_API_URL
|
|
338
|
+
|
|
326
339
|
# Whether to collect metrics about the plugin usage. The mechanism for
|
|
327
340
|
# collecting and exposing metrics is controlled by the monitoring_type
|
|
328
341
|
# parameter.
|
|
@@ -368,11 +381,11 @@ module Fluent
|
|
|
368
381
|
|
|
369
382
|
# TODO(qingling128): Remove this warning after the support is added. Also
|
|
370
383
|
# remove the comment in the description of this configuration.
|
|
371
|
-
|
|
372
|
-
@log.warn 'Detected
|
|
373
|
-
' enabled.
|
|
374
|
-
' is
|
|
375
|
-
'
|
|
384
|
+
unless @logging_api_url == DEFAULT_LOGGING_API_URL || @use_grpc
|
|
385
|
+
@log.warn 'Detected customized logging_api_url while use_grpc is not' \
|
|
386
|
+
' enabled. Customized logging_api_url for the non-gRPC path' \
|
|
387
|
+
' is not supported. The logging_api_url option will be' \
|
|
388
|
+
' ignored.'
|
|
376
389
|
end
|
|
377
390
|
|
|
378
391
|
# If monitoring is enabled, register metrics in the default registry
|
|
@@ -397,7 +410,7 @@ module Fluent
|
|
|
397
410
|
'The number of log entries that failed to be ingested by the'\
|
|
398
411
|
' Stackdriver output plugin due to a transient error and were'\
|
|
399
412
|
' retried')
|
|
400
|
-
@ok_code = @use_grpc ?
|
|
413
|
+
@ok_code = @use_grpc ? GRPC::Core::StatusCodes::OK : 200
|
|
401
414
|
end
|
|
402
415
|
|
|
403
416
|
# Alert on old authentication configuration.
|
|
@@ -540,6 +553,9 @@ module Fluent
|
|
|
540
553
|
fq_trace_id = record.delete(@trace_key)
|
|
541
554
|
entry.trace = fq_trace_id if fq_trace_id
|
|
542
555
|
|
|
556
|
+
span_id = record.delete(@span_id_key)
|
|
557
|
+
entry.span_id = span_id if span_id
|
|
558
|
+
|
|
543
559
|
set_log_entry_fields(record, entry)
|
|
544
560
|
set_payload(entry_level_resource.type, record, entry, is_json)
|
|
545
561
|
|
|
@@ -634,7 +650,6 @@ module Fluent
|
|
|
634
650
|
client = api_client
|
|
635
651
|
entries_count = entries.length
|
|
636
652
|
client.write_log_entries(
|
|
637
|
-
# Ignore partial_success for gRPC path.
|
|
638
653
|
entries,
|
|
639
654
|
log_name: log_name,
|
|
640
655
|
# Leave resource nil if it's nil.
|
|
@@ -646,7 +661,8 @@ module Fluent
|
|
|
646
661
|
end,
|
|
647
662
|
labels: labels.map do |k, v|
|
|
648
663
|
[k.encode('utf-8'), convert_to_utf8(v)]
|
|
649
|
-
end.to_h
|
|
664
|
+
end.to_h,
|
|
665
|
+
partial_success: @partial_success
|
|
650
666
|
)
|
|
651
667
|
increment_successful_requests_count
|
|
652
668
|
increment_ingested_entries_count(entries_count)
|
|
@@ -683,14 +699,10 @@ module Fluent
|
|
|
683
699
|
# Most client errors indicate a problem with the request itself and
|
|
684
700
|
# should not be retried.
|
|
685
701
|
when \
|
|
686
|
-
# HTTP status 400 (Bad Request).
|
|
687
|
-
GRPC::InvalidArgument,
|
|
688
702
|
# HTTP status 401 (Unauthorized).
|
|
689
|
-
# These are usually solved via a `gcloud auth` call, or by
|
|
690
|
-
#
|
|
703
|
+
# These are usually solved via a `gcloud auth` call, or by modifying
|
|
704
|
+
# the permissions on the Google Cloud project.
|
|
691
705
|
GRPC::Unauthenticated,
|
|
692
|
-
# HTTP status 403 (Forbidden).
|
|
693
|
-
GRPC::PermissionDenied,
|
|
694
706
|
# HTTP status 404 (Not Found).
|
|
695
707
|
GRPC::NotFound,
|
|
696
708
|
# HTTP status 409 (Conflict).
|
|
@@ -711,6 +723,33 @@ module Fluent
|
|
|
711
723
|
@log.warn "Dropping #{entries_count} log message(s)",
|
|
712
724
|
error: error.to_s, error_code: error.code.to_s
|
|
713
725
|
|
|
726
|
+
# If partial_success is enabled, valid entries should have be
|
|
727
|
+
# written even if some other entries fail due to InvalidArgument or
|
|
728
|
+
# PermissionDenied errors. Only invalid entries will be dropped.
|
|
729
|
+
when \
|
|
730
|
+
# HTTP status 400 (Bad Request).
|
|
731
|
+
GRPC::InvalidArgument,
|
|
732
|
+
# HTTP status 403 (Forbidden).
|
|
733
|
+
GRPC::PermissionDenied
|
|
734
|
+
error_details_map = construct_error_details_map_grpc(gax_error)
|
|
735
|
+
if error_details_map.empty?
|
|
736
|
+
increment_dropped_entries_count(entries_count, error.code)
|
|
737
|
+
@log.warn "Dropping #{entries_count} log message(s)",
|
|
738
|
+
error: error.to_s, error_code: error.code.to_s
|
|
739
|
+
else
|
|
740
|
+
error_details_map.each do |(error_code, error_message), indexes|
|
|
741
|
+
partial_errors_count = indexes.length
|
|
742
|
+
increment_dropped_entries_count(partial_errors_count,
|
|
743
|
+
error_code)
|
|
744
|
+
entries_count -= partial_errors_count
|
|
745
|
+
@log.warn "Dropping #{partial_errors_count} log message(s)",
|
|
746
|
+
error: error_message, error_code: error_code.to_s
|
|
747
|
+
end
|
|
748
|
+
# Consider partially successful requests successful.
|
|
749
|
+
increment_successful_requests_count
|
|
750
|
+
increment_ingested_entries_count(entries_count)
|
|
751
|
+
end
|
|
752
|
+
|
|
714
753
|
else
|
|
715
754
|
# Assume it's a problem with the request itself and don't retry.
|
|
716
755
|
increment_failed_requests_count(error.code)
|
|
@@ -771,7 +810,7 @@ module Fluent
|
|
|
771
810
|
increment_failed_requests_count(error.status_code)
|
|
772
811
|
increment_dropped_entries_count(entries_count, error.status_code)
|
|
773
812
|
@log.warn "Dropping #{entries_count} log message(s)",
|
|
774
|
-
|
|
813
|
+
error: error.to_s, error_code: error.status_code.to_s
|
|
775
814
|
|
|
776
815
|
rescue Google::Apis::ClientError => error
|
|
777
816
|
# 4xx client errors. Most client errors indicate a problem with the
|
|
@@ -781,15 +820,15 @@ module Fluent
|
|
|
781
820
|
increment_failed_requests_count(error.status_code)
|
|
782
821
|
increment_dropped_entries_count(entries_count, error.status_code)
|
|
783
822
|
@log.warn "Dropping #{entries_count} log message(s)",
|
|
784
|
-
|
|
823
|
+
error: error.to_s, error_code: error.status_code.to_s
|
|
785
824
|
else
|
|
786
825
|
error_details_map.each do |(error_code, error_message), indexes|
|
|
787
|
-
|
|
788
|
-
increment_dropped_entries_count(
|
|
789
|
-
entries_count -=
|
|
790
|
-
@log.warn "Dropping #{
|
|
791
|
-
|
|
792
|
-
|
|
826
|
+
partial_errors_count = indexes.length
|
|
827
|
+
increment_dropped_entries_count(partial_errors_count, error_code)
|
|
828
|
+
entries_count -= partial_errors_count
|
|
829
|
+
@log.warn "Dropping #{partial_errors_count} log message(s)",
|
|
830
|
+
error: error_message,
|
|
831
|
+
error_code: "google.rpc.Code[#{error_code}]"
|
|
793
832
|
end
|
|
794
833
|
# Consider partially successful requests successful.
|
|
795
834
|
increment_successful_requests_count
|
|
@@ -945,8 +984,13 @@ module Fluent
|
|
|
945
984
|
# Response format: "projects/<number>/zones/<zone>"
|
|
946
985
|
@zone ||= fetch_gce_metadata('instance/zone').rpartition('/')[2] if
|
|
947
986
|
@platform == Platform::GCE
|
|
948
|
-
|
|
949
|
-
|
|
987
|
+
aws_location_key = if @use_aws_availability_zone
|
|
988
|
+
'availabilityZone'
|
|
989
|
+
else
|
|
990
|
+
'region'
|
|
991
|
+
end
|
|
992
|
+
@zone ||= 'aws:' + ec2_metadata[aws_location_key] if
|
|
993
|
+
@platform == Platform::EC2 && ec2_metadata.key?(aws_location_key)
|
|
950
994
|
rescue StandardError => e
|
|
951
995
|
@log.error 'Failed to obtain location: ', error: e
|
|
952
996
|
end
|
|
@@ -1828,13 +1872,24 @@ module Fluent
|
|
|
1828
1872
|
|
|
1829
1873
|
def init_api_client
|
|
1830
1874
|
if @use_grpc
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1875
|
+
uri = URI.parse(@logging_api_url)
|
|
1876
|
+
host = uri.host
|
|
1877
|
+
unless host
|
|
1878
|
+
raise Fluent::ConfigError,
|
|
1879
|
+
'The logging_api_url option specifies an invalid URL:' \
|
|
1880
|
+
" #{@logging_api_url}."
|
|
1881
|
+
end
|
|
1882
|
+
if uri.scheme == 'https'
|
|
1883
|
+
ssl_creds = GRPC::Core::ChannelCredentials.new
|
|
1884
|
+
authentication = Google::Auth.get_application_default
|
|
1885
|
+
creds = GRPC::Core::CallCredentials.new(authentication.updater_proc)
|
|
1886
|
+
creds = ssl_creds.compose(creds)
|
|
1887
|
+
else
|
|
1888
|
+
creds = :this_channel_is_insecure
|
|
1889
|
+
end
|
|
1890
|
+
port = ":#{uri.port}" if uri.port
|
|
1835
1891
|
@client = Google::Cloud::Logging::V2::LoggingServiceV2Client.new(
|
|
1836
|
-
|
|
1837
|
-
'logging.googleapis.com', nil, creds))
|
|
1892
|
+
credentials: GRPC::Core::Channel.new("#{host}#{port}", nil, creds))
|
|
1838
1893
|
else
|
|
1839
1894
|
# TODO: Use a non-default ClientOptions object.
|
|
1840
1895
|
Google::Apis::ClientOptions.default.application_name = PLUGIN_NAME
|
|
@@ -1885,8 +1940,8 @@ module Fluent
|
|
|
1885
1940
|
end
|
|
1886
1941
|
end
|
|
1887
1942
|
|
|
1888
|
-
# Extract a map of error details from
|
|
1889
|
-
# request. Return an empty map if @partial_success is not enabled.
|
|
1943
|
+
# Extract a map of error details from a potentially partially successful
|
|
1944
|
+
# REST request. Return an empty map if @partial_success is not enabled.
|
|
1890
1945
|
#
|
|
1891
1946
|
# The keys in this map are [error_code, error_message] pairs, and the values
|
|
1892
1947
|
# are a list of stringified indexes of log entries that failed due to this
|
|
@@ -1989,6 +2044,65 @@ module Fluent
|
|
|
1989
2044
|
{}
|
|
1990
2045
|
end
|
|
1991
2046
|
|
|
2047
|
+
# Extract a map of error details from a potentially partially successful
|
|
2048
|
+
# gRPC request. Return an empty map if @partial_success is not enabled.
|
|
2049
|
+
#
|
|
2050
|
+
# The keys in this map are [error_code, error_message] pairs, and the values
|
|
2051
|
+
# are a list of indexes of log entries that failed due to this error.
|
|
2052
|
+
#
|
|
2053
|
+
# A sample error looks like:
|
|
2054
|
+
# <Google::Gax::RetryError:
|
|
2055
|
+
# message: 'GaxError Exception occurred in retry method that was not class
|
|
2056
|
+
# ified as transient, caused by 7:User not authorized.',
|
|
2057
|
+
# details: [
|
|
2058
|
+
# <Google::Logging::V2::WriteLogEntriesPartialErrors:
|
|
2059
|
+
# log_entry_errors: {
|
|
2060
|
+
# 0 => <Google::Rpc::Status:
|
|
2061
|
+
# code: 7,
|
|
2062
|
+
# message: "User not authorized.",
|
|
2063
|
+
# details: []>,
|
|
2064
|
+
# 1 => <Google::Rpc::Status:
|
|
2065
|
+
# code: 3,
|
|
2066
|
+
# message: "Log name contains illegal character :",
|
|
2067
|
+
# details: []>,
|
|
2068
|
+
# 3 => <Google::Rpc::Status:
|
|
2069
|
+
# code: 3,
|
|
2070
|
+
# message: "Log name contains illegal character :",
|
|
2071
|
+
# details: []>
|
|
2072
|
+
# }
|
|
2073
|
+
# >,
|
|
2074
|
+
# <Google::Rpc::DebugInfo:
|
|
2075
|
+
# stack_entries: [],
|
|
2076
|
+
# detail: "..."
|
|
2077
|
+
# >
|
|
2078
|
+
# ]
|
|
2079
|
+
# cause: <GRPC::PermissionDenied: 7:User not authorized.>
|
|
2080
|
+
# }
|
|
2081
|
+
#
|
|
2082
|
+
# The ultimate map that is constructed is:
|
|
2083
|
+
# {
|
|
2084
|
+
# [7, 'User not authorized.']: [0],
|
|
2085
|
+
# [3, 'Log name contains illegal character :']: [1, 3]
|
|
2086
|
+
# }
|
|
2087
|
+
def construct_error_details_map_grpc(gax_error)
|
|
2088
|
+
return {} unless @partial_success
|
|
2089
|
+
error_details_map = Hash.new { |h, k| h[k] = [] }
|
|
2090
|
+
|
|
2091
|
+
error_details = ensure_array(gax_error.status_details)
|
|
2092
|
+
raise JSON::ParserError, 'The error details are empty.' if
|
|
2093
|
+
error_details.empty?
|
|
2094
|
+
log_entry_errors = ensure_hash(error_details[0].log_entry_errors)
|
|
2095
|
+
log_entry_errors.each do |index, log_entry_error|
|
|
2096
|
+
error_key = [log_entry_error[:code], log_entry_error[:message]].freeze
|
|
2097
|
+
error_details_map[error_key] << index
|
|
2098
|
+
end
|
|
2099
|
+
error_details_map
|
|
2100
|
+
rescue JSON::ParserError => e
|
|
2101
|
+
@log.warn 'Failed to extract log entry errors from the error details:' \
|
|
2102
|
+
" #{gax_error.details.inspect}.", error: e
|
|
2103
|
+
{}
|
|
2104
|
+
end
|
|
2105
|
+
|
|
1992
2106
|
def ensure_array(value)
|
|
1993
2107
|
Array.try_convert(value) || (raise JSON::ParserError, value.class.to_s)
|
|
1994
2108
|
end
|
data/test/plugin/base_test.rb
CHANGED
|
@@ -62,6 +62,17 @@ module BaseTest
|
|
|
62
62
|
assert_equal 1, exception_count
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
+
def test_configure_logging_api_url
|
|
66
|
+
setup_gce_metadata_stubs
|
|
67
|
+
{
|
|
68
|
+
APPLICATION_DEFAULT_CONFIG => DEFAULT_LOGGING_API_URL,
|
|
69
|
+
CUSTOM_LOGGING_API_URL_CONFIG => CUSTOM_LOGGING_API_URL
|
|
70
|
+
}.each do |(config, url)|
|
|
71
|
+
d = create_driver(config)
|
|
72
|
+
assert_equal url, d.instance.instance_variable_get(:@logging_api_url)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
65
76
|
def test_configure_custom_metadata
|
|
66
77
|
setup_no_metadata_service_stubs
|
|
67
78
|
d = create_driver(CUSTOM_METADATA_CONFIG)
|
|
@@ -163,7 +174,9 @@ module BaseTest
|
|
|
163
174
|
CONFIG_EC2_PROJECT_ID =>
|
|
164
175
|
['ec2', EC2_PROJECT_ID, EC2_PREFIXED_ZONE, EC2_VM_ID],
|
|
165
176
|
CONFIG_EC2_PROJECT_ID_AND_CUSTOM_VM_ID =>
|
|
166
|
-
['ec2', EC2_PROJECT_ID, EC2_PREFIXED_ZONE, CUSTOM_VM_ID]
|
|
177
|
+
['ec2', EC2_PROJECT_ID, EC2_PREFIXED_ZONE, CUSTOM_VM_ID],
|
|
178
|
+
CONFIG_EC2_PROJECT_ID_USE_REGION =>
|
|
179
|
+
['ec2', EC2_PROJECT_ID, EC2_PREFIXED_REGION, EC2_VM_ID]
|
|
167
180
|
}.each_with_index do |(config, parts), index|
|
|
168
181
|
send("setup_#{parts[0]}_metadata_stubs")
|
|
169
182
|
d = create_driver(config)
|
|
@@ -257,7 +270,18 @@ module BaseTest
|
|
|
257
270
|
d.emit('message' => log_entry(0))
|
|
258
271
|
d.run
|
|
259
272
|
end
|
|
260
|
-
verify_log_entries(1,
|
|
273
|
+
verify_log_entries(1, EC2_ZONE_PARAMS)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def test_one_log_ec2_region
|
|
277
|
+
ENV['GOOGLE_APPLICATION_CREDENTIALS'] = IAM_CREDENTIALS[:path]
|
|
278
|
+
setup_ec2_metadata_stubs
|
|
279
|
+
setup_logging_stubs do
|
|
280
|
+
d = create_driver(CONFIG_EC2_PROJECT_ID_USE_REGION)
|
|
281
|
+
d.emit('message' => log_entry(0))
|
|
282
|
+
d.run
|
|
283
|
+
end
|
|
284
|
+
verify_log_entries(1, EC2_REGION_PARAMS)
|
|
261
285
|
end
|
|
262
286
|
|
|
263
287
|
def test_structured_payload_log
|
|
@@ -1154,55 +1178,14 @@ module BaseTest
|
|
|
1154
1178
|
end
|
|
1155
1179
|
|
|
1156
1180
|
def test_log_entry_trace_field
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
{
|
|
1162
|
-
# It leaves trace entry field nil if no trace value sent.
|
|
1163
|
-
driver_config: APPLICATION_DEFAULT_CONFIG,
|
|
1164
|
-
emitted_log: { 'msg' => message },
|
|
1165
|
-
expected_fields: { 'msg' => message },
|
|
1166
|
-
expected_trace_value: nil
|
|
1167
|
-
},
|
|
1168
|
-
{
|
|
1169
|
-
# By default, it sets trace via Google-specific key.
|
|
1170
|
-
driver_config: APPLICATION_DEFAULT_CONFIG,
|
|
1171
|
-
emitted_log: { 'msg' => message, DEFAULT_TRACE_KEY => trace },
|
|
1172
|
-
expected_fields: { 'msg' => message },
|
|
1173
|
-
expected_trace_value: trace
|
|
1174
|
-
},
|
|
1175
|
-
{
|
|
1176
|
-
# It allows setting the trace via a custom configured key.
|
|
1177
|
-
driver_config: CONFIG_CUSTOM_TRACE_KEY_SPECIFIED,
|
|
1178
|
-
emitted_log: { 'msg' => message, 'custom_trace_key' => trace },
|
|
1179
|
-
expected_fields: { 'msg' => message },
|
|
1180
|
-
expected_trace_value: trace
|
|
1181
|
-
},
|
|
1182
|
-
{
|
|
1183
|
-
# It no longer sets trace by the default key if custom key specified.
|
|
1184
|
-
driver_config: CONFIG_CUSTOM_TRACE_KEY_SPECIFIED,
|
|
1185
|
-
emitted_log: { 'msg' => message, DEFAULT_TRACE_KEY => trace },
|
|
1186
|
-
expected_fields: { 'msg' => message, DEFAULT_TRACE_KEY => trace },
|
|
1187
|
-
expected_trace_value: nil
|
|
1188
|
-
}
|
|
1189
|
-
].each do |input|
|
|
1190
|
-
setup_logging_stubs do
|
|
1191
|
-
@logs_sent = []
|
|
1192
|
-
d = create_driver(input[:driver_config])
|
|
1193
|
-
d.emit(input[:emitted_log])
|
|
1194
|
-
d.run
|
|
1195
|
-
end
|
|
1196
|
-
verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
|
|
1197
|
-
assert_equal input[:expected_trace_value], entry['trace'], input
|
|
1181
|
+
verify_field_key('trace', DEFAULT_TRACE_KEY, 'custom_trace_key',
|
|
1182
|
+
CONFIG_CUSTOM_TRACE_KEY_SPECIFIED,
|
|
1183
|
+
'projects/proj1/traces/1234567890abcdef1234567890abcdef')
|
|
1184
|
+
end
|
|
1198
1185
|
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
assert_equal input[:expected_fields][key], get_string(value), input
|
|
1203
|
-
end
|
|
1204
|
-
end
|
|
1205
|
-
end
|
|
1186
|
+
def test_log_entry_span_id_field
|
|
1187
|
+
verify_field_key('spanId', DEFAULT_SPAN_ID_KEY, 'custom_span_id_key',
|
|
1188
|
+
CONFIG_CUSTOM_SPAN_ID_KEY_SPECIFIED, '000000000000004a')
|
|
1206
1189
|
end
|
|
1207
1190
|
|
|
1208
1191
|
# Metadata Agent related tests.
|
|
@@ -1765,6 +1748,57 @@ module BaseTest
|
|
|
1765
1748
|
end
|
|
1766
1749
|
end
|
|
1767
1750
|
|
|
1751
|
+
def verify_field_key(log_entry_field, default_key, custom_key,
|
|
1752
|
+
custom_key_config, sample_value)
|
|
1753
|
+
setup_gce_metadata_stubs
|
|
1754
|
+
message = log_entry(0)
|
|
1755
|
+
[
|
|
1756
|
+
{
|
|
1757
|
+
# It leaves log entry field nil if no keyed value sent.
|
|
1758
|
+
driver_config: APPLICATION_DEFAULT_CONFIG,
|
|
1759
|
+
emitted_log: { 'msg' => message },
|
|
1760
|
+
expected_payload: { 'msg' => message },
|
|
1761
|
+
expected_field_value: nil
|
|
1762
|
+
},
|
|
1763
|
+
{
|
|
1764
|
+
# By default, it sets log entry field via a default key.
|
|
1765
|
+
driver_config: APPLICATION_DEFAULT_CONFIG,
|
|
1766
|
+
emitted_log: { 'msg' => message, default_key => sample_value },
|
|
1767
|
+
expected_payload: { 'msg' => message },
|
|
1768
|
+
expected_field_value: sample_value
|
|
1769
|
+
},
|
|
1770
|
+
{
|
|
1771
|
+
# It allows setting the log entry field via a custom configured key.
|
|
1772
|
+
driver_config: custom_key_config,
|
|
1773
|
+
emitted_log: { 'msg' => message, custom_key => sample_value },
|
|
1774
|
+
expected_payload: { 'msg' => message },
|
|
1775
|
+
expected_field_value: sample_value
|
|
1776
|
+
},
|
|
1777
|
+
{
|
|
1778
|
+
# It doesn't set log entry field by default key if custom key specified.
|
|
1779
|
+
driver_config: custom_key_config,
|
|
1780
|
+
emitted_log: { 'msg' => message, default_key => sample_value },
|
|
1781
|
+
expected_payload: { 'msg' => message, default_key => sample_value },
|
|
1782
|
+
expected_field_value: nil
|
|
1783
|
+
}
|
|
1784
|
+
].each do |input|
|
|
1785
|
+
setup_logging_stubs do
|
|
1786
|
+
@logs_sent = []
|
|
1787
|
+
d = create_driver(input[:driver_config])
|
|
1788
|
+
d.emit(input[:emitted_log])
|
|
1789
|
+
d.run
|
|
1790
|
+
end
|
|
1791
|
+
verify_log_entries(1, COMPUTE_PARAMS, 'jsonPayload') do |entry|
|
|
1792
|
+
assert_equal input[:expected_field_value], entry[log_entry_field], input
|
|
1793
|
+
payload_fields = get_fields(entry['jsonPayload'])
|
|
1794
|
+
assert_equal input[:expected_payload].size, payload_fields.size, input
|
|
1795
|
+
payload_fields.each do |key, value|
|
|
1796
|
+
assert_equal input[:expected_payload][key], get_string(value), input
|
|
1797
|
+
end
|
|
1798
|
+
end
|
|
1799
|
+
end
|
|
1800
|
+
end
|
|
1801
|
+
|
|
1768
1802
|
def http_request_message
|
|
1769
1803
|
HTTP_REQUEST_MESSAGE
|
|
1770
1804
|
end
|
data/test/plugin/constants.rb
CHANGED
|
@@ -20,6 +20,7 @@ module Constants
|
|
|
20
20
|
|
|
21
21
|
# Generic attributes.
|
|
22
22
|
HOSTNAME = Socket.gethostname
|
|
23
|
+
CUSTOM_LOGGING_API_URL = 'http://localhost:52000'.freeze
|
|
23
24
|
|
|
24
25
|
# TODO(qingling128) Separate constants into different submodules.
|
|
25
26
|
# Attributes used for the GCE metadata service.
|
|
@@ -43,6 +44,8 @@ module Constants
|
|
|
43
44
|
EC2_PROJECT_ID = 'test-ec2-project-id'.freeze
|
|
44
45
|
EC2_ZONE = 'us-west-2b'.freeze
|
|
45
46
|
EC2_PREFIXED_ZONE = "aws:#{EC2_ZONE}".freeze
|
|
47
|
+
EC2_REGION = 'us-west-2'.freeze
|
|
48
|
+
EC2_PREFIXED_REGION = "aws:#{EC2_REGION}".freeze
|
|
46
49
|
EC2_VM_ID = 'i-81c16767'.freeze
|
|
47
50
|
EC2_ACCOUNT_ID = '123456789012'.freeze
|
|
48
51
|
|
|
@@ -50,6 +53,7 @@ module Constants
|
|
|
50
53
|
EC2_IDENTITY_DOCUMENT = %({
|
|
51
54
|
"accountId" : "#{EC2_ACCOUNT_ID}",
|
|
52
55
|
"availabilityZone" : "#{EC2_ZONE}",
|
|
56
|
+
"region" : "#{EC2_REGION}",
|
|
53
57
|
"instanceId" : "#{EC2_VM_ID}"
|
|
54
58
|
}).freeze
|
|
55
59
|
|
|
@@ -138,6 +142,10 @@ module Constants
|
|
|
138
142
|
APPLICATION_DEFAULT_CONFIG = %(
|
|
139
143
|
).freeze
|
|
140
144
|
|
|
145
|
+
CUSTOM_LOGGING_API_URL_CONFIG = %(
|
|
146
|
+
logging_api_url #{CUSTOM_LOGGING_API_URL}
|
|
147
|
+
).freeze
|
|
148
|
+
|
|
141
149
|
DETECT_JSON_CONFIG = %(
|
|
142
150
|
detect_json true
|
|
143
151
|
).freeze
|
|
@@ -220,6 +228,11 @@ module Constants
|
|
|
220
228
|
vm_id #{CUSTOM_VM_ID}
|
|
221
229
|
).freeze
|
|
222
230
|
|
|
231
|
+
CONFIG_EC2_PROJECT_ID_USE_REGION = %(
|
|
232
|
+
project_id #{EC2_PROJECT_ID}
|
|
233
|
+
use_aws_availability_zone false
|
|
234
|
+
).freeze
|
|
235
|
+
|
|
223
236
|
CONFIG_DATAFLOW = %(
|
|
224
237
|
subservice_name "#{DATAFLOW_CONSTANTS[:service]}"
|
|
225
238
|
labels {
|
|
@@ -244,6 +257,10 @@ module Constants
|
|
|
244
257
|
trace_key custom_trace_key
|
|
245
258
|
).freeze
|
|
246
259
|
|
|
260
|
+
CONFIG_CUSTOM_SPAN_ID_KEY_SPECIFIED = %(
|
|
261
|
+
span_id_key custom_span_id_key
|
|
262
|
+
).freeze
|
|
263
|
+
|
|
247
264
|
# Service configurations for various services.
|
|
248
265
|
|
|
249
266
|
# GCE.
|
|
@@ -506,12 +523,12 @@ module Constants
|
|
|
506
523
|
}
|
|
507
524
|
}.freeze
|
|
508
525
|
|
|
509
|
-
|
|
526
|
+
EC2_REGION_PARAMS = {
|
|
510
527
|
resource: {
|
|
511
528
|
type: EC2_CONSTANTS[:resource_type],
|
|
512
529
|
labels: {
|
|
513
530
|
'instance_id' => EC2_VM_ID,
|
|
514
|
-
'region' =>
|
|
531
|
+
'region' => EC2_PREFIXED_REGION,
|
|
515
532
|
'aws_account' => EC2_ACCOUNT_ID
|
|
516
533
|
}
|
|
517
534
|
},
|
|
@@ -522,6 +539,14 @@ module Constants
|
|
|
522
539
|
}
|
|
523
540
|
}.freeze
|
|
524
541
|
|
|
542
|
+
EC2_ZONE_PARAMS = EC2_REGION_PARAMS.merge(
|
|
543
|
+
resource: EC2_REGION_PARAMS[:resource].merge(
|
|
544
|
+
labels: EC2_REGION_PARAMS[:resource][:labels].merge(
|
|
545
|
+
'region' => EC2_PREFIXED_ZONE
|
|
546
|
+
)
|
|
547
|
+
)
|
|
548
|
+
).freeze
|
|
549
|
+
|
|
525
550
|
HTTP_REQUEST_MESSAGE = {
|
|
526
551
|
'requestMethod' => 'POST',
|
|
527
552
|
'requestUrl' => 'http://example/',
|
|
@@ -651,4 +676,46 @@ module Constants
|
|
|
651
676
|
]
|
|
652
677
|
}
|
|
653
678
|
}.freeze
|
|
679
|
+
|
|
680
|
+
# rubocop:disable Style/StringLiterals
|
|
681
|
+
PARTIAL_SUCCESS_GRPC_METADATA = {
|
|
682
|
+
'google.logging.v2.writelogentriespartialerrors-bin' =>
|
|
683
|
+
Google::Logging::V2::WriteLogEntriesPartialErrors.encode(
|
|
684
|
+
Google::Logging::V2::WriteLogEntriesPartialErrors.new(
|
|
685
|
+
log_entry_errors: {
|
|
686
|
+
0 => Google::Rpc::Status.new(
|
|
687
|
+
code: GRPC::Core::StatusCodes::PERMISSION_DENIED,
|
|
688
|
+
message: "User not authorized.",
|
|
689
|
+
details: []),
|
|
690
|
+
1 => Google::Rpc::Status.new(
|
|
691
|
+
code: GRPC::Core::StatusCodes::INVALID_ARGUMENT,
|
|
692
|
+
message: "Log name contains illegal character :",
|
|
693
|
+
details: []),
|
|
694
|
+
3 => Google::Rpc::Status.new(
|
|
695
|
+
code: GRPC::Core::StatusCodes::INVALID_ARGUMENT,
|
|
696
|
+
message: "Log name contains illegal character :",
|
|
697
|
+
details: []) })),
|
|
698
|
+
'google.rpc.debuginfo-bin' =>
|
|
699
|
+
"\x12\xA7\x03[ORIGINAL ERROR] generic::permission_denied: User not auth" \
|
|
700
|
+
"orized. [google.rpc.error_details_ext] { message: \"User not authorize" \
|
|
701
|
+
"d.\" details { type_url: \"type.googleapis.com/google.logging.v2.Write" \
|
|
702
|
+
"LogEntriesPartialErrors\" value: \"\\n\\034\\010\\000\\022\\030\\010\\" \
|
|
703
|
+
"007\\022\\024User not authorized.\\n-\\010\\001\\022)\\010\\003\\022%L" \
|
|
704
|
+
"og name contains illegal character :\\n-\\010\\002\\022)\\010\\003\\02" \
|
|
705
|
+
"2%Log name contains illegal character :\" } }",
|
|
706
|
+
'grpc-status-details-bin' =>
|
|
707
|
+
"\b\a\x12\x14User not authorized.\x1A\xC2\x01\nBtype.googleapis.com/goo" \
|
|
708
|
+
"gle.logging.v2.WriteLogEntriesPartialErrors\x12|\n\x1C\b\x00\x12\x18\b" \
|
|
709
|
+
"\a\x12\x14User not authorized.\n-\b\x01\x12)\b\x03\x12%Log name contai" \
|
|
710
|
+
"ns illegal character :\n-\b\x02\x12)\b\x03\x12%Log name contains illeg" \
|
|
711
|
+
"al character :\x1A\xD7\x03\n(type.googleapis.com/google.rpc.DebugInfo" \
|
|
712
|
+
"\x12\xAA\x03\x12\xA7\x03[ORIGINAL ERROR] generic::permission_denied: U" \
|
|
713
|
+
"ser not authorized. [google.rpc.error_details_ext] { message: \"User n" \
|
|
714
|
+
"ot authorized.\" details { type_url: \"type.googleapis.com/google.logg" \
|
|
715
|
+
"ing.v2.WriteLogEntriesPartialErrors\" value: \"\\n\\034\\010\\000\\022" \
|
|
716
|
+
"\\030\\010\\007\\022\\024User not authorized.\\n-\\010\\001\\022)\\010" \
|
|
717
|
+
"\\003\\022%Log name contains illegal character :\\n-\\010\\002\\022)" \
|
|
718
|
+
"\\010\\003\\022%Log name contains illegal character :\" } }"
|
|
719
|
+
}.freeze
|
|
720
|
+
# rubocop:enable Style/StringLiterals
|
|
654
721
|
end
|
|
@@ -51,6 +51,39 @@ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
|
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
def test_partial_success
|
|
55
|
+
setup_gce_metadata_stubs
|
|
56
|
+
setup_prometheus
|
|
57
|
+
setup_logging_stubs(
|
|
58
|
+
true, GRPC::Core::StatusCodes::PERMISSION_DENIED,
|
|
59
|
+
'User not authorized.', PARTIAL_SUCCESS_GRPC_METADATA) do
|
|
60
|
+
# The API Client should not retry this and the plugin should consume
|
|
61
|
+
# the exception.
|
|
62
|
+
d = create_driver(PROMETHEUS_ENABLE_CONFIG + PARTIAL_SUCCESS_CONFIG)
|
|
63
|
+
4.times do |i|
|
|
64
|
+
d.emit('message' => log_entry(i.to_s))
|
|
65
|
+
end
|
|
66
|
+
d.run
|
|
67
|
+
assert_prometheus_metric_value(
|
|
68
|
+
:stackdriver_successful_requests_count, 1,
|
|
69
|
+
grpc: true, code: GRPC::Core::StatusCodes::OK)
|
|
70
|
+
assert_prometheus_metric_value(
|
|
71
|
+
:stackdriver_failed_requests_count, 0,
|
|
72
|
+
grpc: true, code: GRPC::Core::StatusCodes::PERMISSION_DENIED)
|
|
73
|
+
assert_prometheus_metric_value(
|
|
74
|
+
:stackdriver_ingested_entries_count, 1,
|
|
75
|
+
grpc: true, code: GRPC::Core::StatusCodes::OK)
|
|
76
|
+
assert_prometheus_metric_value(
|
|
77
|
+
:stackdriver_dropped_entries_count, 2,
|
|
78
|
+
grpc: true, code: GRPC::Core::StatusCodes::INVALID_ARGUMENT)
|
|
79
|
+
assert_prometheus_metric_value(
|
|
80
|
+
:stackdriver_dropped_entries_count, 1,
|
|
81
|
+
grpc: true, code: GRPC::Core::StatusCodes::PERMISSION_DENIED)
|
|
82
|
+
assert_prometheus_metric_value(
|
|
83
|
+
:stackdriver_retried_entries_count, 0, grpc: true)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
54
87
|
def test_server_error
|
|
55
88
|
setup_gce_metadata_stubs
|
|
56
89
|
{
|
|
@@ -246,11 +279,6 @@ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
|
|
|
246
279
|
end
|
|
247
280
|
|
|
248
281
|
def api_client
|
|
249
|
-
ssl_creds = GRPC::Core::ChannelCredentials.new
|
|
250
|
-
authentication = Google::Auth.get_application_default
|
|
251
|
-
creds = GRPC::Core::CallCredentials.new(authentication.updater_proc)
|
|
252
|
-
ssl_creds.compose(creds)
|
|
253
|
-
|
|
254
282
|
@grpc_stub
|
|
255
283
|
end
|
|
256
284
|
end
|
|
@@ -263,12 +291,17 @@ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
|
|
|
263
291
|
@requests_received = requests_received
|
|
264
292
|
end
|
|
265
293
|
|
|
266
|
-
def write_log_entries(entries,
|
|
294
|
+
def write_log_entries(entries,
|
|
295
|
+
log_name: nil,
|
|
296
|
+
resource: nil,
|
|
297
|
+
labels: nil,
|
|
298
|
+
partial_success: nil)
|
|
267
299
|
request = Google::Apis::LoggingV2::WriteLogEntriesRequest.new(
|
|
268
300
|
log_name: log_name,
|
|
269
301
|
resource: resource,
|
|
270
302
|
labels: labels,
|
|
271
|
-
entries: entries
|
|
303
|
+
entries: entries,
|
|
304
|
+
partial_success: partial_success
|
|
272
305
|
)
|
|
273
306
|
@requests_received << request
|
|
274
307
|
WriteLogEntriesResponse.new
|
|
@@ -278,18 +311,23 @@ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
|
|
|
278
311
|
# GRPC logging mock that fails and returns server side or client side errors.
|
|
279
312
|
class GRPCLoggingMockFailingService <
|
|
280
313
|
Google::Cloud::Logging::V2::LoggingServiceV2Client
|
|
281
|
-
def initialize(code, message, failed_attempts)
|
|
314
|
+
def initialize(code, message, metadata, failed_attempts)
|
|
282
315
|
@code = code
|
|
283
316
|
@message = message
|
|
317
|
+
@metadata = metadata
|
|
284
318
|
@failed_attempts = failed_attempts
|
|
285
319
|
super()
|
|
286
320
|
end
|
|
287
321
|
|
|
288
322
|
# rubocop:disable Lint/UnusedMethodArgument
|
|
289
|
-
def write_log_entries(entries,
|
|
323
|
+
def write_log_entries(entries,
|
|
324
|
+
log_name: nil,
|
|
325
|
+
resource: nil,
|
|
326
|
+
labels: nil,
|
|
327
|
+
partial_success: nil)
|
|
290
328
|
@failed_attempts << 1
|
|
291
329
|
begin
|
|
292
|
-
raise GRPC::BadStatus.new_status_exception(@code, @message)
|
|
330
|
+
raise GRPC::BadStatus.new_status_exception(@code, @message, @metadata)
|
|
293
331
|
rescue
|
|
294
332
|
# Google::Gax::GaxError will wrap the latest thrown exception as @cause.
|
|
295
333
|
raise Google::Gax::GaxError, @message
|
|
@@ -299,11 +337,14 @@ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
|
|
|
299
337
|
end
|
|
300
338
|
|
|
301
339
|
# Set up grpc stubs to mock the external calls.
|
|
302
|
-
def setup_logging_stubs(should_fail = false,
|
|
340
|
+
def setup_logging_stubs(should_fail = false,
|
|
341
|
+
code = nil,
|
|
342
|
+
message = nil,
|
|
343
|
+
metadata = {})
|
|
303
344
|
if should_fail
|
|
304
345
|
@failed_attempts = []
|
|
305
346
|
@grpc_stub = GRPCLoggingMockFailingService.new(
|
|
306
|
-
code, message, @failed_attempts)
|
|
347
|
+
code, message, metadata, @failed_attempts)
|
|
307
348
|
else
|
|
308
349
|
@requests_sent = []
|
|
309
350
|
@grpc_stub = GRPCLoggingMockService.new(@requests_sent)
|
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.6.
|
|
4
|
+
version: 0.6.14
|
|
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: 2018-01-
|
|
12
|
+
date: 2018-01-25 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: fluentd
|
|
@@ -45,56 +45,62 @@ dependencies:
|
|
|
45
45
|
requirements:
|
|
46
46
|
- - "~>"
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
|
-
version: '0.
|
|
48
|
+
version: '0.17'
|
|
49
49
|
type: :runtime
|
|
50
50
|
prerelease: false
|
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
|
52
52
|
requirements:
|
|
53
53
|
- - "~>"
|
|
54
54
|
- !ruby/object:Gem::Version
|
|
55
|
-
version: '0.
|
|
55
|
+
version: '0.17'
|
|
56
56
|
- !ruby/object:Gem::Dependency
|
|
57
57
|
name: google-cloud-logging
|
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
|
59
59
|
requirements:
|
|
60
60
|
- - "~>"
|
|
61
61
|
- !ruby/object:Gem::Version
|
|
62
|
-
version: 1.
|
|
62
|
+
version: '1.3'
|
|
63
|
+
- - ">="
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: 1.3.2
|
|
63
66
|
type: :runtime
|
|
64
67
|
prerelease: false
|
|
65
68
|
version_requirements: !ruby/object:Gem::Requirement
|
|
66
69
|
requirements:
|
|
67
70
|
- - "~>"
|
|
68
71
|
- !ruby/object:Gem::Version
|
|
69
|
-
version: 1.
|
|
72
|
+
version: '1.3'
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 1.3.2
|
|
70
76
|
- !ruby/object:Gem::Dependency
|
|
71
77
|
name: googleauth
|
|
72
78
|
requirement: !ruby/object:Gem::Requirement
|
|
73
79
|
requirements:
|
|
74
80
|
- - "~>"
|
|
75
81
|
- !ruby/object:Gem::Version
|
|
76
|
-
version: '0.
|
|
82
|
+
version: '0.6'
|
|
77
83
|
type: :runtime
|
|
78
84
|
prerelease: false
|
|
79
85
|
version_requirements: !ruby/object:Gem::Requirement
|
|
80
86
|
requirements:
|
|
81
87
|
- - "~>"
|
|
82
88
|
- !ruby/object:Gem::Version
|
|
83
|
-
version: '0.
|
|
89
|
+
version: '0.6'
|
|
84
90
|
- !ruby/object:Gem::Dependency
|
|
85
91
|
name: grpc
|
|
86
92
|
requirement: !ruby/object:Gem::Requirement
|
|
87
93
|
requirements:
|
|
88
94
|
- - "~>"
|
|
89
95
|
- !ruby/object:Gem::Version
|
|
90
|
-
version: 1.
|
|
96
|
+
version: '1.0'
|
|
91
97
|
type: :runtime
|
|
92
98
|
prerelease: false
|
|
93
99
|
version_requirements: !ruby/object:Gem::Requirement
|
|
94
100
|
requirements:
|
|
95
101
|
- - "~>"
|
|
96
102
|
- !ruby/object:Gem::Version
|
|
97
|
-
version: 1.
|
|
103
|
+
version: '1.0'
|
|
98
104
|
- !ruby/object:Gem::Dependency
|
|
99
105
|
name: json
|
|
100
106
|
requirement: !ruby/object:Gem::Requirement
|