fluent-plugin-google-cloud 0.6.8 → 0.6.9.pre.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5e8ef1f49a71df9fe1f3d06422ab70861af8b236
4
- data.tar.gz: 75944aae3e5ea94e1d90ddf17e4ebda82eb2a75a
3
+ metadata.gz: 88272d0a151ead26a57ac7b523602e566a2c6e79
4
+ data.tar.gz: 3161e4dd7387a67af1c725a5423165f42d85a448
5
5
  SHA512:
6
- metadata.gz: 859c5b09cf8130aebdba203a2683d13e7f605eaebff7978b829d7f128e16999e4bc1272282f85ab79b8209eef175bae62e523941dcf3947b8cc9da030bd51f84
7
- data.tar.gz: 38987eb08a7d895d830a0d586a5fcd7bbc2594ef3863977e9518db7bad085e241857e1852f485027dddcce039c48e880cc58ae565734efa5bc1b093c798a7df2
6
+ metadata.gz: b3e2e2acd6e6b7083bf806ad2cdda05f2bb0014cb751a2ee7777b05c21428e2c6256ff16764652b337700f8568df3e02b3e055e3ce8da8505f24e95220e50f6f
7
+ data.tar.gz: d9bed2291c45799ead9d6ef38d3f59bfb9e49f26c34b141e1f2f7db60e4bdc7623304d276b468d6816b02981b8439a39a5158d23b954bc319a93922db1b0e786
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fluent-plugin-google-cloud (0.6.8)
4
+ fluent-plugin-google-cloud (0.6.9.pre.1)
5
5
  fluentd (~> 0.10)
6
- google-api-client (~> 0.9.0)
7
- google-cloud-logging (= 0.24.1)
6
+ google-api-client (~> 0.14)
7
+ google-cloud-logging (~> 1.2, >= 1.2.3)
8
8
  googleapis-common-protos (~> 1.3)
9
9
  googleauth (~> 0.4, < 0.5.2)
10
10
  grpc (~> 1.0, < 1.3)
@@ -21,6 +21,8 @@ GEM
21
21
  cool.io (1.5.1)
22
22
  crack (0.4.3)
23
23
  safe_yaml (~> 1.0.0)
24
+ declarative (0.0.10)
25
+ declarative-option (0.1.0)
24
26
  faraday (0.13.1)
25
27
  multipart-post (>= 1.2, < 3)
26
28
  fluentd (0.14.21)
@@ -34,22 +36,23 @@ GEM
34
36
  tzinfo (~> 1.0)
35
37
  tzinfo-data (~> 1.0)
36
38
  yajl-ruby (~> 1.0)
37
- google-api-client (0.9.28)
38
- addressable (~> 2.3)
39
+ google-api-client (0.15.0)
40
+ addressable (~> 2.5, >= 2.5.1)
39
41
  googleauth (~> 0.5)
40
- httpclient (~> 2.7)
41
- hurley (~> 0.1)
42
- memoist (~> 0.11)
43
- mime-types (>= 1.6)
44
- representable (~> 2.3.0)
45
- retriable (~> 2.0)
46
- google-cloud-core (0.21.1)
42
+ httpclient (>= 2.8.1, < 3.0)
43
+ mime-types (~> 3.0)
44
+ representable (~> 3.0)
45
+ retriable (>= 2.0, < 4.0)
46
+ google-cloud-core (1.0.0)
47
+ google-cloud-env (~> 1.0)
47
48
  googleauth (~> 0.5.1)
48
- google-cloud-logging (0.24.1)
49
- google-cloud-core (~> 0.21.1)
49
+ google-cloud-env (1.0.1)
50
+ faraday (~> 0.11)
51
+ google-cloud-logging (1.2.3)
52
+ google-cloud-core (~> 1.0)
50
53
  google-gax (~> 0.8.0)
51
- stackdriver-core (~> 0.21.0)
52
- google-gax (0.8.7)
54
+ stackdriver-core (~> 1.2)
55
+ google-gax (0.8.10)
53
56
  google-protobuf (~> 3.2)
54
57
  googleapis-common-protos (~> 1.3.5)
55
58
  googleauth (~> 0.5.1)
@@ -73,10 +76,9 @@ GEM
73
76
  grpc (1.2.5)
74
77
  google-protobuf (~> 3.1)
75
78
  googleauth (~> 0.5.1)
76
- hashdiff (0.3.6)
79
+ hashdiff (0.3.7)
77
80
  http_parser.rb (0.6.0)
78
81
  httpclient (2.8.3)
79
- hurley (0.2)
80
82
  json (1.8.6)
81
83
  jwt (1.5.6)
82
84
  little-plugger (1.1.4)
@@ -105,9 +107,11 @@ GEM
105
107
  rainbow (2.2.2)
106
108
  rake
107
109
  rake (10.5.0)
108
- representable (2.3.0)
109
- uber (~> 0.0.7)
110
- retriable (2.1.0)
110
+ representable (3.0.4)
111
+ declarative (< 0.1.0)
112
+ declarative-option (< 0.2.0)
113
+ uber (< 0.2.0)
114
+ retriable (3.1.1)
111
115
  rly (0.2.3)
