fluent-plugin-google-cloud 0.12.10 → 0.13.0
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 +99 -71
- data/Rakefile +6 -5
- data/fluent-plugin-google-cloud.gemspec +17 -21
- 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 +65 -47
- data/lib/fluent/plugin/in_object_space_dump.rb +1 -1
- data/lib/fluent/plugin/monitoring.rb +34 -23
- data/lib/fluent/plugin/out_google_cloud.rb +269 -213
- data/lib/fluent/plugin/statusz.rb +10 -10
- data/test/helper.rb +6 -0
- data/test/plugin/base_test.rb +199 -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 +53 -39
@@ -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.
|
@@ -1544,56 +1579,53 @@ module Fluent
|
|
1544
1579
|
begin
|
1545
1580
|
numeric_severity = (severity.to_i / 100) * 100
|
1546
1581
|
case
|
1547
|
-
when numeric_severity
|
1582
|
+
when numeric_severity.negative?
|
1548
1583
|
return 0
|
1549
1584
|
when numeric_severity > 800
|
1550
1585
|
return 800
|
1551
1586
|
else
|
1552
1587
|
return numeric_severity
|
1553
1588
|
end
|
1554
|
-
rescue
|
1589
|
+
rescue StandardError
|
1555
1590
|
return 'DEFAULT'
|
1556
1591
|
end
|
1557
1592
|
end
|
1558
1593
|
|
1559
1594
|
# Try to translate the severity.
|
1560
|
-
if SEVERITY_TRANSLATIONS.key?(severity)
|
1561
|
-
return SEVERITY_TRANSLATIONS[severity]
|
1562
|
-
end
|
1595
|
+
return SEVERITY_TRANSLATIONS[severity] if SEVERITY_TRANSLATIONS.key?(severity)
|
1563
1596
|
|
1564
1597
|
# If all else fails, use 'DEFAULT'.
|
1565
1598
|
'DEFAULT'
|
1566
1599
|
end
|
1567
1600
|
|
1568
1601
|
GRPC_SEVERITY_MAPPING = {
|
1569
|
-
'DEFAULT' => Google::Logging::Type::LogSeverity::DEFAULT,
|
1570
|
-
'DEBUG' => Google::Logging::Type::LogSeverity::DEBUG,
|
1571
|
-
'INFO' => Google::Logging::Type::LogSeverity::INFO,
|
1572
|
-
'NOTICE' => Google::Logging::Type::LogSeverity::NOTICE,
|
1573
|
-
'WARNING' => Google::Logging::Type::LogSeverity::WARNING,
|
1574
|
-
'ERROR' => Google::Logging::Type::LogSeverity::ERROR,
|
1575
|
-
'CRITICAL' => Google::Logging::Type::LogSeverity::CRITICAL,
|
1576
|
-
'ALERT' => Google::Logging::Type::LogSeverity::ALERT,
|
1577
|
-
'EMERGENCY' => Google::Logging::Type::LogSeverity::EMERGENCY,
|
1578
|
-
0 => Google::Logging::Type::LogSeverity::DEFAULT,
|
1579
|
-
100 => Google::Logging::Type::LogSeverity::DEBUG,
|
1580
|
-
200 => Google::Logging::Type::LogSeverity::INFO,
|
1581
|
-
300 => Google::Logging::Type::LogSeverity::NOTICE,
|
1582
|
-
400 => Google::Logging::Type::LogSeverity::WARNING,
|
1583
|
-
500 => Google::Logging::Type::LogSeverity::ERROR,
|
1584
|
-
600 => Google::Logging::Type::LogSeverity::CRITICAL,
|
1585
|
-
700 => Google::Logging::Type::LogSeverity::ALERT,
|
1586
|
-
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
|
1587
1620
|
}.freeze
|
1588
1621
|
|
1589
1622
|
def grpc_severity(severity)
|
1590
1623
|
# TODO: find out why this doesn't work.
|
1591
1624
|
# if severity.is_a? String
|
1592
|
-
# return Google::Logging::Type::LogSeverity.resolve(severity)
|
1625
|
+
# return Google::Cloud::Logging::Type::LogSeverity.resolve(severity)
|
1593
1626
|
# end
|
1594
|
-
if GRPC_SEVERITY_MAPPING.key?(severity)
|
1595
|
-
|
1596
|
-
end
|
1627
|
+
return GRPC_SEVERITY_MAPPING[severity] if GRPC_SEVERITY_MAPPING.key?(severity)
|
1628
|
+
|
1597
1629
|
severity
|
1598
1630
|
end
|
1599
1631
|
|
@@ -1624,15 +1656,15 @@ module Fluent
|
|
1624
1656
|
seconds = match['seconds'].to_i
|
1625
1657
|
nanos = (match['decimal'].to_f * 1000 * 1000 * 1000).round
|
1626
1658
|
if @use_grpc
|
1627
|
-
|
1659
|
+
Google::Protobuf::Duration.new(
|
1628
1660
|
seconds: seconds,
|
1629
1661
|
nanos: nanos
|
1630
1662
|
)
|
1631
1663
|
else
|
1632
|
-
|
1664
|
+
{
|
1633
1665
|
seconds: seconds,
|
1634
1666
|
nanos: nanos
|
1635
|
-
}.delete_if { |_, v| v
|
1667
|
+
}.delete_if { |_, v| v.zero? }
|
1636
1668
|
end
|
1637
1669
|
end
|
1638
1670
|
|
@@ -1653,6 +1685,7 @@ module Fluent
|
|
1653
1685
|
(!tag.is_a?(String) || tag == '' || convert_to_utf8(tag) != tag)
|
1654
1686
|
return nil
|
1655
1687
|
end
|
1688
|
+
|
1656
1689
|
tag = convert_to_utf8(tag.to_s)
|
1657
1690
|
tag = '_' if tag == ''
|
1658
1691
|
tag
|
@@ -1664,11 +1697,12 @@ module Fluent
|
|
1664
1697
|
def delete_and_extract_labels(hash, label_map)
|
1665
1698
|
return {} if label_map.nil? || !label_map.is_a?(Hash) ||
|
1666
1699
|
hash.nil? || !hash.is_a?(Hash)
|
1700
|
+
|
1667
1701
|
label_map.each_with_object({}) \
|
1668
1702
|
do |(original_label, new_label), extracted_labels|
|
1669
|
-
|
1670
|
-
|
1671
|
-
|
1703
|
+
value = hash.delete(original_label)
|
1704
|
+
extracted_labels[new_label] = convert_to_utf8(value.to_s) if value
|
1705
|
+
end
|
1672
1706
|
end
|
1673
1707
|
|
1674
1708
|
def value_from_ruby(value)
|
@@ -1758,13 +1792,12 @@ module Fluent
|
|
1758
1792
|
elsif resource.type == GKE_CONSTANTS[:resource_type]
|
1759
1793
|
# For Kubernetes logs, use just the container name as the log name
|
1760
1794
|
# if we have it.
|
1761
|
-
if resource.labels
|
1795
|
+
if resource.labels&.key?('container_name')
|
1762
1796
|
sanitized_tag = sanitize_tag(resource.labels['container_name'])
|
1763
1797
|
tag = sanitized_tag unless sanitized_tag.nil?
|
1764
1798
|
end
|
1765
1799
|
end
|
1766
|
-
|
1767
|
-
tag
|
1800
|
+
ERB::Util.url_encode(tag)
|
1768
1801
|
end
|
1769
1802
|
|
1770
1803
|
def init_api_client
|
@@ -1781,7 +1814,8 @@ module Fluent
|
|
1781
1814
|
if @grpc_compression_algorithm
|
1782
1815
|
compression_options =
|
1783
1816
|
GRPC::Core::CompressionOptions.new(
|
1784
|
-
default_algorithm: @grpc_compression_algorithm
|
1817
|
+
default_algorithm: @grpc_compression_algorithm
|
1818
|
+
)
|
1785
1819
|
compression_channel_args = compression_options.to_channel_arg_hash
|
1786
1820
|
else
|
1787
1821
|
compression_channel_args = {}
|
@@ -1800,16 +1834,19 @@ module Fluent
|
|
1800
1834
|
"#{Google::Apis::OS_VERSION}"
|
1801
1835
|
channel_args = { 'grpc.primary_user_agent' => user_agent }
|
1802
1836
|
.merge!(compression_channel_args)
|
1803
|
-
@client = Google::Cloud::Logging::V2::
|
1804
|
-
credentials
|
1805
|
-
"#{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
|
1806
1842
|
else
|
1807
1843
|
# TODO: Use a non-default ClientOptions object.
|
1808
1844
|
Google::Apis::ClientOptions.default.application_name = PLUGIN_NAME
|
1809
1845
|
Google::Apis::ClientOptions.default.application_version = PLUGIN_VERSION
|
1810
1846
|
@client = Google::Apis::LoggingV2::LoggingService.new
|
1811
1847
|
@client.authorization = Google::Auth.get_application_default(
|
1812
|
-
Common::LOGGING_SCOPE
|
1848
|
+
Common::LOGGING_SCOPE
|
1849
|
+
)
|
1813
1850
|
end
|
1814
1851
|
end
|
1815
1852
|
|
@@ -1839,7 +1876,8 @@ module Fluent
|
|
1839
1876
|
'utf-8',
|
1840
1877
|
invalid: :replace,
|
1841
1878
|
undef: :replace,
|
1842
|
-
replace: @non_utf8_replacement_string
|
1879
|
+
replace: @non_utf8_replacement_string
|
1880
|
+
)
|
1843
1881
|
else
|
1844
1882
|
begin
|
1845
1883
|
input.encode('utf-8')
|
@@ -1932,19 +1970,22 @@ module Fluent
|
|
1932
1970
|
error_details_map = Hash.new { |h, k| h[k] = [] }
|
1933
1971
|
|
1934
1972
|
error_details = ensure_array(
|
1935
|
-
ensure_hash(ensure_hash(JSON.parse(error.body))['error'])['details']
|
1973
|
+
ensure_hash(ensure_hash(JSON.parse(error.body))['error'])['details']
|
1974
|
+
)
|
1936
1975
|
partial_errors = error_details.detect(
|
1937
1976
|
-> { raise JSON::ParserError, "No type #{PARTIAL_ERROR_FIELD}." }
|
1938
1977
|
) do |error_detail|
|
1939
1978
|
ensure_hash(error_detail)['@type'] == PARTIAL_ERROR_FIELD
|
1940
1979
|
end
|
1941
1980
|
log_entry_errors = ensure_hash(
|
1942
|
-
ensure_hash(partial_errors)['logEntryErrors']
|
1981
|
+
ensure_hash(partial_errors)['logEntryErrors']
|
1982
|
+
)
|
1943
1983
|
log_entry_errors.each do |index, log_entry_error|
|
1944
1984
|
error_hash = ensure_hash(log_entry_error)
|
1945
|
-
|
1946
|
-
|
1947
|
-
|
1985
|
+
unless error_hash['code'] && error_hash['message']
|
1986
|
+
raise JSON::ParserError,
|
1987
|
+
"Entry #{index} is missing 'code' or 'message'."
|
1988
|
+
end
|
1948
1989
|
error_key = [error_hash['code'], error_hash['message']].freeze
|
1949
1990
|
# TODO(qingling128): Convert indexes to integers.
|
1950
1991
|
error_details_map[error_key] << index
|
@@ -1963,11 +2004,10 @@ module Fluent
|
|
1963
2004
|
# are a list of indexes of log entries that failed due to this error.
|
1964
2005
|
#
|
1965
2006
|
# A sample error looks like:
|
1966
|
-
# <Google::
|
1967
|
-
# message: '
|
1968
|
-
# ified as transient, caused by 7:User not authorized.',
|
2007
|
+
# <Google::Cloud::PermissionDeniedError:
|
2008
|
+
# message: 'User not authorized.',
|
1969
2009
|
# details: [
|
1970
|
-
# <Google::Logging::V2::WriteLogEntriesPartialErrors:
|
2010
|
+
# <Google::Cloud::Logging::V2::WriteLogEntriesPartialErrors:
|
1971
2011
|
# log_entry_errors: {
|
1972
2012
|
# 0 => <Google::Rpc::Status:
|
1973
2013
|
# code: 7,
|
@@ -1997,13 +2037,16 @@ module Fluent
|
|
1997
2037
|
# [3, 'Log name contains illegal character :']: [1, 3]
|
1998
2038
|
# }
|
1999
2039
|
def construct_error_details_map_grpc(gax_error)
|
2040
|
+
@log.error "construct_error_details_map_grpc: #{gax_error}"
|
2000
2041
|
error_details_map = Hash.new { |h, k| h[k] = [] }
|
2001
2042
|
error_details = ensure_array(gax_error.status_details)
|
2002
2043
|
raise JSON::ParserError, 'The error details are empty.' if
|
2003
2044
|
error_details.empty?
|
2004
2045
|
raise JSON::ParserError, 'No partial error info in error details.' unless
|
2005
2046
|
error_details[0].is_a?(
|
2006
|
-
Google::Logging::V2::WriteLogEntriesPartialErrors
|
2047
|
+
Google::Cloud::Logging::V2::WriteLogEntriesPartialErrors
|
2048
|
+
)
|
2049
|
+
|
2007
2050
|
log_entry_errors = ensure_hash(error_details[0].log_entry_errors)
|
2008
2051
|
log_entry_errors.each do |index, log_entry_error|
|
2009
2052
|
error_key = [log_entry_error[:code], log_entry_error[:message]].freeze
|
@@ -2039,9 +2082,11 @@ module Fluent
|
|
2039
2082
|
|
2040
2083
|
begin
|
2041
2084
|
@k8s_cluster_name ||= @utils.fetch_gce_metadata(
|
2042
|
-
@platform, 'instance/attributes/cluster-name'
|
2085
|
+
@platform, 'instance/attributes/cluster-name'
|
2086
|
+
)
|
2043
2087
|
@k8s_cluster_location ||= @utils.fetch_gce_metadata(
|
2044
|
-
@platform, 'instance/attributes/cluster-location'
|
2088
|
+
@platform, 'instance/attributes/cluster-location'
|
2089
|
+
)
|
2045
2090
|
rescue StandardError => e
|
2046
2091
|
@log.error 'Failed to retrieve k8s cluster name and location.', \
|
2047
2092
|
error: e
|
@@ -2080,7 +2125,8 @@ module Fluent
|
|
2080
2125
|
end
|
2081
2126
|
constructed_resource = Google::Apis::LoggingV2::MonitoredResource.new(
|
2082
2127
|
type: resource_type,
|
2083
|
-
labels: labels
|
2128
|
+
labels: labels
|
2129
|
+
)
|
2084
2130
|
@log.debug("Constructed #{resource_type} resource locally: " \
|
2085
2131
|
"#{constructed_resource.inspect}")
|
2086
2132
|
constructed_resource
|
@@ -2099,40 +2145,50 @@ module Fluent
|
|
2099
2145
|
# Increment the metric for the number of successful requests.
|
2100
2146
|
def increment_successful_requests_count
|
2101
2147
|
return unless @successful_requests_count
|
2148
|
+
|
2102
2149
|
@successful_requests_count.increment(
|
2103
|
-
labels: { grpc: @use_grpc, code: @ok_code }
|
2150
|
+
labels: { grpc: @use_grpc, code: @ok_code }
|
2151
|
+
)
|
2104
2152
|
end
|
2105
2153
|
|
2106
2154
|
# Increment the metric for the number of failed requests, labeled by
|
2107
2155
|
# the provided status code.
|
2108
2156
|
def increment_failed_requests_count(code)
|
2109
2157
|
return unless @failed_requests_count
|
2158
|
+
|
2110
2159
|
@failed_requests_count.increment(
|
2111
|
-
labels: { grpc: @use_grpc, code: code }
|
2160
|
+
labels: { grpc: @use_grpc, code: code }
|
2161
|
+
)
|
2112
2162
|
end
|
2113
2163
|
|
2114
2164
|
# Increment the metric for the number of log entries, successfully
|
2115
2165
|
# ingested by the Stackdriver Logging API.
|
2116
2166
|
def increment_ingested_entries_count(count)
|
2117
2167
|
return unless @ingested_entries_count
|
2168
|
+
|
2118
2169
|
@ingested_entries_count.increment(
|
2119
|
-
labels: { grpc: @use_grpc, code: @ok_code }, by: count
|
2170
|
+
labels: { grpc: @use_grpc, code: @ok_code }, by: count
|
2171
|
+
)
|
2120
2172
|
end
|
2121
2173
|
|
2122
2174
|
# Increment the metric for the number of log entries that were dropped
|
2123
2175
|
# and not ingested by the Stackdriver Logging API.
|
2124
2176
|
def increment_dropped_entries_count(count, code)
|
2125
2177
|
return unless @dropped_entries_count
|
2178
|
+
|
2126
2179
|
@dropped_entries_count.increment(
|
2127
|
-
labels: { grpc: @use_grpc, code: code }, by: count
|
2180
|
+
labels: { grpc: @use_grpc, code: code }, by: count
|
2181
|
+
)
|
2128
2182
|
end
|
2129
2183
|
|
2130
2184
|
# Increment the metric for the number of log entries that were dropped
|
2131
2185
|
# and not ingested by the Stackdriver Logging API.
|
2132
2186
|
def increment_retried_entries_count(count, code)
|
2133
2187
|
return unless @retried_entries_count
|
2188
|
+
|
2134
2189
|
@retried_entries_count.increment(
|
2135
|
-
labels: { grpc: @use_grpc, code: code }, by: count
|
2190
|
+
labels: { grpc: @use_grpc, code: code }, by: count
|
2191
|
+
)
|
2136
2192
|
end
|
2137
2193
|
end
|
2138
2194
|
end
|