fluent-plugin-google-cloud 0.6.20 → 0.6.21
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/fluent-plugin-google-cloud.gemspec +1 -1
- data/lib/fluent/plugin/out_google_cloud.rb +54 -37
- data/test/plugin/base_test.rb +61 -54
- data/test/plugin/constants.rb +98 -40
- data/test/plugin/test_out_google_cloud.rb +25 -0
- data/test/plugin/test_out_google_cloud_grpc.rb +28 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 33b71adc0c744f682e9f3548911ec4f550988864
|
|
4
|
+
data.tar.gz: 3c45d732c056e34e32f05f2708012f4b69205cca
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9dab6cb5bcecc828bc025458f3adb04ba0690fcac1052c936a7e3beaebca7ea35de72295f694e73342c92a5cf1129be7bcc2e5040d405280bb23822c6f7521fb
|
|
7
|
+
data.tar.gz: 4ea689e785e16c15c4b30286203aaf54caa5e23aa1987a30252f75ec02278a41a3fa064170e4b5233de9f2104cdf1ae86f7012dd85c19f773c44e25034cfcf10
|
|
@@ -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.21'
|
|
14
14
|
gem.authors = ['Ling Huang', 'Igor Peshansky']
|
|
15
15
|
gem.email = ['stackdriver-agents@google.com']
|
|
16
16
|
gem.required_ruby_version = Gem::Requirement.new('>= 2.2')
|
|
@@ -227,7 +227,7 @@ module Fluent
|
|
|
227
227
|
Fluent::Plugin.register_output('google_cloud', self)
|
|
228
228
|
|
|
229
229
|
PLUGIN_NAME = 'Fluentd Google Cloud Logging plugin'.freeze
|
|
230
|
-
PLUGIN_VERSION = '0.6.
|
|
230
|
+
PLUGIN_VERSION = '0.6.21'.freeze
|
|
231
231
|
|
|
232
232
|
# Name of the the Google cloud logging write scope.
|
|
233
233
|
LOGGING_SCOPE = 'https://www.googleapis.com/auth/logging.write'.freeze
|
|
@@ -396,6 +396,9 @@ module Fluent
|
|
|
396
396
|
# requests when talking to Stackdriver Logging API.
|
|
397
397
|
config_param :split_logs_by_tag, :bool, :default => false
|
|
398
398
|
|
|
399
|
+
# Whether to attempt adjusting invalid log entry timestamps.
|
|
400
|
+
config_param :adjust_invalid_timestamps, :bool, :default => true
|
|
401
|
+
|
|
399
402
|
# rubocop:enable Style/HashSyntax
|
|
400
403
|
|
|
401
404
|
# TODO: Add a log_name config option rather than just using the tag?
|
|
@@ -792,6 +795,7 @@ module Fluent
|
|
|
792
795
|
GRPC::PermissionDenied
|
|
793
796
|
error_details_map = construct_error_details_map_grpc(gax_error)
|
|
794
797
|
if error_details_map.empty?
|
|
798
|
+
increment_failed_requests_count(error.code)
|
|
795
799
|
increment_dropped_entries_count(entries_count, error.code)
|
|
796
800
|
@log.warn "Dropping #{entries_count} log message(s)",
|
|
797
801
|
error: error.to_s, error_code: error.code.to_s
|
|
@@ -1249,27 +1253,10 @@ module Fluent
|
|
|
1249
1253
|
# Examples:
|
|
1250
1254
|
# "container.<container_id>" // Docker container.
|
|
1251
1255
|
# "k8s_pod.<namespace_name>.<pod_name>" // GKE pod.
|
|
1252
|
-
if
|
|
1253
|
-
|
|
1254
|
-
"#{local_resource_id}."
|
|
1255
|
-
retrieved_resource = query_metadata_agent_for_monitored_resource(
|
|
1256
|
+
if local_resource_id
|
|
1257
|
+
converted_resource = monitored_resource_from_local_resource_id(
|
|
1256
1258
|
local_resource_id)
|
|
1257
|
-
|
|
1258
|
-
"#{retrieved_resource.inspect}."
|
|
1259
|
-
if retrieved_resource
|
|
1260
|
-
resource = retrieved_resource
|
|
1261
|
-
# TODO(qingling128): Fix this temporary renaming from 'gke_container'
|
|
1262
|
-
# to 'container'.
|
|
1263
|
-
resource.type = 'container' if resource.type == 'gke_container'
|
|
1264
|
-
else
|
|
1265
|
-
# TODO(qingling128): This entire else clause is temporary before we
|
|
1266
|
-
# implement buffering and caching.
|
|
1267
|
-
@log.warn('Failed to retrieve monitored resource from Metadata' \
|
|
1268
|
-
" Agent with local_resource_id #{local_resource_id}.")
|
|
1269
|
-
constructed_k8s_resource = construct_k8s_resource_locally(
|
|
1270
|
-
local_resource_id)
|
|
1271
|
-
resource = constructed_k8s_resource if constructed_k8s_resource
|
|
1272
|
-
end
|
|
1259
|
+
resource = converted_resource if converted_resource
|
|
1273
1260
|
end
|
|
1274
1261
|
|
|
1275
1262
|
# Once the resource type is settled down, determine the labels.
|
|
@@ -1349,6 +1336,32 @@ module Fluent
|
|
|
1349
1336
|
[resource, common_labels]
|
|
1350
1337
|
end
|
|
1351
1338
|
|
|
1339
|
+
# Take a locally unique resource id and convert it to the globally unique
|
|
1340
|
+
# monitored resource.
|
|
1341
|
+
def monitored_resource_from_local_resource_id(local_resource_id)
|
|
1342
|
+
return unless local_resource_id
|
|
1343
|
+
if @enable_metadata_agent
|
|
1344
|
+
@log.debug 'Calling metadata agent with local_resource_id: ' \
|
|
1345
|
+
"#{local_resource_id}."
|
|
1346
|
+
resource = query_metadata_agent_for_monitored_resource(
|
|
1347
|
+
local_resource_id)
|
|
1348
|
+
@log.debug 'Retrieved monitored resource from metadata agent: ' \
|
|
1349
|
+
"#{resource.inspect}."
|
|
1350
|
+
if resource
|
|
1351
|
+
# TODO(qingling128): Fix this temporary renaming from 'gke_container'
|
|
1352
|
+
# to 'container'.
|
|
1353
|
+
resource.type = 'container' if resource.type == 'gke_container'
|
|
1354
|
+
return resource
|
|
1355
|
+
end
|
|
1356
|
+
end
|
|
1357
|
+
# Fall back to constructing monitored resource locally.
|
|
1358
|
+
# TODO(qingling128): This entire else clause is temporary until we
|
|
1359
|
+
# implement buffering and caching.
|
|
1360
|
+
@log.debug('Failed to retrieve monitored resource from Metadata' \
|
|
1361
|
+
" Agent with local_resource_id #{local_resource_id}.")
|
|
1362
|
+
construct_k8s_resource_locally(local_resource_id)
|
|
1363
|
+
end
|
|
1364
|
+
|
|
1352
1365
|
# Extract entry level monitored resource and common labels that should be
|
|
1353
1366
|
# applied to individual entries.
|
|
1354
1367
|
def determine_entry_level_monitored_resource_and_labels(
|
|
@@ -1578,22 +1591,22 @@ module Fluent
|
|
|
1578
1591
|
ts_nanos
|
|
1579
1592
|
end
|
|
1580
1593
|
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1594
|
+
if @adjust_invalid_timestamps && timestamp
|
|
1595
|
+
# Adjust timestamps from the future.
|
|
1596
|
+
# There are two cases:
|
|
1597
|
+
# 1. The parsed timestamp is later in the current year:
|
|
1598
|
+
# This can happen when system log lines from previous years are missing
|
|
1599
|
+
# the year, so the date parser assumes the current year.
|
|
1600
|
+
# We treat these lines as coming from last year. This could label
|
|
1601
|
+
# 2-year-old logs incorrectly, but this probably isn't super important.
|
|
1602
|
+
#
|
|
1603
|
+
# 2. The parsed timestamp is past the end of the current year:
|
|
1604
|
+
# Since the year is different from the current year, this isn't the
|
|
1605
|
+
# missing year in system logs. It is unlikely that users explicitly
|
|
1606
|
+
# write logs at a future date. This could result from an unsynchronized
|
|
1607
|
+
# clock on a VM, or some random value being parsed as the timestamp.
|
|
1608
|
+
# We reset the timestamp on those lines to the default value and let the
|
|
1609
|
+
# downstream API handle it.
|
|
1597
1610
|
next_year = Time.mktime(current_time.year + 1)
|
|
1598
1611
|
one_day_later = current_time.to_datetime.next_day.to_time
|
|
1599
1612
|
if timestamp >= next_year # Case 2.
|
|
@@ -1605,6 +1618,7 @@ module Fluent
|
|
|
1605
1618
|
# The value of ts_nanos should not change when subtracting a year.
|
|
1606
1619
|
end
|
|
1607
1620
|
end
|
|
1621
|
+
|
|
1608
1622
|
[ts_secs, ts_nanos]
|
|
1609
1623
|
end
|
|
1610
1624
|
|
|
@@ -2172,6 +2186,9 @@ module Fluent
|
|
|
2172
2186
|
error_details = ensure_array(gax_error.status_details)
|
|
2173
2187
|
raise JSON::ParserError, 'The error details are empty.' if
|
|
2174
2188
|
error_details.empty?
|
|
2189
|
+
raise JSON::ParserError, 'No partial error info in error details.' unless
|
|
2190
|
+
error_details[0].is_a?(
|
|
2191
|
+
Google::Logging::V2::WriteLogEntriesPartialErrors)
|
|
2175
2192
|
log_entry_errors = ensure_hash(error_details[0].log_entry_errors)
|
|
2176
2193
|
log_entry_errors.each do |index, log_entry_error|
|
|
2177
2194
|
error_key = [log_entry_error[:code], log_entry_error[:message]].freeze
|
data/test/plugin/base_test.rb
CHANGED
|
@@ -724,58 +724,65 @@ module BaseTest
|
|
|
724
724
|
one_second_into_next_year = next_year + 1
|
|
725
725
|
one_day_into_next_year = next_year.to_date.next_day.to_time
|
|
726
726
|
{
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
emit_index
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
727
|
+
APPLICATION_DEFAULT_CONFIG => {
|
|
728
|
+
Time.at(123_456.789) => Time.at(123_456.789),
|
|
729
|
+
Time.at(0) => Time.at(0),
|
|
730
|
+
current_time => current_time,
|
|
731
|
+
one_second_before_next_year => adjusted_to_last_year,
|
|
732
|
+
next_year => Time.at(0),
|
|
733
|
+
one_second_into_next_year => Time.at(0),
|
|
734
|
+
one_day_into_next_year => Time.at(0)
|
|
735
|
+
},
|
|
736
|
+
NO_ADJUST_TIMESTAMPS_CONFIG => {
|
|
737
|
+
Time.at(123_456.789) => Time.at(123_456.789),
|
|
738
|
+
Time.at(0) => Time.at(0),
|
|
739
|
+
current_time => current_time,
|
|
740
|
+
one_second_before_next_year => one_second_before_next_year,
|
|
741
|
+
next_year => next_year,
|
|
742
|
+
one_second_into_next_year => one_second_into_next_year,
|
|
743
|
+
one_day_into_next_year => one_day_into_next_year
|
|
744
|
+
}
|
|
745
|
+
}.each do |config, timestamps|
|
|
746
|
+
timestamps.each do |ts, expected_ts|
|
|
747
|
+
emit_index = 0
|
|
748
|
+
setup_logging_stubs do
|
|
749
|
+
@logs_sent = []
|
|
750
|
+
d = create_driver(config)
|
|
751
|
+
# Test the "native" fluentd timestamp as well as our nanosecond tags.
|
|
752
|
+
d.emit({ 'message' => log_entry(emit_index) }, ts.to_f)
|
|
753
|
+
emit_index += 1
|
|
754
|
+
d.emit('message' => log_entry(emit_index),
|
|
755
|
+
'timeNanos' => ts.tv_sec * 1_000_000_000 + ts.tv_nsec)
|
|
756
|
+
emit_index += 1
|
|
757
|
+
d.emit('message' => log_entry(emit_index),
|
|
758
|
+
'timestamp' => { 'seconds' => ts.tv_sec,
|
|
759
|
+
'nanos' => ts.tv_nsec })
|
|
760
|
+
emit_index += 1
|
|
761
|
+
d.emit('message' => log_entry(emit_index),
|
|
762
|
+
'timestampSeconds' => ts.tv_sec,
|
|
763
|
+
'timestampNanos' => ts.tv_nsec)
|
|
764
|
+
emit_index += 1
|
|
765
|
+
d.emit('message' => log_entry(emit_index),
|
|
766
|
+
'timestampSeconds' => ts.tv_sec.to_s,
|
|
767
|
+
'timestampNanos' => ts.tv_nsec.to_s)
|
|
768
|
+
emit_index += 1
|
|
769
|
+
d.run
|
|
770
|
+
verify_log_entries(emit_index, COMPUTE_PARAMS) do |entry, i|
|
|
771
|
+
verify_default_log_entry_text(entry['textPayload'], i, entry)
|
|
772
|
+
assert_equal_with_default entry['timestamp']['seconds'],
|
|
773
|
+
expected_ts.tv_sec, 0, entry
|
|
774
|
+
assert_equal_with_default \
|
|
775
|
+
entry['timestamp']['nanos'],
|
|
776
|
+
expected_ts.tv_nsec, 0, entry do
|
|
777
|
+
# Fluentd v0.14 onwards supports nanosecond timestamp values.
|
|
778
|
+
# Added in 600 ns delta to avoid flaky tests introduced
|
|
779
|
+
# due to rounding error in double-precision floating-point numbers
|
|
780
|
+
# (to account for the missing 9 bits of precision ~ 512 ns).
|
|
781
|
+
# See http://wikipedia.org/wiki/Double-precision_floating-point_format.
|
|
782
|
+
assert_in_delta expected_ts.tv_nsec,
|
|
783
|
+
entry['timestamp']['nanos'], 600, entry
|
|
784
|
+
end
|
|
777
785
|
end
|
|
778
|
-
verify_index += 1
|
|
779
786
|
end
|
|
780
787
|
end
|
|
781
788
|
end
|
|
@@ -1338,14 +1345,14 @@ module BaseTest
|
|
|
1338
1345
|
setup_metadata_agent_stub: true,
|
|
1339
1346
|
setup_k8s_stub: true,
|
|
1340
1347
|
log_entry: k8s_container_log_entry(log_entry(0)),
|
|
1341
|
-
expected_params:
|
|
1348
|
+
expected_params: K8S_CONTAINER_PARAMS_FROM_LOCAL
|
|
1342
1349
|
},
|
|
1343
1350
|
{
|
|
1344
1351
|
config: APPLICATION_DEFAULT_CONFIG,
|
|
1345
1352
|
setup_metadata_agent_stub: false,
|
|
1346
1353
|
setup_k8s_stub: true,
|
|
1347
1354
|
log_entry: k8s_container_log_entry(log_entry(0)),
|
|
1348
|
-
expected_params:
|
|
1355
|
+
expected_params: K8S_CONTAINER_PARAMS_FROM_LOCAL
|
|
1349
1356
|
},
|
|
1350
1357
|
# When enable_metadata_agent is true.
|
|
1351
1358
|
{
|
|
@@ -1409,7 +1416,7 @@ module BaseTest
|
|
|
1409
1416
|
setup_metadata_agent_stub: true,
|
|
1410
1417
|
setup_k8s_stub: true,
|
|
1411
1418
|
log_entry: k8s_node_log_entry(log_entry(0)),
|
|
1412
|
-
expected_params:
|
|
1419
|
+
expected_params: K8S_NODE_PARAMS_FROM_LOCAL
|
|
1413
1420
|
},
|
|
1414
1421
|
{
|
|
1415
1422
|
config: ENABLE_METADATA_AGENT_CONFIG,
|
data/test/plugin/constants.rb
CHANGED
|
@@ -12,6 +12,36 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
# Add some helper methods to standard classes.
|
|
16
|
+
module Google
|
|
17
|
+
module Protobuf
|
|
18
|
+
Any.class_eval do
|
|
19
|
+
# TODO(igorpeshansky): Remove this once
|
|
20
|
+
# https://github.com/google/protobuf/pull/4719 gets released.
|
|
21
|
+
def self.pack(msg, type_url_prefix = 'type.googleapis.com/')
|
|
22
|
+
any = Google::Protobuf::Any.new
|
|
23
|
+
any.pack(msg, type_url_prefix)
|
|
24
|
+
any
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
String.class_eval do
|
|
30
|
+
def inspect_octal
|
|
31
|
+
specials = {
|
|
32
|
+
'a' => '\\007',
|
|
33
|
+
'b' => '\\010',
|
|
34
|
+
'v' => '\\013',
|
|
35
|
+
'f' => '\\014',
|
|
36
|
+
'r' => '\\015'
|
|
37
|
+
}.freeze
|
|
38
|
+
inspect.gsub(/\\([abvfr])/) { specials[Regexp.last_match(1)] } \
|
|
39
|
+
.gsub(/\\x([0-9A-F][0-9A-F])/) do
|
|
40
|
+
format('\\%03o', Regexp.last_match(1).to_i(16))
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
15
45
|
# Constants used by unit tests for Google Cloud Logging plugin.
|
|
16
46
|
module Constants
|
|
17
47
|
include Fluent::GoogleCloudOutput::ServiceConstants
|
|
@@ -219,6 +249,10 @@ module Constants
|
|
|
219
249
|
split_logs_by_tag true
|
|
220
250
|
).freeze
|
|
221
251
|
|
|
252
|
+
NO_ADJUST_TIMESTAMPS_CONFIG = %(
|
|
253
|
+
adjust_invalid_timestamps false
|
|
254
|
+
).freeze
|
|
255
|
+
|
|
222
256
|
ENABLE_PROMETHEUS_CONFIG = %(
|
|
223
257
|
enable_monitoring true
|
|
224
258
|
monitoring_type prometheus
|
|
@@ -809,45 +843,69 @@ module Constants
|
|
|
809
843
|
}
|
|
810
844
|
}.freeze
|
|
811
845
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
846
|
+
PARTIAL_SUCCESS_GRPC_METADATA = begin
|
|
847
|
+
partial_errors = Google::Logging::V2::WriteLogEntriesPartialErrors.new(
|
|
848
|
+
log_entry_errors: {
|
|
849
|
+
0 => Google::Rpc::Status.new(
|
|
850
|
+
code: GRPC::Core::StatusCodes::PERMISSION_DENIED,
|
|
851
|
+
message: 'User not authorized.',
|
|
852
|
+
details: []),
|
|
853
|
+
1 => Google::Rpc::Status.new(
|
|
854
|
+
code: GRPC::Core::StatusCodes::INVALID_ARGUMENT,
|
|
855
|
+
message: 'Log name contains illegal character :',
|
|
856
|
+
details: []),
|
|
857
|
+
3 => Google::Rpc::Status.new(
|
|
858
|
+
code: GRPC::Core::StatusCodes::INVALID_ARGUMENT,
|
|
859
|
+
message: 'Log name contains illegal character :',
|
|
860
|
+
details: [])
|
|
861
|
+
})
|
|
862
|
+
status = Google::Rpc::Status.new(
|
|
863
|
+
message: 'User not authorized.',
|
|
864
|
+
details: [Google::Protobuf::Any.pack(partial_errors)])
|
|
865
|
+
debug_info = Google::Rpc::DebugInfo.new(
|
|
866
|
+
detail: '[ORIGINAL ERROR] generic::permission_denied: User not' \
|
|
867
|
+
' authorized. [google.rpc.error_details_ext] { message:' \
|
|
868
|
+
" #{status.message.inspect} details { type_url:" \
|
|
869
|
+
" #{status.details[0].type_url.inspect} value:" \
|
|
870
|
+
" #{status.details[0].value.inspect_octal} } }")
|
|
871
|
+
status_details = Google::Rpc::Status.new(
|
|
872
|
+
code: 7, message: 'User not authorized.',
|
|
873
|
+
details: [Google::Protobuf::Any.pack(partial_errors),
|
|
874
|
+
Google::Protobuf::Any.pack(debug_info)])
|
|
875
|
+
{
|
|
876
|
+
'google.logging.v2.writelogentriespartialerrors-bin' =>
|
|
877
|
+
partial_errors.to_proto,
|
|
878
|
+
'google.rpc.debuginfo-bin' => debug_info.to_proto,
|
|
879
|
+
'grpc-status-details-bin' => status_details.to_proto
|
|
880
|
+
}.freeze
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
PARSE_ERROR_RESPONSE_BODY = {
|
|
884
|
+
'error' => {
|
|
885
|
+
'code' => 400,
|
|
886
|
+
'message' => 'Request contains an invalid argument.',
|
|
887
|
+
'status' => 'INVALID_ARGUMENT',
|
|
888
|
+
'details' => [
|
|
889
|
+
{
|
|
890
|
+
'@type' => 'type.googleapis.com/google.rpc.DebugInfo',
|
|
891
|
+
'detail' =>
|
|
892
|
+
'[ORIGINAL ERROR] RPC::CLIENT_ERROR: server could not parse' \
|
|
893
|
+
" request sent by client; initialization error is: ''"
|
|
894
|
+
}
|
|
895
|
+
]
|
|
896
|
+
}
|
|
851
897
|
}.freeze
|
|
852
|
-
|
|
898
|
+
|
|
899
|
+
PARSE_ERROR_GRPC_METADATA = begin
|
|
900
|
+
debug_info = Google::Rpc::DebugInfo.new(
|
|
901
|
+
detail: '[ORIGINAL ERROR] RPC::CLIENT_ERROR: server could not parse' \
|
|
902
|
+
" request sent by client; initialization error is: ''")
|
|
903
|
+
status_details = Google::Rpc::Status.new(
|
|
904
|
+
code: 3, message: 'internal client error',
|
|
905
|
+
details: [Google::Protobuf::Any.pack(debug_info)])
|
|
906
|
+
{
|
|
907
|
+
'google.rpc.debuginfo-bin' => debug_info.to_proto,
|
|
908
|
+
'grpc-status-details-bin' => status_details.to_proto
|
|
909
|
+
}.freeze
|
|
910
|
+
end
|
|
853
911
|
end
|
|
@@ -81,6 +81,31 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
|
|
|
81
81
|
assert_requested(:post, WRITE_LOG_ENTRIES_URI, times: 1)
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
def test_non_api_error
|
|
85
|
+
setup_gce_metadata_stubs
|
|
86
|
+
setup_prometheus
|
|
87
|
+
# The API Client should not retry this and the plugin should consume
|
|
88
|
+
# the exception.
|
|
89
|
+
root_error_code = PARSE_ERROR_RESPONSE_BODY['error']['code']
|
|
90
|
+
stub_request(:post, WRITE_LOG_ENTRIES_URI)
|
|
91
|
+
.to_return(status: root_error_code,
|
|
92
|
+
body: PARSE_ERROR_RESPONSE_BODY.to_json)
|
|
93
|
+
d = create_driver(ENABLE_PROMETHEUS_CONFIG)
|
|
94
|
+
d.emit('message' => log_entry(0))
|
|
95
|
+
d.run
|
|
96
|
+
assert_prometheus_metric_value(
|
|
97
|
+
:stackdriver_successful_requests_count, 0, grpc: false, code: 200)
|
|
98
|
+
assert_prometheus_metric_value(
|
|
99
|
+
:stackdriver_failed_requests_count, 1, grpc: false, code: 400)
|
|
100
|
+
assert_prometheus_metric_value(
|
|
101
|
+
:stackdriver_ingested_entries_count, 0, grpc: false, code: 200)
|
|
102
|
+
assert_prometheus_metric_value(
|
|
103
|
+
:stackdriver_dropped_entries_count, 1, grpc: false, code: 400)
|
|
104
|
+
assert_prometheus_metric_value(
|
|
105
|
+
:stackdriver_retried_entries_count, 0, grpc: false)
|
|
106
|
+
assert_requested(:post, WRITE_LOG_ENTRIES_URI, times: 1)
|
|
107
|
+
end
|
|
108
|
+
|
|
84
109
|
def test_server_error
|
|
85
110
|
setup_gce_metadata_stubs
|
|
86
111
|
# The API client should retry this once, then throw an exception which
|
|
@@ -97,6 +97,34 @@ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
|
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
+
def test_non_api_error
|
|
101
|
+
setup_gce_metadata_stubs
|
|
102
|
+
setup_prometheus
|
|
103
|
+
setup_logging_stubs(
|
|
104
|
+
GRPC::InvalidArgument.new('internal client error',
|
|
105
|
+
PARSE_ERROR_GRPC_METADATA)) do
|
|
106
|
+
# The API Client should not retry this and the plugin should consume
|
|
107
|
+
# the exception.
|
|
108
|
+
d = create_driver(ENABLE_PROMETHEUS_CONFIG)
|
|
109
|
+
d.emit('message' => log_entry(0))
|
|
110
|
+
d.run
|
|
111
|
+
assert_prometheus_metric_value(
|
|
112
|
+
:stackdriver_successful_requests_count, 0,
|
|
113
|
+
grpc: true, code: GRPC::Core::StatusCodes::OK)
|
|
114
|
+
assert_prometheus_metric_value(
|
|
115
|
+
:stackdriver_failed_requests_count, 1,
|
|
116
|
+
grpc: true, code: GRPC::Core::StatusCodes::INVALID_ARGUMENT)
|
|
117
|
+
assert_prometheus_metric_value(
|
|
118
|
+
:stackdriver_ingested_entries_count, 0,
|
|
119
|
+
grpc: true, code: GRPC::Core::StatusCodes::OK)
|
|
120
|
+
assert_prometheus_metric_value(
|
|
121
|
+
:stackdriver_dropped_entries_count, 1,
|
|
122
|
+
grpc: true, code: GRPC::Core::StatusCodes::INVALID_ARGUMENT)
|
|
123
|
+
assert_prometheus_metric_value(
|
|
124
|
+
:stackdriver_retried_entries_count, 0, grpc: true)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
100
128
|
def test_server_error
|
|
101
129
|
setup_gce_metadata_stubs
|
|
102
130
|
{
|
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.21
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ling Huang
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2018-06-
|
|
12
|
+
date: 2018-06-28 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: fluentd
|