112
116
  rubocop (0.35.1)
113
117
  astrolabe (~> 1.3)
@@ -116,18 +120,18 @@ GEM
116
120
  rainbow (>= 1.99.1, < 3.0)
117
121
  ruby-progressbar (~> 1.7)
118
122
  tins (<= 1.6.0)
119
- ruby-progressbar (1.8.3)
123
+ ruby-progressbar (1.9.0)
120
124
  ruby_dig (0.0.2)
121
125
  safe_yaml (1.0.4)
122
126
  serverengine (2.0.5)
123
127
  sigdump (~> 0.2.2)
124
128
  sigdump (0.2.4)
125
- signet (0.7.3)
129
+ signet (0.8.1)
126
130
  addressable (~> 2.3)
127
131
  faraday (~> 0.9)
128
- jwt (~> 1.5)
132
+ jwt (>= 1.5, < 3.0)
129
133
  multi_json (~> 1.10)
130
- stackdriver-core (0.21.0)
134
+ stackdriver-core (1.2.0)
131
135
  strptime (0.1.9)
132
136
  test-unit (3.2.6)
133
137
  power_assert
@@ -137,7 +141,7 @@ GEM
137
141
  thread_safe (~> 0.1)
138
142
  tzinfo-data (1.2017.2)
139
143
  tzinfo (>= 1.0.0)
140
- uber (0.0.15)
144
+ uber (0.1.0)
141
145
  webmock (2.3.2)
142
146
  addressable (>= 2.3.6)
143
147
  crack (>= 0.3.2)
@@ -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.8'
13
+ gem.version = '0.6.9.pre.1'
14
14
  gem.authors = ['Todd Derr', 'Alex Robinson']
15
15
  gem.email = ['salty@google.com']
16
16
  gem.required_ruby_version = Gem::Requirement.new('>= 2.0')
@@ -21,8 +21,8 @@ eos
21
21
 
22
22
  gem.add_runtime_dependency 'fluentd', '~> 0.10'
23
23
  gem.add_runtime_dependency 'googleapis-common-protos', '~> 1.3'
24
- gem.add_runtime_dependency 'google-api-client', '~> 0.9.0'
25
- gem.add_runtime_dependency 'google-cloud-logging', '0.24.1'
24
+ gem.add_runtime_dependency 'google-api-client', '~> 0.14'
25
+ gem.add_runtime_dependency 'google-cloud-logging', '~> 1.2', '>= 1.2.3'
26
26
  gem.add_runtime_dependency 'googleauth', '~> 0.4', '< 0.5.2'
27
27
  gem.add_runtime_dependency 'grpc', '~> 1.0', '< 1.3'
28
28
  gem.add_runtime_dependency 'json', '~> 1.8'
@@ -11,6 +11,7 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+ require 'erb'
14
15
  require 'grpc'
15
16
  require 'json'
16
17
  require 'open-uri'
@@ -18,7 +19,7 @@ require 'socket'
18
19
  require 'time'
19
20
  require 'yaml'
20
21
  require 'google/apis'
21
- require 'google/apis/logging_v2beta1'
22
+ require 'google/apis/logging_v2'
22
23
  require 'google/logging/v2/logging_pb'
23
24
  require 'google/logging/v2/logging_services_pb'
24
25
  require 'google/logging/v2/log_entry_pb'
@@ -67,7 +68,7 @@ module Fluent
67
68
  DATAFLOW_CONSTANTS = {
68
69
  service: 'dataflow.googleapis.com',
69
70
  resource_type: 'dataflow_step',
70
- extra_common_labels: %w(region job_name job_id step_id)
71
+ extra_resource_labels: %w(region job_name job_id step_id)
71
72
  }
72
73
  DATAPROC_CONSTANTS = {
73
74
  service: 'cluster.dataproc.googleapis.com',
@@ -81,7 +82,7 @@ module Fluent
81
82
  ML_CONSTANTS = {
82
83
  service: 'ml.googleapis.com',
83
84
  resource_type: 'ml_job',
84
- extra_common_labels: %w(job_id task_name)
85
+ extra_resource_labels: %w(job_id task_name)
85
86
  }
86
87
 
87
88
  # The map between a subservice name and a resource type.
@@ -112,7 +113,7 @@ module Fluent
112
113
  'http://local-metadata-agent.stackdriver.com:8000'
113
114
  end
114
115
 
115
- # Constants for log entry field extraction.
116
+ # Internal constants.
116
117
  module InternalConstants
117
118
  # The label name of local_resource_id in the json payload. When a record
118
119
  # has this field in the payload, we will use the value to retrieve
@@ -144,7 +145,7 @@ module Fluent
144
145
  # The grpc version class name.
145
146
  'Google::Logging::Type::HttpRequest',
146
147
  # The non-grpc version class name.
147
- 'Google::Apis::LoggingV2beta1::HttpRequest'
148
+ 'Google::Apis::LoggingV2::HttpRequest'
148
149
  ],
