fluent-plugin-google-cloud 0.10.9 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +133 -108
- data/Rakefile +6 -5
- data/fluent-plugin-google-cloud.gemspec +21 -22
- data/lib/fluent/plugin/common.rb +42 -29
- data/lib/fluent/plugin/filter_add_insert_ids.rb +1 -14
- data/lib/fluent/plugin/filter_analyze_config.rb +73 -48
- data/lib/fluent/plugin/in_object_space_dump.rb +1 -1
- data/lib/fluent/plugin/monitoring.rb +49 -20
- data/lib/fluent/plugin/out_google_cloud.rb +270 -213
- data/lib/fluent/plugin/statusz.rb +10 -10
- data/test/helper.rb +6 -0
- data/test/plugin/base_test.rb +200 -136
- data/test/plugin/constants.rb +21 -28
- data/test/plugin/test_driver.rb +2 -1
- data/test/plugin/test_filter_add_insert_ids.rb +5 -3
- data/test/plugin/test_filter_analyze_config.rb +32 -17
- data/test/plugin/test_out_google_cloud.rb +37 -25
- data/test/plugin/test_out_google_cloud_grpc.rb +45 -30
- data/test/plugin/utils.rb +9 -8
- metadata +58 -44
@@ -20,9 +20,9 @@ require 'socket'
|
|
20
20
|
require 'time'
|
21
21
|
require 'yaml'
|
22
22
|
require 'google/apis'
|
23
|
+
require 'google/cloud/errors'
|
23
24
|
require 'google/apis/logging_v2'
|
24
25
|
require 'google/cloud/logging/v2'
|
25
|
-
require 'google/gax'
|
26
26
|
require 'google/logging/v2/logging_pb'
|
27
27
|
require 'google/logging/v2/logging_services_pb'
|
28
28
|
require 'google/logging/v2/log_entry_pb'
|
@@ -85,6 +85,7 @@ require 'strptime'
|
|
85
85
|
# Dummy Strptime class.
|
86
86
|
class Strptime
|
87
87
|
def self.new(_)
|
88
|
+
# empty
|
88
89
|
end
|
89
90
|
end
|
90
91
|
|
@@ -130,47 +131,47 @@ module Fluent
|
|
130
131
|
# Map from subfields' names to their types.
|
131
132
|
[
|
132
133
|
# subfield key in the payload, destination key, cast lambda (opt)
|
133
|
-
%w
|
134
|
-
%w
|
135
|
-
%w
|
136
|
-
%w
|
137
|
-
cache_validated_with_origin_server parse_bool
|
138
|
-
%w
|
139
|
-
%w
|
140
|
-
%w
|
141
|
-
%w
|
142
|
-
%w
|
143
|
-
%w
|
144
|
-
%w
|
145
|
-
%w
|
146
|
-
%w
|
147
|
-
%w
|
148
|
-
%w
|
134
|
+
%w[cacheFillBytes cache_fill_bytes parse_int],
|
135
|
+
%w[cacheHit cache_hit parse_bool],
|
136
|
+
%w[cacheLookup cache_lookup parse_bool],
|
137
|
+
%w[cacheValidatedWithOriginServer
|
138
|
+
cache_validated_with_origin_server parse_bool],
|
139
|
+
%w[latency latency parse_latency],
|
140
|
+
%w[protocol protocol parse_string],
|
141
|
+
%w[referer referer parse_string],
|
142
|
+
%w[remoteIp remote_ip parse_string],
|
143
|
+
%w[responseSize response_size parse_int],
|
144
|
+
%w[requestMethod request_method parse_string],
|
145
|
+
%w[requestSize request_size parse_int],
|
146
|
+
%w[requestUrl request_url parse_string],
|
147
|
+
%w[serverIp server_ip parse_string],
|
148
|
+
%w[status status parse_int],
|
149
|
+
%w[userAgent user_agent parse_string]
|
149
150
|
],
|
150
151
|
# The grpc version class name.
|
151
|
-
'Google::Logging::Type::HttpRequest',
|
152
|
+
'Google::Cloud::Logging::Type::HttpRequest',
|
152
153
|
# The non-grpc version class name.
|
153
154
|
'Google::Apis::LoggingV2::HttpRequest'
|
154
155
|
],
|
155
156
|
'operation' => [
|
156
157
|
'@operation_key',
|
157
158
|
[
|
158
|
-
%w
|
159
|
-
%w
|
160
|
-
%w
|
161
|
-
%w
|
159
|
+
%w[id id parse_string],
|
160
|
+
%w[producer producer parse_string],
|
161
|
+
%w[first first parse_bool],
|
162
|
+
%w[last last parse_bool]
|
162
163
|
],
|
163
|
-
'Google::Logging::V2::LogEntryOperation',
|
164
|
+
'Google::Cloud::Logging::V2::LogEntryOperation',
|
164
165
|
'Google::Apis::LoggingV2::LogEntryOperation'
|
165
166
|
],
|
166
167
|
'source_location' => [
|
167
168
|
'@source_location_key',
|
168
169
|
[
|
169
|
-
%w
|
170
|
-
%w
|
171
|
-
%w
|
170
|
+
%w[file file parse_string],
|
171
|
+
%w[function function parse_string],
|
172
|
+
%w[line line parse_int]
|
172
173
|
],
|
173
|
-
'Google::Logging::V2::LogEntrySourceLocation',
|
174
|
+
'Google::Cloud::Logging::V2::LogEntrySourceLocation',
|
174
175
|
'Google::Apis::LoggingV2::LogEntrySourceLocation'
|
175
176
|
]
|
176
177
|
}.freeze
|
@@ -195,7 +196,8 @@ module Fluent
|
|
195
196
|
PLUGIN_VERSION = begin
|
196
197
|
# Extract plugin version from file path.
|
197
198
|
match_data = __FILE__.match(
|
198
|
-
%r{fluent-plugin-google-cloud-(?<version>[^/]*)/}
|
199
|
+
%r{fluent-plugin-google-cloud-(?<version>[^/]*)/}
|
200
|
+
)
|
199
201
|
if match_data
|
200
202
|
match_data['version']
|
201
203
|
else
|
@@ -203,9 +205,10 @@ module Fluent
|
|
203
205
|
dependency = Gem::Dependency.new('fluent-plugin-google-cloud')
|
204
206
|
all_specs, = Gem::SpecFetcher.fetcher.spec_for_dependency(dependency)
|
205
207
|
matching_version, = all_specs.grep(
|
206
|
-
proc { |spec,| __FILE__.include?(spec.full_gem_path) }
|
207
|
-
|
208
|
-
|
208
|
+
proc { |spec,| __FILE__.include?(spec.full_gem_path) }
|
209
|
+
) do |spec,|
|
210
|
+
spec.version.to_s
|
211
|
+
end
|
209
212
|
# If no matching version was found, return a valid but obviously wrong
|
210
213
|
# value.
|
211
214
|
matching_version || '0.0.0-unknown'
|
@@ -323,7 +326,7 @@ module Fluent
|
|
323
326
|
# Whether to enable gRPC compression when communicating with the Stackdriver
|
324
327
|
# Logging API. Only used if 'use_grpc' is set to true.
|
325
328
|
config_param :grpc_compression_algorithm, :enum,
|
326
|
-
list: [
|
329
|
+
list: %i[none gzip],
|
327
330
|
:default => nil
|
328
331
|
|
329
332
|
# Whether valid entries should be written even if some other entries fail
|
@@ -428,12 +431,7 @@ module Fluent
|
|
428
431
|
|
429
432
|
# Expose attr_readers to make testing of metadata more direct than only
|
430
433
|
# testing it indirectly through metadata sent with logs.
|
431
|
-
attr_reader :
|
432
|
-
attr_reader :zone
|
433
|
-
attr_reader :vm_id
|
434
|
-
attr_reader :resource
|
435
|
-
attr_reader :common_labels
|
436
|
-
attr_reader :monitoring_resource
|
434
|
+
attr_reader :resource, :common_labels, :monitoring_resource
|
437
435
|
|
438
436
|
def initialize
|
439
437
|
super
|
@@ -496,13 +494,15 @@ module Fluent
|
|
496
494
|
|
497
495
|
# All metadata parameters must now be set.
|
498
496
|
@utils.check_required_metadata_variables(
|
499
|
-
@platform, @project_id, @zone, @vm_id
|
497
|
+
@platform, @project_id, @zone, @vm_id
|
498
|
+
)
|
500
499
|
|
501
500
|
# Retrieve monitored resource.
|
502
501
|
# Fail over to retrieve monitored resource via the legacy path if we fail
|
503
502
|
# to get it from Metadata Agent.
|
504
503
|
@resource ||= @utils.determine_agent_level_monitored_resource_via_legacy(
|
505
|
-
@platform, @subservice_name, @detect_subservice, @vm_id, @zone
|
504
|
+
@platform, @subservice_name, @detect_subservice, @vm_id, @zone
|
505
|
+
)
|
506
506
|
|
507
507
|
if @metrics_resource
|
508
508
|
unless @metrics_resource[:type].is_a?(String)
|
@@ -517,7 +517,7 @@ module Fluent
|
|
517
517
|
" #{@metrics_resource}."
|
518
518
|
end
|
519
519
|
extra_keys = @metrics_resource.reject do |k, _|
|
520
|
-
|
520
|
+
%i[type labels].include?(k)
|
521
521
|
end
|
522
522
|
unless extra_keys.empty?
|
523
523
|
raise Fluent::ConfigError,
|
@@ -545,16 +545,18 @@ module Fluent
|
|
545
545
|
# and store metric objects for future use.
|
546
546
|
if @enable_monitoring
|
547
547
|
unless Monitoring::MonitoringRegistryFactory.supports_monitoring_type(
|
548
|
-
@monitoring_type
|
548
|
+
@monitoring_type
|
549
|
+
)
|
549
550
|
@log.warn "monitoring_type '#{@monitoring_type}' is unknown; "\
|
550
551
|
'there will be no metrics'
|
551
552
|
end
|
552
|
-
if @metrics_resource
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
553
|
+
@monitoring_resource = if @metrics_resource
|
554
|
+
@utils.create_monitored_resource(
|
555
|
+
@metrics_resource[:type], @metrics_resource[:labels]
|
556
|
+
)
|
557
|
+
else
|
558
|
+
@resource
|
559
|
+
end
|
558
560
|
@registry = Monitoring::MonitoringRegistryFactory
|
559
561
|
.create(@monitoring_type, @project_id,
|
560
562
|
@monitoring_resource, @gcm_service_address)
|
@@ -564,37 +566,43 @@ module Fluent
|
|
564
566
|
# we can't change it.
|
565
567
|
@uptime_metric = @registry.counter(
|
566
568
|
:uptime, [:version], 'Uptime of Logging agent',
|
567
|
-
'agent.googleapis.com/agent', 'CUMULATIVE'
|
569
|
+
'agent.googleapis.com/agent', 'CUMULATIVE'
|
570
|
+
)
|
568
571
|
update_uptime
|
569
572
|
timer_execute(:update_uptime, 1) { update_uptime }
|
570
573
|
@successful_requests_count = @registry.counter(
|
571
574
|
:stackdriver_successful_requests_count,
|
572
|
-
[
|
575
|
+
%i[grpc code],
|
573
576
|
'A number of successful requests to the Stackdriver Logging API',
|
574
|
-
'agent.googleapis.com/agent', 'CUMULATIVE'
|
577
|
+
'agent.googleapis.com/agent', 'CUMULATIVE'
|
578
|
+
)
|
575
579
|
@failed_requests_count = @registry.counter(
|
576
580
|
:stackdriver_failed_requests_count,
|
577
|
-
[
|
581
|
+
%i[grpc code],
|
578
582
|
'A number of failed requests to the Stackdriver Logging '\
|
579
583
|
'API, broken down by the error code',
|
580
|
-
'agent.googleapis.com/agent', 'CUMULATIVE'
|
584
|
+
'agent.googleapis.com/agent', 'CUMULATIVE'
|
585
|
+
)
|
581
586
|
@ingested_entries_count = @registry.counter(
|
582
587
|
:stackdriver_ingested_entries_count,
|
583
|
-
[
|
588
|
+
%i[grpc code],
|
584
589
|
'A number of log entries ingested by Stackdriver Logging',
|
585
|
-
'agent.googleapis.com/agent', 'CUMULATIVE'
|
590
|
+
'agent.googleapis.com/agent', 'CUMULATIVE'
|
591
|
+
)
|
586
592
|
@dropped_entries_count = @registry.counter(
|
587
593
|
:stackdriver_dropped_entries_count,
|
588
|
-
[
|
594
|
+
%i[grpc code],
|
589
595
|
'A number of log entries dropped by the Stackdriver output plugin',
|
590
|
-
'agent.googleapis.com/agent', 'CUMULATIVE'
|
596
|
+
'agent.googleapis.com/agent', 'CUMULATIVE'
|
597
|
+
)
|
591
598
|
@retried_entries_count = @registry.counter(
|
592
599
|
:stackdriver_retried_entries_count,
|
593
|
-
[
|
600
|
+
%i[grpc code],
|
594
601
|
'The number of log entries that failed to be ingested by '\
|
595
602
|
'the Stackdriver output plugin due to a transient error '\
|
596
603
|
'and were retried',
|
597
|
-
'agent.googleapis.com/agent', 'CUMULATIVE'
|
604
|
+
'agent.googleapis.com/agent', 'CUMULATIVE'
|
605
|
+
)
|
598
606
|
@ok_code = @use_grpc ? GRPC::Core::StatusCodes::OK : 200
|
599
607
|
end
|
600
608
|
|
@@ -625,12 +633,12 @@ module Fluent
|
|
625
633
|
@write_request = method(:write_request_via_rest)
|
626
634
|
end
|
627
635
|
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
636
|
+
return unless [Common::Platform::GCE, Common::Platform::EC2].include?(@platform)
|
637
|
+
|
638
|
+
# Log an informational message containing the Logs viewer URL
|
639
|
+
@log.info 'Logs viewer address: https://console.cloud.google.com/logs/',
|
640
|
+
"viewer?project=#{@project_id}&resource=#{@resource.type}/",
|
641
|
+
"instance_id/#{@vm_id}"
|
634
642
|
end
|
635
643
|
|
636
644
|
def start
|
@@ -639,16 +647,16 @@ module Fluent
|
|
639
647
|
@successful_call = false
|
640
648
|
@timenanos_warning = false
|
641
649
|
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
650
|
+
return unless @statusz_port.positive?
|
651
|
+
|
652
|
+
@log.info "Starting statusz server on port #{@statusz_port}"
|
653
|
+
server_create(:out_google_cloud_statusz,
|
654
|
+
@statusz_port,
|
655
|
+
bind: '127.0.0.1') do |data, conn|
|
656
|
+
if data.split(' ')[1] == '/statusz'
|
657
|
+
write_html_response(data, conn, 200, Statusz.response(self))
|
658
|
+
else
|
659
|
+
write_html_response(data, conn, 404, "Not found\n")
|
652
660
|
end
|
653
661
|
end
|
654
662
|
end
|
@@ -657,7 +665,7 @@ module Fluent
|
|
657
665
|
super
|
658
666
|
# Export metrics on shutdown. This is a best-effort attempt, and it might
|
659
667
|
# fail, for instance if there was a recent write to the same time series.
|
660
|
-
@registry
|
668
|
+
@registry&.export
|
661
669
|
end
|
662
670
|
|
663
671
|
def write(chunk)
|
@@ -668,12 +676,14 @@ module Fluent
|
|
668
676
|
entries = []
|
669
677
|
group_level_resource, group_level_common_labels =
|
670
678
|
determine_group_level_monitored_resource_and_labels(
|
671
|
-
tag, local_resource_id
|
679
|
+
tag, local_resource_id
|
680
|
+
)
|
672
681
|
|
673
682
|
arr.each do |time, record|
|
674
683
|
entry_level_resource, entry_level_common_labels =
|
675
684
|
determine_entry_level_monitored_resource_and_labels(
|
676
|
-
group_level_resource, group_level_common_labels, record
|
685
|
+
group_level_resource, group_level_common_labels, record
|
686
|
+
)
|
677
687
|
|
678
688
|
is_json = false
|
679
689
|
if @detect_json
|
@@ -703,10 +713,8 @@ module Fluent
|
|
703
713
|
# unless there is additional metadata that would be lost.
|
704
714
|
record_json = nil
|
705
715
|
if (record.keys - preserved_keys).length == 1
|
706
|
-
%w
|
707
|
-
if record.key?(field)
|
708
|
-
record_json = parse_json_or_nil(record[field])
|
709
|
-
end
|
716
|
+
%w[log message msg].each do |field|
|
717
|
+
record_json = parse_json_or_nil(record[field]) if record.key?(field)
|
710
718
|
end
|
711
719
|
end
|
712
720
|
unless record_json.nil?
|
@@ -727,12 +735,16 @@ module Fluent
|
|
727
735
|
if @adjust_invalid_timestamps && timestamp
|
728
736
|
|
729
737
|
severity = compute_severity(
|
730
|
-
entry_level_resource.type, record, entry_level_common_labels
|
738
|
+
entry_level_resource.type, record, entry_level_common_labels
|
739
|
+
)
|
731
740
|
|
732
741
|
dynamic_labels_from_payload = parse_labels(record)
|
733
742
|
|
734
|
-
|
735
|
-
|
743
|
+
if dynamic_labels_from_payload
|
744
|
+
entry_level_common_labels.merge!(
|
745
|
+
dynamic_labels_from_payload
|
746
|
+
)
|
747
|
+
end
|
736
748
|
|
737
749
|
entry = @construct_log_entry.call(entry_level_common_labels,
|
738
750
|
entry_level_resource,
|
@@ -759,7 +771,8 @@ module Fluent
|
|
759
771
|
next if entries.empty?
|
760
772
|
|
761
773
|
log_name = "projects/#{@project_id}/logs/#{log_name(
|
762
|
-
tag, group_level_resource
|
774
|
+
tag, group_level_resource
|
775
|
+
)}"
|
763
776
|
|
764
777
|
requests_to_send << {
|
765
778
|
entries: entries,
|
@@ -771,7 +784,7 @@ module Fluent
|
|
771
784
|
|
772
785
|
if @split_logs_by_tag
|
773
786
|
requests_to_send.each do |request|
|
774
|
-
@write_request.call(request)
|
787
|
+
@write_request.call(**request)
|
775
788
|
end
|
776
789
|
else
|
777
790
|
# Combine all requests into one. The request level "log_name" will be
|
@@ -803,7 +816,8 @@ module Fluent
|
|
803
816
|
now = Time.now.to_i
|
804
817
|
@uptime_metric.increment(
|
805
818
|
by: now - @uptime_update_time,
|
806
|
-
labels: { version: Fluent::GoogleCloudOutput.version_string }
|
819
|
+
labels: { version: Fluent::GoogleCloudOutput.version_string }
|
820
|
+
)
|
807
821
|
@uptime_update_time = now
|
808
822
|
end
|
809
823
|
|
@@ -823,6 +837,7 @@ module Fluent
|
|
823
837
|
def compute_trace(trace)
|
824
838
|
return trace unless @autoformat_stackdriver_trace &&
|
825
839
|
STACKDRIVER_TRACE_ID_REGEXP.match(trace)
|
840
|
+
|
826
841
|
"projects/#{@project_id}/traces/#{trace}"
|
827
842
|
end
|
828
843
|
|
@@ -831,7 +846,7 @@ module Fluent
|
|
831
846
|
severity,
|
832
847
|
ts_secs,
|
833
848
|
ts_nanos)
|
834
|
-
entry = Google::Logging::V2::LogEntry.new(
|
849
|
+
entry = Google::Cloud::Logging::V2::LogEntry.new(
|
835
850
|
labels: labels,
|
836
851
|
resource: Google::Api::MonitoredResource.new(
|
837
852
|
type: resource.type,
|
@@ -878,7 +893,7 @@ module Fluent
|
|
878
893
|
client = api_client
|
879
894
|
entries_count = entries.length
|
880
895
|
client.write_log_entries(
|
881
|
-
entries,
|
896
|
+
entries: entries,
|
882
897
|
log_name: log_name,
|
883
898
|
# Leave resource nil if it's nil.
|
884
899
|
resource: if resource
|
@@ -901,10 +916,9 @@ module Fluent
|
|
901
916
|
@successful_call = true
|
902
917
|
@log.info 'Successfully sent gRPC to Stackdriver Logging API.'
|
903
918
|
end
|
904
|
-
|
905
|
-
rescue Google::Gax::GaxError => gax_error
|
919
|
+
rescue Google::Cloud::Error => e
|
906
920
|
# GRPC::BadStatus is wrapped in error.cause.
|
907
|
-
error =
|
921
|
+
error = e.cause
|
908
922
|
|
909
923
|
# See the mapping between HTTP status and gRPC status code at:
|
910
924
|
# https://github.com/grpc/grpc/blob/master/src/core/lib/transport/status_conversion.cc
|
@@ -959,7 +973,7 @@ module Fluent
|
|
959
973
|
GRPC::InvalidArgument,
|
960
974
|
# HTTP status 403 (Forbidden).
|
961
975
|
GRPC::PermissionDenied
|
962
|
-
error_details_map = construct_error_details_map_grpc(
|
976
|
+
error_details_map = construct_error_details_map_grpc(e)
|
963
977
|
if error_details_map.empty?
|
964
978
|
increment_failed_requests_count(error.code)
|
965
979
|
increment_dropped_entries_count(entries_count, error.code)
|
@@ -993,15 +1007,15 @@ module Fluent
|
|
993
1007
|
error: error.to_s, error_code: error_code.to_s
|
994
1008
|
end
|
995
1009
|
|
996
|
-
# Got an unexpected error (not Google::
|
1010
|
+
# Got an unexpected error (not Google::Cloud::Error) from the
|
997
1011
|
# google-cloud-logging lib.
|
998
|
-
rescue StandardError =>
|
1012
|
+
rescue StandardError => e
|
999
1013
|
increment_failed_requests_count(GRPC::Core::StatusCodes::UNKNOWN)
|
1000
1014
|
increment_dropped_entries_count(entries_count,
|
1001
1015
|
GRPC::Core::StatusCodes::UNKNOWN)
|
1002
|
-
@log.error "Unexpected error type #{
|
1016
|
+
@log.error "Unexpected error type #{e.class.name} from the client" \
|
1003
1017
|
" library, dropping #{entries_count} log message(s)",
|
1004
|
-
error:
|
1018
|
+
error: e.to_s
|
1005
1019
|
end
|
1006
1020
|
|
1007
1021
|
def write_request_via_rest(entries:,
|
@@ -1029,32 +1043,29 @@ module Fluent
|
|
1029
1043
|
@successful_call = true
|
1030
1044
|
@log.info 'Successfully sent to Stackdriver Logging API.'
|
1031
1045
|
end
|
1032
|
-
|
1033
|
-
rescue Google::Apis::ServerError => error
|
1046
|
+
rescue Google::Apis::ServerError => e
|
1034
1047
|
# 5xx server errors. Retry via re-raising the error.
|
1035
|
-
increment_retried_entries_count(entries_count,
|
1048
|
+
increment_retried_entries_count(entries_count, e.status_code)
|
1036
1049
|
@log.debug "Retrying #{entries_count} log message(s) later.",
|
1037
|
-
error:
|
1038
|
-
raise
|
1039
|
-
|
1040
|
-
rescue Google::Apis::AuthorizationError => error
|
1050
|
+
error: e.to_s, error_code: e.status_code.to_s
|
1051
|
+
raise e
|
1052
|
+
rescue Google::Apis::AuthorizationError => e
|
1041
1053
|
# 401 authorization error.
|
1042
1054
|
# These are usually solved via a `gcloud auth` call, or by modifying
|
1043
1055
|
# the permissions on the Google Cloud project.
|
1044
|
-
increment_failed_requests_count(
|
1045
|
-
increment_dropped_entries_count(entries_count,
|
1056
|
+
increment_failed_requests_count(e.status_code)
|
1057
|
+
increment_dropped_entries_count(entries_count, e.status_code)
|
1046
1058
|
@log.warn "Dropping #{entries_count} log message(s)",
|
1047
|
-
error:
|
1048
|
-
|
1049
|
-
rescue Google::Apis::ClientError => error
|
1059
|
+
error: e.to_s, error_code: e.status_code.to_s
|
1060
|
+
rescue Google::Apis::ClientError => e
|
1050
1061
|
# 4xx client errors. Most client errors indicate a problem with the
|
1051
1062
|
# request itself and should not be retried.
|
1052
|
-
error_details_map = construct_error_details_map(
|
1063
|
+
error_details_map = construct_error_details_map(e)
|
1053
1064
|
if error_details_map.empty?
|
1054
|
-
increment_failed_requests_count(
|
1055
|
-
increment_dropped_entries_count(entries_count,
|
1065
|
+
increment_failed_requests_count(e.status_code)
|
1066
|
+
increment_dropped_entries_count(entries_count, e.status_code)
|
1056
1067
|
@log.warn "Dropping #{entries_count} log message(s)",
|
1057
|
-
error:
|
1068
|
+
error: e.to_s, error_code: e.status_code.to_s
|
1058
1069
|
else
|
1059
1070
|
error_details_map.each do |(error_code, error_message), indexes|
|
1060
1071
|
partial_errors_count = indexes.length
|
@@ -1086,9 +1097,9 @@ module Fluent
|
|
1086
1097
|
# in which case we continue to look for a left curly bracket.
|
1087
1098
|
# Whitespace as per the JSON spec are: tabulation (U+0009),
|
1088
1099
|
# line feed (U+000A), carriage return (U+000D), and space (U+0020).
|
1089
|
-
break unless
|
1090
|
-
end
|
1091
|
-
end
|
1100
|
+
break unless [9, 10, 13, 32].include?(c)
|
1101
|
+
end
|
1102
|
+
end
|
1092
1103
|
nil
|
1093
1104
|
end
|
1094
1105
|
|
@@ -1191,7 +1202,8 @@ module Fluent
|
|
1191
1202
|
# "k8s_container.<namespace_name>.<pod_name>.<container_name>"
|
1192
1203
|
if local_resource_id
|
1193
1204
|
converted_resource = monitored_resource_from_local_resource_id(
|
1194
|
-
local_resource_id
|
1205
|
+
local_resource_id
|
1206
|
+
)
|
1195
1207
|
resource = converted_resource if converted_resource
|
1196
1208
|
end
|
1197
1209
|
|
@@ -1213,13 +1225,17 @@ module Fluent
|
|
1213
1225
|
# constants like GKE_CONSTANTS[:extra_resource_labels].
|
1214
1226
|
'container_name' => 'container_name',
|
1215
1227
|
'namespace_name' => 'namespace_id',
|
1216
|
-
'pod_name' => 'pod_id'
|
1228
|
+
'pod_name' => 'pod_id'
|
1229
|
+
)
|
1230
|
+
)
|
1217
1231
|
|
1218
1232
|
common_labels.merge!(
|
1219
1233
|
delete_and_extract_labels(
|
1220
1234
|
common_labels_candidates,
|
1221
1235
|
GKE_CONSTANTS[:extra_common_labels]
|
1222
|
-
.map { |l| [l, "#{GKE_CONSTANTS[:service]}/#{l}"] }.to_h
|
1236
|
+
.map { |l| [l, "#{GKE_CONSTANTS[:service]}/#{l}"] }.to_h
|
1237
|
+
)
|
1238
|
+
)
|
1223
1239
|
end
|
1224
1240
|
|
1225
1241
|
# TODO(qingling128): Temporary fallback for metadata agent restarts.
|
@@ -1237,10 +1253,13 @@ module Fluent
|
|
1237
1253
|
# e.g. "dataflow.googleapis.com/job_id" => "job_id"
|
1238
1254
|
[DATAFLOW_CONSTANTS, ML_CONSTANTS].each do |service_constants|
|
1239
1255
|
next unless resource.type == service_constants[:resource_type]
|
1256
|
+
|
1240
1257
|
resource.labels.merge!(
|
1241
1258
|
delete_and_extract_labels(
|
1242
1259
|
common_labels, service_constants[:extra_resource_labels]
|
1243
|
-
.map { |l| ["#{service_constants[:service]}/#{l}", l] }.to_h
|
1260
|
+
.map { |l| ["#{service_constants[:service]}/#{l}", l] }.to_h
|
1261
|
+
)
|
1262
|
+
)
|
1244
1263
|
end
|
1245
1264
|
|
1246
1265
|
resource.freeze
|
@@ -1253,7 +1272,8 @@ module Fluent
|
|
1253
1272
|
# Extract entry level monitored resource and common labels that should be
|
1254
1273
|
# applied to individual entries.
|
1255
1274
|
def determine_entry_level_monitored_resource_and_labels(
|
1256
|
-
group_level_resource, group_level_common_labels, record
|
1275
|
+
group_level_resource, group_level_common_labels, record
|
1276
|
+
)
|
1257
1277
|
resource = group_level_resource.dup
|
1258
1278
|
resource.labels = group_level_resource.labels.dup
|
1259
1279
|
common_labels = group_level_common_labels.dup
|
@@ -1264,7 +1284,9 @@ module Fluent
|
|
1264
1284
|
# Move the stdout/stderr annotation from the record into a label.
|
1265
1285
|
common_labels.merge!(
|
1266
1286
|
delete_and_extract_labels(
|
1267
|
-
record, 'stream' => "#{GKE_CONSTANTS[:service]}/stream"
|
1287
|
+
record, 'stream' => "#{GKE_CONSTANTS[:service]}/stream"
|
1288
|
+
)
|
1289
|
+
)
|
1268
1290
|
|
1269
1291
|
# If the record has been annotated by the kubernetes_metadata_filter
|
1270
1292
|
# plugin, then use that metadata. Otherwise, rely on commonLabels
|
@@ -1273,17 +1295,23 @@ module Fluent
|
|
1273
1295
|
resource.labels.merge!(
|
1274
1296
|
delete_and_extract_labels(
|
1275
1297
|
record['kubernetes'], GKE_CONSTANTS[:extra_resource_labels]
|
1276
|
-
.map { |l| [l, l] }.to_h
|
1298
|
+
.map { |l| [l, l] }.to_h
|
1299
|
+
)
|
1300
|
+
)
|
1277
1301
|
common_labels.merge!(
|
1278
1302
|
delete_and_extract_labels(
|
1279
1303
|
record['kubernetes'], GKE_CONSTANTS[:extra_common_labels]
|
1280
|
-
.map { |l| [l, "#{GKE_CONSTANTS[:service]}/#{l}"] }.to_h
|
1304
|
+
.map { |l| [l, "#{GKE_CONSTANTS[:service]}/#{l}"] }.to_h
|
1305
|
+
)
|
1306
|
+
)
|
1281
1307
|
# Prepend label/ to all user-defined labels' keys.
|
1282
1308
|
if record['kubernetes'].key?('labels')
|
1283
1309
|
common_labels.merge!(
|
1284
1310
|
delete_and_extract_labels(
|
1285
1311
|
record['kubernetes']['labels'], record['kubernetes']['labels']
|
1286
|
-
.map { |key, _| [key, "label/#{key}"] }.to_h
|
1312
|
+
.map { |key, _| [key, "label/#{key}"] }.to_h
|
1313
|
+
)
|
1314
|
+
)
|
1287
1315
|
end
|
1288
1316
|
# We've explicitly consumed all the fields we care about -- don't
|
1289
1317
|
# litter the log entries with the remaining fields that the kubernetes
|
@@ -1304,10 +1332,13 @@ module Fluent
|
|
1304
1332
|
# e.g. "dataflow.googleapis.com/job_id" => "job_id"
|
1305
1333
|
[DATAFLOW_CONSTANTS, ML_CONSTANTS].each do |service_constants|
|
1306
1334
|
next unless resource.type == service_constants[:resource_type]
|
1335
|
+
|
1307
1336
|
resource.labels.merge!(
|
1308
1337
|
delete_and_extract_labels(
|
1309
1338
|
common_labels, service_constants[:extra_resource_labels]
|
1310
|
-
.map { |l| ["#{service_constants[:service]}/#{l}", l] }.to_h
|
1339
|
+
.map { |l| ["#{service_constants[:service]}/#{l}", l] }.to_h
|
1340
|
+
)
|
1341
|
+
)
|
1311
1342
|
end
|
1312
1343
|
|
1313
1344
|
[resource, common_labels]
|
@@ -1350,7 +1381,7 @@ module Fluent
|
|
1350
1381
|
# k8s ISO8601 timestamp
|
1351
1382
|
begin
|
1352
1383
|
timestamp = Time.iso8601(record.delete('time'))
|
1353
|
-
rescue
|
1384
|
+
rescue StandardError
|
1354
1385
|
timestamp = Time.at(time)
|
1355
1386
|
end
|
1356
1387
|
ts_secs = timestamp.tv_sec
|
@@ -1361,15 +1392,15 @@ module Fluent
|
|
1361
1392
|
ts_nanos = timestamp.tv_nsec
|
1362
1393
|
end
|
1363
1394
|
ts_secs = begin
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1395
|
+
Integer ts_secs
|
1396
|
+
rescue ArgumentError, TypeError
|
1397
|
+
ts_secs
|
1398
|
+
end
|
1368
1399
|
ts_nanos = begin
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1400
|
+
Integer ts_nanos
|
1401
|
+
rescue ArgumentError, TypeError
|
1402
|
+
ts_nanos
|
1403
|
+
end
|
1373
1404
|
|
1374
1405
|
[ts_secs, ts_nanos, timestamp]
|
1375
1406
|
end
|
@@ -1420,6 +1451,7 @@ module Fluent
|
|
1420
1451
|
stream = entry_level_common_labels["#{GKE_CONSTANTS[:service]}/stream"]
|
1421
1452
|
return GKE_CONSTANTS[:stream_severity_map].fetch(stream, 'DEFAULT')
|
1422
1453
|
end
|
1454
|
+
|
1423
1455
|
'DEFAULT'
|
1424
1456
|
end
|
1425
1457
|
|
@@ -1438,18 +1470,20 @@ module Fluent
|
|
1438
1470
|
|
1439
1471
|
extracted_subfields = subfields.each_with_object({}) \
|
1440
1472
|
do |(original_key, destination_key, cast_fn), extracted_fields|
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1473
|
+
value = fields.delete(original_key)
|
1474
|
+
next if value.nil?
|
1475
|
+
|
1476
|
+
begin
|
1477
|
+
casted_value = send(cast_fn, value)
|
1478
|
+
rescue TypeError
|
1479
|
+
@log.error "Failed to #{cast_fn} for #{field_name}." \
|
1480
|
+
"#{original_key} with value #{value.inspect}.", err
|
1481
|
+
next
|
1482
|
+
end
|
1483
|
+
next if casted_value.nil?
|
1484
|
+
|
1485
|
+
extracted_fields[destination_key] = casted_value
|
1449
1486
|
end
|
1450
|
-
next if casted_value.nil?
|
1451
|
-
extracted_fields[destination_key] = casted_value
|
1452
|
-
end
|
1453
1487
|
|
1454
1488
|
next unless extracted_subfields
|
1455
1489
|
|
@@ -1465,8 +1499,8 @@ module Fluent
|
|
1465
1499
|
record.delete(payload_key) if fields.empty?
|
1466
1500
|
|
1467
1501
|
entry.send("#{field_name}=", output)
|
1468
|
-
rescue StandardError =>
|
1469
|
-
@log.error "Failed to set log entry field for #{field_name}.",
|
1502
|
+
rescue StandardError => e
|
1503
|
+
@log.error "Failed to set log entry field for #{field_name}.", e
|
1470
1504
|
end
|
1471
1505
|
end
|
1472
1506
|
end
|
@@ -1475,6 +1509,7 @@ module Fluent
|
|
1475
1509
|
def parse_labels(record)
|
1476
1510
|
payload_labels = record.delete(@labels_key)
|
1477
1511
|
return nil unless payload_labels
|
1512
|
+
|
1478
1513
|
unless payload_labels.is_a?(Hash)
|
1479
1514
|
@log.error "Invalid value of '#{@labels_key}' in the payload: " \
|
1480
1515
|
"#{payload_labels}. Labels need to be a JSON object."
|
@@ -1491,14 +1526,14 @@ module Fluent
|
|
1491
1526
|
return nil
|
1492
1527
|
end
|
1493
1528
|
payload_labels
|
1494
|
-
rescue StandardError =>
|
1495
|
-
@log.error "Failed to extract '#{@labels_key}' from payload.",
|
1496
|
-
|
1529
|
+
rescue StandardError => e
|
1530
|
+
@log.error "Failed to extract '#{@labels_key}' from payload.", e
|
1531
|
+
nil
|
1497
1532
|
end
|
1498
1533
|
|
1499
1534
|
# Values permitted by the API for 'severity' (which is an enum).
|
1500
1535
|
VALID_SEVERITIES = Set.new(
|
1501
|
-
%w
|
1536
|
+
%w[DEFAULT DEBUG INFO NOTICE WARNING ERROR CRITICAL ALERT EMERGENCY]
|
1502
1537
|
).freeze
|
1503
1538
|
|
1504
1539
|
# Translates other severity strings to one of the valid values above.
|
@@ -1526,6 +1561,7 @@ module Fluent
|
|
1526
1561
|
'C' => 'CRITICAL',
|
1527
1562
|
'A' => 'ALERT',
|
1528
1563
|
# other misc. translations.
|
1564
|
+
'INFORMATION' => 'INFO',
|
1529
1565
|
'ERR' => 'ERROR',
|
1530
1566
|
'F' => 'CRITICAL'
|
1531
1567
|
}.freeze
|
@@ -1543,56 +1579,53 @@ module Fluent
|
|
1543
1579
|
begin
|
1544
1580
|
numeric_severity = (severity.to_i / 100) * 100
|
1545
1581
|
case
|
1546
|
-
when numeric_severity
|
1582
|
+
when numeric_severity.negative?
|
1547
1583
|
return 0
|
1548
1584
|
when numeric_severity > 800
|
1549
1585
|
return 800
|
1550
1586
|
else
|
1551
1587
|
return numeric_severity
|
1552
1588
|
end
|
1553
|
-
rescue
|
1589
|
+
rescue StandardError
|
1554
1590
|
return 'DEFAULT'
|
1555
1591
|
end
|
1556
1592
|
end
|
1557
1593
|
|
1558
1594
|
# Try to translate the severity.
|
1559
|
-
if SEVERITY_TRANSLATIONS.key?(severity)
|
1560
|
-
return SEVERITY_TRANSLATIONS[severity]
|
1561
|
-
end
|
1595
|
+
return SEVERITY_TRANSLATIONS[severity] if SEVERITY_TRANSLATIONS.key?(severity)
|
1562
1596
|
|
1563
1597
|
# If all else fails, use 'DEFAULT'.
|
1564
1598
|
'DEFAULT'
|
1565
1599
|
end
|
1566
1600
|
|
1567
1601
|
GRPC_SEVERITY_MAPPING = {
|
1568
|
-
'DEFAULT' => Google::Logging::Type::LogSeverity::DEFAULT,
|
1569
|
-
'DEBUG' => Google::Logging::Type::LogSeverity::DEBUG,
|
1570
|
-
'INFO' => Google::Logging::Type::LogSeverity::INFO,
|
1571
|
-
'NOTICE' => Google::Logging::Type::LogSeverity::NOTICE,
|
1572
|
-
'WARNING' => Google::Logging::Type::LogSeverity::WARNING,
|
1573
|
-
'ERROR' => Google::Logging::Type::LogSeverity::ERROR,
|
1574
|
-
'CRITICAL' => Google::Logging::Type::LogSeverity::CRITICAL,
|
1575
|
-
'ALERT' => Google::Logging::Type::LogSeverity::ALERT,
|
1576
|
-
'EMERGENCY' => Google::Logging::Type::LogSeverity::EMERGENCY,
|
1577
|
-
0 => Google::Logging::Type::LogSeverity::DEFAULT,
|
1578
|
-
100 => Google::Logging::Type::LogSeverity::DEBUG,
|
1579
|
-
200 => Google::Logging::Type::LogSeverity::INFO,
|
1580
|
-
300 => Google::Logging::Type::LogSeverity::NOTICE,
|
1581
|
-
400 => Google::Logging::Type::LogSeverity::WARNING,
|
1582
|
-
500 => Google::Logging::Type::LogSeverity::ERROR,
|
1583
|
-
600 => Google::Logging::Type::LogSeverity::CRITICAL,
|
1584
|
-
700 => Google::Logging::Type::LogSeverity::ALERT,
|
1585
|
-
800 => Google::Logging::Type::LogSeverity::EMERGENCY
|
1602
|
+
'DEFAULT' => Google::Cloud::Logging::Type::LogSeverity::DEFAULT,
|
1603
|
+
'DEBUG' => Google::Cloud::Logging::Type::LogSeverity::DEBUG,
|
1604
|
+
'INFO' => Google::Cloud::Logging::Type::LogSeverity::INFO,
|
1605
|
+
'NOTICE' => Google::Cloud::Logging::Type::LogSeverity::NOTICE,
|
1606
|
+
'WARNING' => Google::Cloud::Logging::Type::LogSeverity::WARNING,
|
1607
|
+
'ERROR' => Google::Cloud::Logging::Type::LogSeverity::ERROR,
|
1608
|
+
'CRITICAL' => Google::Cloud::Logging::Type::LogSeverity::CRITICAL,
|
1609
|
+
'ALERT' => Google::Cloud::Logging::Type::LogSeverity::ALERT,
|
1610
|
+
'EMERGENCY' => Google::Cloud::Logging::Type::LogSeverity::EMERGENCY,
|
1611
|
+
0 => Google::Cloud::Logging::Type::LogSeverity::DEFAULT,
|
1612
|
+
100 => Google::Cloud::Logging::Type::LogSeverity::DEBUG,
|
1613
|
+
200 => Google::Cloud::Logging::Type::LogSeverity::INFO,
|
1614
|
+
300 => Google::Cloud::Logging::Type::LogSeverity::NOTICE,
|
1615
|
+
400 => Google::Cloud::Logging::Type::LogSeverity::WARNING,
|
1616
|
+
500 => Google::Cloud::Logging::Type::LogSeverity::ERROR,
|
1617
|
+
600 => Google::Cloud::Logging::Type::LogSeverity::CRITICAL,
|
1618
|
+
700 => Google::Cloud::Logging::Type::LogSeverity::ALERT,
|
1619
|
+
800 => Google::Cloud::Logging::Type::LogSeverity::EMERGENCY
|
1586
1620
|
}.freeze
|
1587
1621
|
|
1588
1622
|
def grpc_severity(severity)
|
1589
1623
|
# TODO: find out why this doesn't work.
|
1590
1624
|
# if severity.is_a? String
|
1591
|
-
# return Google::Logging::Type::LogSeverity.resolve(severity)
|
1625
|
+
# return Google::Cloud::Logging::Type::LogSeverity.resolve(severity)
|
1592
1626
|
# end
|
1593
|
-
if GRPC_SEVERITY_MAPPING.key?(severity)
|
1594
|
-
|
1595
|
-
end
|
1627
|
+
return GRPC_SEVERITY_MAPPING[severity] if GRPC_SEVERITY_MAPPING.key?(severity)
|
1628
|
+
|
1596
1629
|
severity
|
1597
1630
|
end
|
1598
1631
|
|
@@ -1623,15 +1656,15 @@ module Fluent
|
|
1623
1656
|
seconds = match['seconds'].to_i
|
1624
1657
|
nanos = (match['decimal'].to_f * 1000 * 1000 * 1000).round
|
1625
1658
|
if @use_grpc
|
1626
|
-
|
1659
|
+
Google::Protobuf::Duration.new(
|
1627
1660
|
seconds: seconds,
|
1628
1661
|
nanos: nanos
|
1629
1662
|
)
|
1630
1663
|
else
|
1631
|
-
|
1664
|
+
{
|
1632
1665
|
seconds: seconds,
|
1633
1666
|
nanos: nanos
|
1634
|
-
}.delete_if { |_, v| v
|
1667
|
+
}.delete_if { |_, v| v.zero? }
|
1635
1668
|
end
|
1636
1669
|
end
|
1637
1670
|
|
@@ -1652,6 +1685,7 @@ module Fluent
|
|
1652
1685
|
(!tag.is_a?(String) || tag == '' || convert_to_utf8(tag) != tag)
|
1653
1686
|
return nil
|
1654
1687
|
end
|
1688
|
+
|
1655
1689
|
tag = convert_to_utf8(tag.to_s)
|
1656
1690
|
tag = '_' if tag == ''
|
1657
1691
|
tag
|
@@ -1663,11 +1697,12 @@ module Fluent
|
|
1663
1697
|
def delete_and_extract_labels(hash, label_map)
|
1664
1698
|
return {} if label_map.nil? || !label_map.is_a?(Hash) ||
|
1665
1699
|
hash.nil? || !hash.is_a?(Hash)
|
1700
|
+
|
1666
1701
|
label_map.each_with_object({}) \
|
1667
1702
|
do |(original_label, new_label), extracted_labels|
|
1668
|
-
|
1669
|
-
|
1670
|
-
|
1703
|
+
value = hash.delete(original_label)
|
1704
|
+
extracted_labels[new_label] = convert_to_utf8(value.to_s) if value
|
1705
|
+
end
|
1671
1706
|
end
|
1672
1707
|
|
1673
1708
|
def value_from_ruby(value)
|
@@ -1757,13 +1792,12 @@ module Fluent
|
|
1757
1792
|
elsif resource.type == GKE_CONSTANTS[:resource_type]
|
1758
1793
|
# For Kubernetes logs, use just the container name as the log name
|
1759
1794
|
# if we have it.
|
1760
|
-
if resource.labels
|
1795
|
+
if resource.labels&.key?('container_name')
|
1761
1796
|
sanitized_tag = sanitize_tag(resource.labels['container_name'])
|
1762
1797
|
tag = sanitized_tag unless sanitized_tag.nil?
|
1763
1798
|
end
|
1764
1799
|
end
|
1765
|
-
|
1766
|
-
tag
|
1800
|
+
ERB::Util.url_encode(tag)
|
1767
1801
|
end
|
1768
1802
|
|
1769
1803
|
def init_api_client
|
@@ -1780,7 +1814,8 @@ module Fluent
|
|
1780
1814
|
if @grpc_compression_algorithm
|
1781
1815
|
compression_options =
|
1782
1816
|
GRPC::Core::CompressionOptions.new(
|
1783
|
-
default_algorithm: @grpc_compression_algorithm
|
1817
|
+
default_algorithm: @grpc_compression_algorithm
|
1818
|
+
)
|
1784
1819
|
compression_channel_args = compression_options.to_channel_arg_hash
|
1785
1820
|
else
|
1786
1821
|
compression_channel_args = {}
|
@@ -1799,16 +1834,19 @@ module Fluent
|
|
1799
1834
|
"#{Google::Apis::OS_VERSION}"
|
1800
1835
|
channel_args = { 'grpc.primary_user_agent' => user_agent }
|
1801
1836
|
.merge!(compression_channel_args)
|
1802
|
-
@client = Google::Cloud::Logging::V2::
|
1803
|
-
credentials
|
1804
|
-
"#{host}#{port}", channel_args, creds
|
1837
|
+
@client = Google::Cloud::Logging::V2::LoggingService::Client.new do |config|
|
1838
|
+
config.credentials = GRPC::Core::Channel.new(
|
1839
|
+
"#{host}#{port}", channel_args, creds
|
1840
|
+
)
|
1841
|
+
end
|
1805
1842
|
else
|
1806
1843
|
# TODO: Use a non-default ClientOptions object.
|
1807
1844
|
Google::Apis::ClientOptions.default.application_name = PLUGIN_NAME
|
1808
1845
|
Google::Apis::ClientOptions.default.application_version = PLUGIN_VERSION
|
1809
1846
|
@client = Google::Apis::LoggingV2::LoggingService.new
|
1810
1847
|
@client.authorization = Google::Auth.get_application_default(
|
1811
|
-
Common::LOGGING_SCOPE
|
1848
|
+
Common::LOGGING_SCOPE
|
1849
|
+
)
|
1812
1850
|
end
|
1813
1851
|
end
|
1814
1852
|
|
@@ -1838,7 +1876,8 @@ module Fluent
|
|
1838
1876
|
'utf-8',
|
1839
1877
|
invalid: :replace,
|
1840
1878
|
undef: :replace,
|
1841
|
-
replace: @non_utf8_replacement_string
|
1879
|
+
replace: @non_utf8_replacement_string
|
1880
|
+
)
|
1842
1881
|
else
|
1843
1882
|
begin
|
1844
1883
|
input.encode('utf-8')
|
@@ -1931,19 +1970,22 @@ module Fluent
|
|
1931
1970
|
error_details_map = Hash.new { |h, k| h[k] = [] }
|
1932
1971
|
|
1933
1972
|
error_details = ensure_array(
|
1934
|
-
ensure_hash(ensure_hash(JSON.parse(error.body))['error'])['details']
|
1973
|
+
ensure_hash(ensure_hash(JSON.parse(error.body))['error'])['details']
|
1974
|
+
)
|
1935
1975
|
partial_errors = error_details.detect(
|
1936
1976
|
-> { raise JSON::ParserError, "No type #{PARTIAL_ERROR_FIELD}." }
|
1937
1977
|
) do |error_detail|
|
1938
1978
|
ensure_hash(error_detail)['@type'] == PARTIAL_ERROR_FIELD
|
1939
1979
|
end
|
1940
1980
|
log_entry_errors = ensure_hash(
|
1941
|
-
ensure_hash(partial_errors)['logEntryErrors']
|
1981
|
+
ensure_hash(partial_errors)['logEntryErrors']
|
1982
|
+
)
|
1942
1983
|
log_entry_errors.each do |index, log_entry_error|
|
1943
1984
|
error_hash = ensure_hash(log_entry_error)
|
1944
|
-
|
1945
|
-
|
1946
|
-
|
1985
|
+
unless error_hash['code'] && error_hash['message']
|
1986
|
+
raise JSON::ParserError,
|
1987
|
+
"Entry #{index} is missing 'code' or 'message'."
|
1988
|
+
end
|
1947
1989
|
error_key = [error_hash['code'], error_hash['message']].freeze
|
1948
1990
|
# TODO(qingling128): Convert indexes to integers.
|
1949
1991
|
error_details_map[error_key] << index
|
@@ -1962,11 +2004,10 @@ module Fluent
|
|
1962
2004
|
# are a list of indexes of log entries that failed due to this error.
|
1963
2005
|
#
|
1964
2006
|
# A sample error looks like:
|
1965
|
-
# <Google::
|
1966
|
-
# message: '
|
1967
|
-
# ified as transient, caused by 7:User not authorized.',
|
2007
|
+
# <Google::Cloud::PermissionDeniedError:
|
2008
|
+
# message: 'User not authorized.',
|
1968
2009
|
# details: [
|
1969
|
-
# <Google::Logging::V2::WriteLogEntriesPartialErrors:
|
2010
|
+
# <Google::Cloud::Logging::V2::WriteLogEntriesPartialErrors:
|
1970
2011
|
# log_entry_errors: {
|
1971
2012
|
# 0 => <Google::Rpc::Status:
|
1972
2013
|
# code: 7,
|
@@ -1996,13 +2037,16 @@ module Fluent
|
|
1996
2037
|
# [3, 'Log name contains illegal character :']: [1, 3]
|
1997
2038
|
# }
|
1998
2039
|
def construct_error_details_map_grpc(gax_error)
|
2040
|
+
@log.error "construct_error_details_map_grpc: #{gax_error}"
|
1999
2041
|
error_details_map = Hash.new { |h, k| h[k] = [] }
|
2000
2042
|
error_details = ensure_array(gax_error.status_details)
|
2001
2043
|
raise JSON::ParserError, 'The error details are empty.' if
|
2002
2044
|
error_details.empty?
|
2003
2045
|
raise JSON::ParserError, 'No partial error info in error details.' unless
|
2004
2046
|
error_details[0].is_a?(
|
2005
|
-
Google::Logging::V2::WriteLogEntriesPartialErrors
|
2047
|
+
Google::Cloud::Logging::V2::WriteLogEntriesPartialErrors
|
2048
|
+
)
|
2049
|
+
|
2006
2050
|
log_entry_errors = ensure_hash(error_details[0].log_entry_errors)
|
2007
2051
|
log_entry_errors.each do |index, log_entry_error|
|
2008
2052
|
error_key = [log_entry_error[:code], log_entry_error[:message]].freeze
|
@@ -2038,9 +2082,11 @@ module Fluent
|
|
2038
2082
|
|
2039
2083
|
begin
|
2040
2084
|
@k8s_cluster_name ||= @utils.fetch_gce_metadata(
|
2041
|
-
@platform, 'instance/attributes/cluster-name'
|
2085
|
+
@platform, 'instance/attributes/cluster-name'
|
2086
|
+
)
|
2042
2087
|
@k8s_cluster_location ||= @utils.fetch_gce_metadata(
|
2043
|
-
@platform, 'instance/attributes/cluster-location'
|
2088
|
+
@platform, 'instance/attributes/cluster-location'
|
2089
|
+
)
|
2044
2090
|
rescue StandardError => e
|
2045
2091
|
@log.error 'Failed to retrieve k8s cluster name and location.', \
|
2046
2092
|
error: e
|
@@ -2079,7 +2125,8 @@ module Fluent
|
|
2079
2125
|
end
|
2080
2126
|
constructed_resource = Google::Apis::LoggingV2::MonitoredResource.new(
|
2081
2127
|
type: resource_type,
|
2082
|
-
labels: labels
|
2128
|
+
labels: labels
|
2129
|
+
)
|
2083
2130
|
@log.debug("Constructed #{resource_type} resource locally: " \
|
2084
2131
|
"#{constructed_resource.inspect}")
|
2085
2132
|
constructed_resource
|
@@ -2098,40 +2145,50 @@ module Fluent
|
|
2098
2145
|
# Increment the metric for the number of successful requests.
|
2099
2146
|
def increment_successful_requests_count
|
2100
2147
|
return unless @successful_requests_count
|
2148
|
+
|
2101
2149
|
@successful_requests_count.increment(
|
2102
|
-
labels: { grpc: @use_grpc, code: @ok_code }
|
2150
|
+
labels: { grpc: @use_grpc, code: @ok_code }
|
2151
|
+
)
|
2103
2152
|
end
|
2104
2153
|
|
2105
2154
|
# Increment the metric for the number of failed requests, labeled by
|
2106
2155
|
# the provided status code.
|
2107
2156
|
def increment_failed_requests_count(code)
|
2108
2157
|
return unless @failed_requests_count
|
2158
|
+
|
2109
2159
|
@failed_requests_count.increment(
|
2110
|
-
labels: { grpc: @use_grpc, code: code }
|
2160
|
+
labels: { grpc: @use_grpc, code: code }
|
2161
|
+
)
|
2111
2162
|
end
|
2112
2163
|
|
2113
2164
|
# Increment the metric for the number of log entries, successfully
|
2114
2165
|
# ingested by the Stackdriver Logging API.
|
2115
2166
|
def increment_ingested_entries_count(count)
|
2116
2167
|
return unless @ingested_entries_count
|
2168
|
+
|
2117
2169
|
@ingested_entries_count.increment(
|
2118
|
-
labels: { grpc: @use_grpc, code: @ok_code }, by: count
|
2170
|
+
labels: { grpc: @use_grpc, code: @ok_code }, by: count
|
2171
|
+
)
|
2119
2172
|
end
|
2120
2173
|
|
2121
2174
|
# Increment the metric for the number of log entries that were dropped
|
2122
2175
|
# and not ingested by the Stackdriver Logging API.
|
2123
2176
|
def increment_dropped_entries_count(count, code)
|
2124
2177
|
return unless @dropped_entries_count
|
2178
|
+
|
2125
2179
|
@dropped_entries_count.increment(
|
2126
|
-
labels: { grpc: @use_grpc, code: code }, by: count
|
2180
|
+
labels: { grpc: @use_grpc, code: code }, by: count
|
2181
|
+
)
|
2127
2182
|
end
|
2128
2183
|
|
2129
2184
|
# Increment the metric for the number of log entries that were dropped
|
2130
2185
|
# and not ingested by the Stackdriver Logging API.
|
2131
2186
|
def increment_retried_entries_count(count, code)
|
2132
2187
|
return unless @retried_entries_count
|
2188
|
+
|
2133
2189
|
@retried_entries_count.increment(
|
2134
|
-
labels: { grpc: @use_grpc, code: code }, by: count
|
2190
|
+
labels: { grpc: @use_grpc, code: code }, by: count
|
2191
|
+
)
|
2135
2192
|
end
|
2136
2193
|
end
|
2137
2194
|
end
|