149
150
  'source_location' => [
150
151
  '@source_location_key',
@@ -154,7 +155,7 @@ module Fluent
154
155
  %w(line line parse_int)
155
156
  ],
156
157
  'Google::Logging::V2::LogEntrySourceLocation',
157
- 'Google::Apis::LoggingV2beta1::LogEntrySourceLocation'
158
+ 'Google::Apis::LoggingV2::LogEntrySourceLocation'
158
159
  ],
159
160
  'operation' => [
160
161
  '@operation_key',
@@ -165,9 +166,13 @@ module Fluent
165
166
  %w(last last parse_bool)
166
167
  ],
167
168
  'Google::Logging::V2::LogEntryOperation',
168
- 'Google::Apis::LoggingV2beta1::LogEntryOperation'
169
+ 'Google::Apis::LoggingV2::LogEntryOperation'
169
170
  ]
170
171
  }
172
+
173
+ # The name of the WriteLogEntriesPartialErrors field in the error details.
174
+ PARTIAL_ERROR_FIELD =
175
+ 'type.googleapis.com/google.logging.v2.WriteLogEntriesPartialErrors'
171
176
  end
172
177
 
173
178
  include self::ServiceConstants
@@ -177,7 +182,7 @@ module Fluent
177
182
  Fluent::Plugin.register_output('google_cloud', self)
178
183
 
179
184
  PLUGIN_NAME = 'Fluentd Google Cloud Logging plugin'
180
- PLUGIN_VERSION = '0.6.8'
185
+ PLUGIN_VERSION = '0.6.9.pre.1'
181
186
 
182
187
  # Name of the the Google cloud logging write scope.
183
188
  LOGGING_SCOPE = 'https://www.googleapis.com/auth/logging.write'
@@ -280,6 +285,12 @@ module Fluent
280
285
  # Cloud Logging API.
281
286
  config_param :use_grpc, :bool, :default => false
282
287
 
288
+ # Whether valid entries should be written even if some other entries fail
289
+ # due to INVALID_ARGUMENT or PERMISSION_DENIED errors when communicating to
290
+ # the Cloud Logging API. This is highly recommended. Right now this only
291
+ # works with the REST path (use_grpc = false).
292
+ config_param :partial_success, :bool, :default => false
293
+
283
294
  # Whether to allow non-UTF-8 characters in user logs. If set to true, any
284
295
  # non-UTF-8 character would be replaced by the string specified by
285
296
  # 'non_utf8_replacement_string'. If set to false, any non-UTF-8 character
@@ -338,6 +349,15 @@ module Fluent
338
349
  def configure(conf)
339
350
  super
340
351
 
352
+ # TODO(qingling128): Remove this warning after the support is added. Also
353
+ # remove the comment in the description of this configuration.
354
+ if @partial_success && @use_grpc
355
+ @log.warn 'Detected partial_success enabled while use_grpc is also' \
356
+ ' enabled. The support for partial success in the gRPC path' \
357
+ ' is to be added in the near future. For now the ' \
358
+ ' partial_success flag will be ignored.'
359
+ end
360
+
341
361
  # If monitoring is enabled, register metrics in the default registry
342
362
  # and store metric objects for future use.
343
363
  if @enable_monitoring
@@ -519,7 +539,7 @@ module Fluent
519
539
  # Remove the labels if we didn't populate them with anything.
520
540
  entry_level_resource.labels = nil if
521
541
  entry_level_resource.labels.empty?
522
- entry = Google::Apis::LoggingV2beta1::LogEntry.new(
542
+ entry = Google::Apis::LoggingV2::LogEntry.new(
523
543
  labels: entry_level_common_labels,
524
544
  resource: entry_level_resource,
525
545
  severity: severity,
@@ -622,20 +642,24 @@ module Fluent
622
642
  else
623
643
  begin
624
644
  write_request = \
625
- Google::Apis::LoggingV2beta1::WriteLogEntriesRequest.new(
645
+ Google::Apis::LoggingV2::WriteLogEntriesRequest.new(
626
646
  log_name: log_name,
627
647
  resource: group_level_resource,
628
648
  labels: group_level_common_labels,
649
+ partial_success: @partial_success,
629
650
  entries: entries)
630
651
  entries_count = entries.length
631
652
 
632
- # TODO: RequestOptions
633
653
  begin
634
- client.write_entry_log_entries(write_request)
654
+ client.write_entry_log_entries(
655
+ write_request,
656
+ options: { api_format_version: '2' }
657
+ )
635
658
  rescue Google::Apis::Error => error
636
659
  increment_failed_requests_count(error.status_code)
637
660
  raise error
638
661
  end
662
+
639
663
  increment_successful_requests_count
640
664
  increment_ingested_entries_count(entries_count)
641
665
 
@@ -664,9 +688,20 @@ module Fluent
664
688
  rescue Google::Apis::ClientError => error
665
689
  # Most ClientErrors indicate a problem with the request itself and
666
690
  # should not be retried.
667
- increment_dropped_entries_count(entries_count)
668
- @log.warn "Dropping #{entries_count} log message(s)",
669
- error_class: error.class.to_s, error: error.to_s
691
+ error_details_map = construct_error_details_map(error)
692
+ if error_details_map.empty?
693
+ increment_dropped_entries_count(entries_count)
694
+ @log.warn "Dropping #{entries_count} log message(s)",
695
+ error_class: error.class.to_s, error: error.to_s
696
+ else
697
+ error_details_map.each do |(error_code, error_message), indexes|
698
+ partial_error_count = indexes.length
699
+ increment_dropped_entries_count(partial_error_count)
700
+ @log.warn "Dropping #{partial_error_count} log message(s)",
701
+ error_code: "google.rpc.Code[#{error_code}]",
702
+ error: error_message
703
+ end
704
+ end
670
705
  end
671
706
  end
672
707
  end
@@ -836,7 +871,7 @@ module Fluent
836
871
  # Metadata Agent. Thus it should be equivalent to what Metadata Agent
837
872
  # returns.
838
873
  def determine_agent_level_monitored_resource_via_legacy
839
- resource = Google::Apis::LoggingV2beta1::MonitoredResource.new(
874
+ resource = Google::Apis::LoggingV2::MonitoredResource.new(
840
875
  labels: {})
841
876
  resource.type = determine_agent_level_monitored_resource_type
842
877
  resource.labels = determine_agent_level_monitored_resource_labels(
@@ -1090,6 +1125,18 @@ module Fluent
1090
1125
  common_labels.delete("#{COMPUTE_CONSTANTS[:service]}/resource_name")
1091
1126
  end
1092
1127
 
1128
+ # Cloud Dataflow and Cloud ML.
1129
+ # These labels can be set via the 'labels' option.
1130
+ # Report them as monitored resource labels instead of common labels.
1131
+ # e.g. "dataflow.googleapis.com/job_id" => "job_id"
1132
+ [DATAFLOW_CONSTANTS, ML_CONSTANTS].each do |service_constants|
1133
+ next unless resource.type == service_constants[:resource_type]
1134
+ resource.labels.merge!(
1135
+ delete_and_extract_labels(
1136
+ common_labels, service_constants[:extra_resource_labels]
1137
+ .map { |l| ["#{service_constants[:service]}/#{l}", l] }.to_h))
1138
+ end
1139
+
1093
1140
  resource.freeze
1094
1141
  resource.labels.freeze
1095
1142
  common_labels.freeze
@@ -1157,14 +1204,14 @@ module Fluent
1157
1204
  common_labels.merge!(delete_and_extract_labels(record, @label_map))
1158
1205
 
1159
1206
  # Cloud Dataflow and Cloud ML.
1160
- # These labels can be set via configuring 'labels' or 'label_map'.
1207
+ # These labels can be set via the 'labels' or 'label_map' options.
1161
1208
  # Report them as monitored resource labels instead of common labels.
1162
1209
  # e.g. "dataflow.googleapis.com/job_id" => "job_id"
1163
1210
  [DATAFLOW_CONSTANTS, ML_CONSTANTS].each do |service_constants|
1164
1211
  next unless resource.type == service_constants[:resource_type]
1165
1212
  resource.labels.merge!(
1166
1213
  delete_and_extract_labels(
1167
- common_labels, service_constants[:extra_common_labels]
1214
+ common_labels, service_constants[:extra_resource_labels]
1168
1215
  .map { |l| ["#{service_constants[:service]}/#{l}", l] }.to_h))
1169
1216
  end
1170
1217
 
@@ -1187,7 +1234,7 @@ module Fluent
1187
1234
  # TODO(qingling128): Use Google::Api::MonitoredResource directly after we
1188
1235
  # upgrade gRPC version to include the fix for the protobuf map
1189
1236
  # corruption issue.
1190
- Google::Apis::LoggingV2beta1::MonitoredResource.new(
1237
+ Google::Apis::LoggingV2::MonitoredResource.new(
1191
1238
  type: resource.type,
1192
1239
  labels: resource.labels.to_h
1193
1240
  )
@@ -1658,7 +1705,7 @@ module Fluent
1658
1705
  # TODO: Use a non-default ClientOptions object.
1659
1706
  Google::Apis::ClientOptions.default.application_name = PLUGIN_NAME
1660
1707
  Google::Apis::ClientOptions.default.application_version = PLUGIN_VERSION
1661
- @client = Google::Apis::LoggingV2beta1::LoggingService.new
1708
+ @client = Google::Apis::LoggingV2::LoggingService.new
1662
1709
  @client.authorization = Google::Auth.get_application_default(
1663
1710
  LOGGING_SCOPE)
1664
1711
  end
@@ -1710,6 +1757,118 @@ module Fluent
1710
1757
  end
1711
1758
  end
1712
1759
 
1760
+ # Extract a map of error details from an potentially partially successful
1761
+ # request. Return an empty map if @partial_success is not enabled.
1762
+ #
1763
+ # The keys in this map are [error_code, error_message] pairs, and the values
1764
+ # are a list of stringified indexes of log entries that failed due to this
1765
+ # error.
1766
+ #
1767
+ # A sample error.body looks like:
1768
+ # {
1769
+ # "error": {
1770
+ # "code": 403,
1771
+ # "message": "User not authorized.",
1772
+ # "status": "PERMISSION_DENIED",
1773
+ # "details": [
1774
+ # {
1775
+ # "@type": "type.googleapis.com/google.logging.v2.WriteLogEntriesPar
1776
+ # tialErrors",
1777
+ # "logEntryErrors": {
1778
+ # "0": {
1779
+ # "code": 7,
1780
+ # "message": "User not authorized."
1781
+ # },
1782
+ # "1": {
1783
+ # "code": 3,
1784
+ # "message": "Log name contains illegal character :"
1785
+ # },
1786
+ # "3": {
1787
+ # "code": 3,
1788
+ # "message": "Log name contains illegal character :"
1789
+ # }
1790
+ # }
1791
+ # },
1792
+ # {
1793
+ # "@type": "type.googleapis.com/google.rpc.DebugInfo",
1794
+ # "detail": ...
1795
+ # }
1796
+ # ]
1797
+ # }
1798
+ # }
1799
+ #
1800
+ # The root level "code", "message", and "status" simply match the root
1801
+ # cause of the first failed log entry. For example, if we switched the order
1802
+ # of the log entries, then we would get:
1803
+ # {
1804
+ # "error" : {
1805
+ # "code" : 400,
1806
+ # "message" : "Log name contains illegal character :",
1807
+ # "status" : "INVALID_ARGUMENT",
1808
+ # "details": ...
1809
+ # }
1810
+ # }
1811
+ # We will ignore it anyway and look at the details instead which includes
1812
+ # info for all failed log entries.
1813
+ #
1814
+ # In this example, the logEntryErrors that we care are:
1815
+ # {
1816
+ # "0": {
1817
+ # "code": 7,
1818
+ # "message": "User not authorized."
1819
+ # },
1820
+ # "1": {
1821
+ # "code": 3,
1822
+ # "message": "Log name contains illegal character :"
1823
+ # },
1824
+ # "3": {
1825
+ # "code": 3,
1826
+ # "message": "Log name contains illegal character :"
1827
+ # }
1828
+ # }
1829
+ #
1830
+ # The ultimate map that is constructed is:
1831
+ # {
1832
+ # [7, 'User not authorized.']: ['0'],
1833
+ # [3, 'Log name contains illegal character :']: ['1', '3']
1834
+ # }
1835
+ def construct_error_details_map(error)
1836
+ return {} unless @partial_success
1837
+ error_details_map = Hash.new { |h, k| h[k] = [] }
1838
+
1839
+ error_details = ensure_array(
1840
+ ensure_hash(ensure_hash(JSON.parse(error.body))['error'])['details'])
1841
+ partial_errors = error_details.detect(
1842
+ -> { fail JSON::ParserError, "No type #{PARTIAL_ERROR_FIELD}." }
1843
+ ) do |error_detail|
1844
+ ensure_hash(error_detail)['@type'] == PARTIAL_ERROR_FIELD
1845
+ end
1846
+ log_entry_errors = ensure_hash(
1847
+ ensure_hash(partial_errors)['logEntryErrors'])
1848
+ log_entry_errors.each do |index, log_entry_error|
1849
+ error_hash = ensure_hash(log_entry_error)
1850
+ fail JSON::ParserError,
1851
+ "Entry #{index} is missing 'code' or 'message'." unless
1852
+ error_hash['code'] && error_hash['message']
1853
+ error_key = [error_hash['code'], error_hash['message']].freeze
1854
+ # TODO(qingling128): Convert indexes to integers.
1855
+ error_details_map[error_key] << index
1856
+ end
1857
+ error_details_map
1858
+ rescue JSON::ParserError => e
1859
+ @log.warn 'Failed to extract log entry errors from the error details:' \
1860
+ " #{error.body}.", error: e
1861
+ {}
1862
+ end
1863
+
1864
+ def ensure_array(value)
1865
+ Array.try_convert(value) || (fail JSON::ParserError, "#{value.class}")
1866
+ end
1867
+
1868
+ def ensure_hash(value)
1869
+ Hash.try_convert(value) || (fail JSON::ParserError, "#{value.class}")
1870
+ end
1871
+
1713
1872
  # Increment the metric for the number of successful requests.
1714
1873
  def increment_successful_requests_count
1715
1874
  return unless @successful_requests_count
@@ -1748,7 +1907,7 @@ end
1748
1907
 
1749
1908
  module Google
1750
1909
  module Apis
1751
- module LoggingV2beta1
1910
+ module LoggingV2
1752
1911
  # Override MonitoredResource::dup to make a deep copy.
1753
1912
  class MonitoredResource
1754
1913
  def dup
@@ -93,6 +93,18 @@ module BaseTest
93
93
  end
94
94
  end
95
95
 
96
+ def test_configure_partial_success
97
+ setup_gce_metadata_stubs
98
+ {
99
+ APPLICATION_DEFAULT_CONFIG => false,
100
+ PARTIAL_SUCCESS_CONFIG => true
101
+ }.each do |(config, partial_success)|
102
+ d = create_driver(config)
103
+ assert_equal partial_success,
104
+ d.instance.instance_variable_get(:@partial_success)
105
+ end
106
+ end
107
+
96
108
  def test_metadata_loading
97
109
  setup_gce_metadata_stubs
98
110
  d = create_driver
@@ -961,6 +973,26 @@ module BaseTest
961
973
  verify_log_entries(1, DATAPROC_PARAMS, 'jsonPayload')
962
974
  end
963
975
 
976
+ def test_cloud_ml_log
977
+ setup_gce_metadata_stubs
978
+ setup_logging_stubs do
979
+ d = create_driver(CONFIG_ML, ML_TAG)
980
+ d.emit(ml_log_entry(0))
981
+ d.run
982
+ end
983
+ verify_log_entries(1, ML_PARAMS)
984
+ end
985
+
986
+ def test_cloud_dataflow_log
987
+ setup_gce_metadata_stubs
988
+ setup_logging_stubs do
989
+ d = create_driver(CONFIG_DATAFLOW, DATAFLOW_TAG)
990
+ d.emit(dataflow_log_entry(0))
991
+ d.run
992
+ end
993
+ verify_log_entries(1, DATAFLOW_PARAMS)
994
+ end
995
+
964
996
  def test_log_entry_http_request_field_from_record
965
997
  verify_subfields_from_record(DEFAULT_HTTP_REQUEST_KEY)
966
998
  end
@@ -1023,11 +1055,11 @@ module BaseTest
1023
1055
  setup_logging_stubs do
1024
1056
  d = create_driver
1025
1057
  @logs_sent = []
1026
- d.emit('httpRequest' => HTTP_REQUEST_MESSAGE.merge('latency' => input))
1058
+ d.emit('httpRequest' => http_request_message.merge('latency' => input))
1027
1059
  d.run
1028
1060
  end
1029
1061
  verify_log_entries(1, COMPUTE_PARAMS, 'httpRequest') do |entry|
1030
- assert_equal HTTP_REQUEST_MESSAGE.merge('latency' => expected),
1062
+ assert_equal http_request_message.merge('latency' => expected),
1031
1063
  entry['httpRequest'], entry
1032
1064
  assert_nil get_fields(entry['jsonPayload'])['httpRequest'], entry
1033
1065
  end
@@ -1044,11 +1076,11 @@ module BaseTest
1044
1076
  setup_logging_stubs do
1045
1077
  d = create_driver
1046
1078
  @logs_sent = []
1047
- d.emit('httpRequest' => HTTP_REQUEST_MESSAGE.merge('latency' => input))
1079
+ d.emit('httpRequest' => http_request_message.merge('latency' => input))
1048
1080
  d.run
1049
1081
  end
1050
1082
  verify_log_entries(1, COMPUTE_PARAMS, 'httpRequest') do |entry|
1051
- assert_equal HTTP_REQUEST_MESSAGE, entry['httpRequest'], entry
1083
+ assert_equal http_request_message, entry['httpRequest'], entry
1052
1084
  assert_nil get_fields(entry['jsonPayload'])['httpRequest'], entry
1053
1085
  end
1054
1086
  end
@@ -1597,8 +1629,22 @@ module BaseTest
1597
1629
  end
1598
1630
  end
1599
1631
 
1632
+ def log_entry_subfields_params
1633
+ {
1634
+ # The keys are the names of fields in the payload that we are extracting
1635
+ # LogEntry info from. The values are lists of two elements: the name of
1636
+ # the subfield in LogEntry object and the expected value of that field.
1637
+ DEFAULT_HTTP_REQUEST_KEY => [
1638
+ 'httpRequest', http_request_message],
1639
+ DEFAULT_SOURCE_LOCATION_KEY => [
1640
+ 'sourceLocation', source_location_message],
1641
+ DEFAULT_OPERATION_KEY => [
1642
+ 'operation', OPERATION_MESSAGE]
1643
+ }
1644
+ end
1645
+
1600
1646
  def verify_subfields_from_record(payload_key)
1601
- destination_key, payload_value = LOG_ENTRY_SUBFIELDS_PARAMS[payload_key]
1647
+ destination_key, payload_value = log_entry_subfields_params[payload_key]
1602
1648
  @logs_sent = []
1603
1649
  setup_gce_metadata_stubs
1604
1650
  setup_logging_stubs do
@@ -1614,7 +1660,7 @@ module BaseTest
1614
1660
  end
1615
1661
 
1616
1662
  def verify_subfields_partial_from_record(payload_key)
1617
- destination_key, payload_value = LOG_ENTRY_SUBFIELDS_PARAMS[payload_key]
1663
+ destination_key, payload_value = log_entry_subfields_params[payload_key]
1618
1664
  @logs_sent = []
1619
1665
  setup_gce_metadata_stubs
1620
1666
  setup_logging_stubs do
@@ -1631,7 +1677,7 @@ module BaseTest
1631
1677
  end
1632
1678
 
1633
1679
  def verify_subfields_when_not_hash(payload_key)
1634
- destination_key = LOG_ENTRY_SUBFIELDS_PARAMS[payload_key][0]
1680
+ destination_key = log_entry_subfields_params[payload_key][0]
1635
1681
  @logs_sent = []
1636
1682
  setup_gce_metadata_stubs
1637
1683
  setup_logging_stubs do
@@ -1646,14 +1692,22 @@ module BaseTest
1646
1692
  end
1647
1693
  end
1648
1694
 
1695
+ def http_request_message
1696
+ HTTP_REQUEST_MESSAGE
1697
+ end
1698
+
1699
+ def source_location_message
1700
+ SOURCE_LOCATION_MESSAGE
1701
+ end
1702
+
1649
1703
  # Replace the 'referer' field with nil.
1650
1704
  def http_request_message_with_nil_referer
1651
- HTTP_REQUEST_MESSAGE.merge('referer' => nil)
1705
+ http_request_message.merge('referer' => nil)
1652
1706
  end
1653
1707
 
1654
1708
  # Unset the 'referer' field.
1655
1709
  def http_request_message_with_absent_referer
1656
- HTTP_REQUEST_MESSAGE.reject do |k, _|
1710
+ http_request_message.reject do |k, _|
1657
1711
  k == 'referer'
1658
1712
  end
1659
1713
  end
@@ -97,7 +97,7 @@ module Constants
97
97
  DATAFLOW_JOB_NAME = 'job_name_1'
98
98
  DATAFLOW_JOB_ID = 'job_id_1'
99
99
  DATAFLOW_STEP_ID = 'step_1'
100
- DATAFLOW_TAG = 'dataflow.googleapis.com/worker'
100
+ DATAFLOW_TAG = 'dataflow-worker'
101
101
 
102
102
  # Dataproc specific labels.
103
103
  DATAPROC_CLUSTER_NAME = 'test-cluster'
@@ -140,6 +140,10 @@ module Constants
140
140
  detect_json true
141
141
  )
142
142
 
143
+ PARTIAL_SUCCESS_CONFIG = %(
144
+ partial_success true
145
+ )
146
+
143
147
  # rubocop:disable Metrics/LineLength
144
148
  PRIVATE_KEY_CONFIG = %(
145
149
  auth_method private_key
@@ -533,13 +537,6 @@ module Constants
533
537
  'last' => true
534
538
  }
535
539
 
536
- LOG_ENTRY_SUBFIELDS_PARAMS = {
537
- # payload key, destination key, payload value
538
- DEFAULT_HTTP_REQUEST_KEY => ['httpRequest', HTTP_REQUEST_MESSAGE],
539
- DEFAULT_SOURCE_LOCATION_KEY => ['sourceLocation', SOURCE_LOCATION_MESSAGE],
540
- DEFAULT_OPERATION_KEY => ['operation', OPERATION_MESSAGE]
541
- }
542
-
543
540
  CUSTOM_LABELS_MESSAGE = {
544
541
  'customKey' => 'value'
545
542
  }
@@ -605,4 +602,43 @@ module Constants
605
602
  }
606
603
  }.to_json
607
604
  }
605
+
606
+ PARTIAL_SUCCESS_RESPONSE_BODY = {
607
+ 'error' => {
608
+ 'code' => 403,
609
+ 'message' => 'User not authorized.',
610
+ 'status' => 'PERMISSION_DENIED',
611
+ 'details' => [
612
+ {
613
+ '@type' => 'type.googleapis.com/google.logging.v2.WriteLogEntriesPa' \
614
+ 'rtialErrors',
615
+ 'logEntryErrors' => {
616
+ '0' => {
617
+ 'code' => 7,
618
+ 'message' => 'User not authorized.'
619
+ },
620
+ '1' => {
621
+ 'code' => 3,
622
+ 'message' => 'Log name contains illegal character :'
623
+ },
624
+ '2' => {
625
+ 'code' => 3,
626
+ 'message' => 'Log name contains illegal character :'
627
+ }
628
+ }
629
+ },
630
+ {
631
+ '@type' => 'type.googleapis.com/google.rpc.DebugInfo',
632
+ 'detail' => '[ORIGINAL ERROR] generic::permission_denied: User not ' \
633
+ 'authorized. [google.rpc.error_details_ext] { message: \"User not' \
634
+ ' authorized.\" details { type_url: \"type.googleapis.com/google.' \
635
+ 'logging.v2.WriteLogEntriesPartialErrors\" value: \"\\n\\034\\010' \
636
+ '\\000\\022\\030\\010\\007\\022\\024User not authorized.\\n-\\010' \
637
+ '\\001\\022)\\010\\003\\022%Log name contains illegal character :' \
638
+ '\\n-\\010\\002\\022)\\010\\003\\022%Log name contains illegal ch' \
639
+ 'aracter :\" } }'
640
+ }
641
+ ]
642
+ }
643
+ }.to_json
608
644
  end
@@ -51,6 +51,28 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
51
51
  assert_requested(:post, WRITE_LOG_ENTRIES_URI, times: 2)
52
52
  end
53
53
 
54
+ def test_partial_success
55
+ setup_gce_metadata_stubs
56
+ {
57
+ APPLICATION_DEFAULT_CONFIG => 4.0,
58
+ PARTIAL_SUCCESS_CONFIG => 3.0
59
+ }.each do |config, failed_entry_count|
60
+ setup_prometheus
61
+ # The API Client should not retry this and the plugin should consume
62
+ # the exception.
63
+ stub_request(:post, WRITE_LOG_ENTRIES_URI)
64
+ .to_return(status: 400, body: PARTIAL_SUCCESS_RESPONSE_BODY)
65
+ d = create_driver(PROMETHEUS_ENABLE_CONFIG + config)
66
+ 4.times do |i|
67
+ d.emit('message' => log_entry(i.to_s))
68
+ end
69
+ d.run
70
+ assert_prometheus_metric_value(:stackdriver_dropped_entries_count,
71
+ failed_entry_count)
72
+ end
73
+ assert_requested(:post, WRITE_LOG_ENTRIES_URI, times: 2)
74
+ end
75
+
54
76
  def test_server_error
55
77
  setup_gce_metadata_stubs
56
78
  # The API client should retry this once, then throw an exception which
@@ -251,7 +273,7 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
251
273
 
252
274
  private
253
275
 
254
- WRITE_LOG_ENTRIES_URI = 'https://logging.googleapis.com/v2beta1/entries:write'
276
+ WRITE_LOG_ENTRIES_URI = 'https://logging.googleapis.com/v2/entries:write'
255
277
 
256
278
  def rename_key(hash, old_key, new_key)
257
279
  hash.merge(new_key => hash[old_key]).reject { |k, _| k == old_key }
@@ -316,4 +338,25 @@ class GoogleCloudOutputTest < Test::Unit::TestCase
316
338
  def null_value
317
339
  nil
318
340
  end
341
+
342
+ # 'responseSize' and 'requestSize' are Integers in the gRPC proto, yet Strings
343
+ # in REST API client.
344
+ # TODO(qingling128): Address this accordingly once the following question is
345
+ # answered: https://github.com/google/google-api-ruby-client/issues/619.
346
+ # If this discrepancy is legit, add some comments to explain the reason.
347
+ # Otherwise once the discrepancy is fixed, we need to upgrade to that version
348
+ # and change our tests accordingly.
349
+ def http_request_message
350
+ HTTP_REQUEST_MESSAGE.merge(
351
+ 'responseSize' => HTTP_REQUEST_MESSAGE['responseSize'].to_s,
352
+ 'requestSize' => HTTP_REQUEST_MESSAGE['requestSize'].to_s
353
+ )
354
+ end
355
+
356
+ # 'line' is an Integer in the gRPC proto, yet a String in the REST API client.
357
+ def source_location_message
358
+ SOURCE_LOCATION_MESSAGE.merge(
359
+ 'line' => SOURCE_LOCATION_MESSAGE['line'].to_s
360
+ )
361
+ end
319
362
  end
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.8
4
+ version: 0.6.9.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Todd Derr
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-09-22 00:00:00.000000000 Z
12
+ date: 2017-10-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fluentd
@@ -45,28 +45,34 @@ dependencies:
45
45
  requirements:
46
46
  - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: 0.9.0
48
+ version: '0.14'
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
- version: 0.9.0
55
+ version: '0.14'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: google-cloud-logging
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - '='
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '1.2'
63
+ - - ">="
61
64
  - !ruby/object:Gem::Version
62
- version: 0.24.1
65
+ version: 1.2.3
63
66
  type: :runtime
64
67
  prerelease: false
65
68
  version_requirements: !ruby/object:Gem::Requirement
66
69
  requirements:
67
- - - '='
70
+ - - "~>"
68
71
  - !ruby/object:Gem::Version
69
- version: 0.24.1
72
+ version: '1.2'
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 1.2.3
70
76
  - !ruby/object:Gem::Dependency
71
77
  name: googleauth
72
78
  requirement: !ruby/object:Gem::Requirement
@@ -249,9 +255,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
249
255
  version: '2.0'
250
256
  required_rubygems_version: !ruby/object:Gem::Requirement
251
257
  requirements:
252
- - - ">="
258
+ - - ">"
253
259
  - !ruby/object:Gem::Version
254
- version: '0'
260
+ version: 1.3.1
255
261
  requirements: []
256
262
  rubyforge_project:
257
263
  rubygems_version: 2.4.8