vmik-fluent-plugin-google-cloud 0.5.5.alpha1

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.
@@ -0,0 +1,381 @@
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'grpc'
16
+
17
+ require_relative 'base_test'
18
+
19
+ # Unit tests for Google Cloud Logging plugin
20
+ class GoogleCloudOutputGRPCTest < Test::Unit::TestCase
21
+ include BaseTest
22
+
23
+ def test_configure_use_grpc
24
+ setup_gce_metadata_stubs
25
+ d = create_driver
26
+ assert_true d.instance.instance_variable_get(:@use_grpc)
27
+ end
28
+
29
+ def test_client_error
30
+ setup_gce_metadata_stubs
31
+ { 8 => 'ResourceExhausted',
32
+ 12 => 'Unimplemented',
33
+ 16 => 'Unauthenticated' }.each_with_index do |(code, message), index|
34
+ setup_logging_stubs(nil, true, code, message) do
35
+ d = create_driver(USE_GRPC_CONFIG, 'test',
36
+ GRPCLoggingMockFailingService.rpc_stub_class)
37
+ # The API Client should not retry this and the plugin should consume the
38
+ # exception.
39
+ d.emit('message' => log_entry(0))
40
+ d.run
41
+ end
42
+ assert_equal 1, @failed_attempts.size, "Index #{index} failed."
43
+ end
44
+ end
45
+
46
+ def test_server_error
47
+ setup_gce_metadata_stubs
48
+ { 1 => 'Cancelled',
49
+ 2 => 'Unknown',
50
+ 4 => 'DeadlineExceeded',
51
+ 13 => 'Internal',
52
+ 14 => 'Unavailable' }.each_with_index do |(code, message), index|
53
+ exception_count = 0
54
+ setup_logging_stubs(nil, true, code, message) do
55
+ d = create_driver(USE_GRPC_CONFIG, 'test',
56
+ GRPCLoggingMockFailingService.rpc_stub_class)
57
+ # The API client should retry this once, then throw an exception which
58
+ # gets propagated through the plugin
59
+ d.emit('message' => log_entry(0))
60
+ begin
61
+ d.run
62
+ rescue GRPC::Cancelled
63
+ # No need to check the message -- we already know the code.
64
+ exception_count += 1
65
+ rescue GRPC::BadStatus => error
66
+ assert_equal "#{code}:#{message}", error.message
67
+ exception_count += 1
68
+ end
69
+ end
70
+ assert_equal 1, @failed_attempts.size, "Index #{index} failed."
71
+ assert_equal 1, exception_count, "Index #{index} failed."
72
+ end
73
+ end
74
+
75
+ def test_http_request_from_record_with_referer_nil
76
+ setup_gce_metadata_stubs
77
+ setup_logging_stubs do
78
+ d = create_driver
79
+ d.emit('httpRequest' => http_request_message_with_nil_referer)
80
+ d.run
81
+ end
82
+ verify_log_entries(1, COMPUTE_PARAMS, 'httpRequest') do |entry|
83
+ assert_equal http_request_message_with_absent_referer,
84
+ entry['httpRequest'], entry
85
+ assert_nil get_fields(entry['structPayload'])['httpRequest'], entry
86
+ end
87
+ end
88
+
89
+ def test_http_request_from_record_with_referer_absent
90
+ setup_gce_metadata_stubs
91
+ setup_logging_stubs do
92
+ d = create_driver
93
+ d.emit('httpRequest' => http_request_message_with_absent_referer)
94
+ d.run
95
+ end
96
+ verify_log_entries(1, COMPUTE_PARAMS, 'httpRequest') do |entry|
97
+ assert_equal http_request_message_with_absent_referer,
98
+ entry['httpRequest'], entry
99
+ assert_nil get_fields(entry['structPayload'])['httpRequest'], entry
100
+ end
101
+ end
102
+
103
+ # This test looks similar between the grpc and non-grpc paths except that when
104
+ # parsing "105", the grpc path responds with "DEBUG", while the non-grpc path
105
+ # responds with "100".
106
+ #
107
+ # TODO(lingshi) consolidate the tests between the grpc path and the non-grpc
108
+ # path, or at least split into two tests, one with string severities and one
109
+ # with numeric severities.
110
+ def test_severities
111
+ setup_gce_metadata_stubs
112
+ expected_severity = []
113
+ emit_index = 0
114
+ setup_logging_stubs do
115
+ d = create_driver
116
+ # Array of pairs of [parsed_severity, expected_severity]
117
+ [%w(INFO INFO), %w(warn WARNING), %w(E ERROR), %w(BLAH DEFAULT),
118
+ %w(105 DEBUG), ['', 'DEFAULT']].each do |sev|
119
+ d.emit('message' => log_entry(emit_index), 'severity' => sev[0])
120
+ expected_severity.push(sev[1])
121
+ emit_index += 1
122
+ end
123
+ d.run
124
+ end
125
+ verify_index = 0
126
+ verify_log_entries(emit_index, COMPUTE_PARAMS) do |entry|
127
+ assert_equal_with_default(entry['metadata']['severity'],
128
+ expected_severity[verify_index],
129
+ 'DEFAULT', entry)
130
+ verify_index += 1
131
+ end
132
+ end
133
+
134
+ def test_struct_payload_non_utf8_log
135
+ setup_gce_metadata_stubs
136
+ setup_logging_stubs do
137
+ d = create_driver
138
+ d.emit('msg' => log_entry(0),
139
+ 'normal_key' => "test#{non_utf8_character}non utf8",
140
+ "non_utf8#{non_utf8_character}key" => 5000,
141
+ 'nested_struct' => { "non_utf8#{non_utf8_character}key" => \
142
+ "test#{non_utf8_character}non utf8" },
143
+ 'null_field' => nil)
144
+ d.run
145
+ end
146
+ verify_log_entries(1, COMPUTE_PARAMS, 'structPayload') do |entry|
147
+ fields = get_fields(entry['structPayload'])
148
+ assert_equal 5, fields.size, entry
149
+ assert_equal 'test log entry 0', get_string(fields['msg']), entry
150
+ assert_equal 'test non utf8', get_string(fields['normal_key']), entry
151
+ assert_equal 5000, get_number(fields['non_utf8 key']), entry
152
+ assert_equal 'test non utf8', get_string(get_fields(get_struct(fields \
153
+ ['nested_struct']))['non_utf8 key']), entry
154
+ assert_equal null_value, fields['null_field'], entry
155
+ end
156
+ end
157
+
158
+ def test_non_integer_timestamp
159
+ setup_gce_metadata_stubs
160
+ time = Time.now
161
+ {
162
+ { 'seconds' => nil, 'nanos' => nil } => nil,
163
+ { 'seconds' => nil, 'nanos' => time.tv_nsec } => nil,
164
+ { 'seconds' => 'seconds', 'nanos' => time.tv_nsec } => nil,
165
+ { 'seconds' => time.tv_sec, 'nanos' => 'nanos' } => \
166
+ { 'seconds' => time.tv_sec },
167
+ { 'seconds' => time.tv_sec, 'nanos' => nil } => \
168
+ { 'seconds' => time.tv_sec }
169
+ }.each do |input, expected|
170
+ setup_logging_stubs do
171
+ d = create_driver
172
+ @logs_sent = []
173
+ d.emit('message' => log_entry(0), 'timestamp' => input)
174
+ d.run
175
+ end
176
+ verify_log_entries(1, COMPUTE_PARAMS) do |entry|
177
+ assert_equal expected, entry['metadata']['timestamp'],
178
+ "Test with timestamp '#{input}' failed for " \
179
+ "entry: '#{entry}'."
180
+ end
181
+ end
182
+ end
183
+
184
+ private
185
+
186
+ GRPC_MOCK_HOST = 'localhost:56789'
187
+
188
+ WriteLogEntriesRequest = Google::Logging::V1::WriteLogEntriesRequest
189
+ WriteLogEntriesResponse = Google::Logging::V1::WriteLogEntriesResponse
190
+
191
+ USE_GRPC_CONFIG = %(
192
+ use_grpc true
193
+ )
194
+
195
+ # Create a Fluentd output test driver with the Google Cloud Output plugin with
196
+ # grpc enabled. The signature of this method is different between the grpc
197
+ # path and the non-grpc path. For grpc, an additional grpc stub class can be
198
+ # passed in to construct the mock used by the test driver.
199
+ def create_driver(conf = APPLICATION_DEFAULT_CONFIG, tag = 'test',
200
+ grpc_stub = GRPCLoggingMockService.rpc_stub_class)
201
+ conf += USE_GRPC_CONFIG
202
+ Fluent::Test::BufferedOutputTestDriver.new(
203
+ GoogleCloudOutputWithGRPCMock.new(grpc_stub), tag).configure(conf, true)
204
+ end
205
+
206
+ # Google Cloud Fluent output stub with grpc mock.
207
+ class GoogleCloudOutputWithGRPCMock < Fluent::GoogleCloudOutput
208
+ def initialize(grpc_stub)
209
+ super()
210
+ @grpc_stub = grpc_stub
211
+ end
212
+
213
+ def api_client
214
+ ssl_creds = GRPC::Core::ChannelCredentials.new
215
+ authentication = Google::Auth.get_application_default
216
+ creds = GRPC::Core::CallCredentials.new(authentication.updater_proc)
217
+ ssl_creds.compose(creds)
218
+
219
+ # Here we have obtained the creds, but for the mock, we will leave the
220
+ # channel insecure.
221
+ @grpc_stub.new(GRPC_MOCK_HOST, :this_channel_is_insecure)
222
+ end
223
+ end
224
+
225
+ # GRPC logging mock that successfully logs the records.
226
+ class GRPCLoggingMockService < Google::Logging::V1::LoggingService::Service
227
+ def initialize(stub_params, requests_received)
228
+ super()
229
+ @requests_received = requests_received
230
+ @expected_log_names = stub_params.map do |param|
231
+ "projects/#{param[:project_id]}/logs/#{param[:log_name]}"
232
+ end
233
+ end
234
+
235
+ def write_log_entries(request, _call)
236
+ fail GRPC::BadStatus.new(99, "Unexpected request: #{request.inspect}") \
237
+ unless @expected_log_names.include?(request.log_name)
238
+ @requests_received << request
239
+ WriteLogEntriesResponse.new
240
+ end
241
+
242
+ # TODO(lingshi) Remove these dummy methods when grpc/9033 is fixed.
243
+ #
244
+ # These methods should never be called, so they will just fail the tests
245
+ # with "unimplemented" errors..
246
+ def _undefined
247
+ fail "Method #{__callee__} is unimplemented and needs to be overridden."
248
+ end
249
+
250
+ alias_method :list_logs, :_undefined
251
+ alias_method :list_log_services, :_undefined
252
+ alias_method :list_log_service_indexes, :_undefined
253
+ alias_method :delete_log, :_undefined
254
+ undef_method :_undefined
255
+ end
256
+
257
+ # GRPC logging mock that fails and returns server side or client side errors.
258
+ class GRPCLoggingMockFailingService <
259
+ Google::Logging::V1::LoggingService::Service
260
+ # 'code_sent' and 'message_sent' are references of external variables. We
261
+ # will assert the values of them later. 'code_value' and 'message_value'
262
+ # are actual error code and message we expect this mock to return.
263
+ def initialize(code, message, failed_attempts)
264
+ @code = code
265
+ @message = message
266
+ @failed_attempts = failed_attempts
267
+ super()
268
+ end
269
+
270
+ def write_log_entries(_request, _call)
271
+ @failed_attempts << 1
272
+ fail GRPC::BadStatus.new(@code, @message)
273
+ end
274
+
275
+ # TODO(lingshi) Remove these dummy methods when grpc/9033 is fixed.
276
+ #
277
+ # These methods should never be called, so they will just fail the tests
278
+ # with "unimplemented" errors..
279
+ def _undefined
280
+ fail "Method #{__callee__} is unimplemented and needs to be overridden."
281
+ end
282
+
283
+ alias_method :list_logs, :_undefined
284
+ alias_method :list_log_services, :_undefined
285
+ alias_method :list_log_service_indexes, :_undefined
286
+ alias_method :delete_log, :_undefined
287
+ undef_method :_undefined
288
+ end
289
+
290
+ # Set up grpc stubs to mock the external calls.
291
+ def setup_logging_stubs(override_stub_params = nil, should_fail = false,
292
+ code = 0, message = 'Ok')
293
+ stub_params = override_stub_params || \
294
+ [COMPUTE_PARAMS, VMENGINE_PARAMS, CONTAINER_FROM_TAG_PARAMS,
295
+ CONTAINER_FROM_METADATA_PARAMS, CLOUDFUNCTIONS_PARAMS,
296
+ CUSTOM_PARAMS, EC2_PARAMS]
297
+ srv = GRPC::RpcServer.new
298
+ @failed_attempts = []
299
+ @requests_sent = []
300
+ if should_fail
301
+ grpc = GRPCLoggingMockFailingService.new(code, message, @failed_attempts)
302
+ else
303
+ grpc = GRPCLoggingMockService.new(stub_params, @requests_sent)
304
+ end
305
+ srv.handle(grpc)
306
+ srv.add_http2_port(GRPC_MOCK_HOST, :this_port_is_insecure)
307
+ t = Thread.new { srv.run }
308
+ srv.wait_till_running
309
+ begin
310
+ yield
311
+ rescue Test::Unit::Failure, StandardError => e
312
+ srv.stop
313
+ t.join
314
+ raise e
315
+ end
316
+ srv.stop
317
+ t.join
318
+ end
319
+
320
+ # Verify the number and the content of the log entries match the expectation.
321
+ # The caller can optionally provide a block which is called for each entry.
322
+ def verify_log_entries(n, params, payload_type = 'textPayload', &block)
323
+ @requests_sent.each do |batch|
324
+ @logs_sent << JSON.parse(batch.to_json)
325
+ end
326
+ verify_json_log_entries(n, params, payload_type, &block)
327
+ end
328
+
329
+ # Use the right single quotation mark as the sample non-utf8 character.
330
+ def non_utf8_character
331
+ [0x92].pack('C*')
332
+ end
333
+
334
+ # For an optional field with default values, Protobuf omits the field when it
335
+ # is deserialized to json. So we need to add an extra check for gRPC which
336
+ # uses Protobuf.
337
+ #
338
+ # An optional block can be passed in if we need to assert something other than
339
+ # a plain equal. e.g. assert_in_delta.
340
+ def assert_equal_with_default(field, expected_value, default_value, entry)
341
+ if expected_value == default_value
342
+ assert_nil field
343
+ elsif block_given?
344
+ yield
345
+ else
346
+ assert_equal expected_value, field, entry
347
+ end
348
+ end
349
+
350
+ # Unset the 'referer' field.
351
+ def http_request_message_with_absent_referer
352
+ http_request_message.reject do |k, _|
353
+ k == 'referer'
354
+ end
355
+ end
356
+
357
+ # Get the fields of the struct payload.
358
+ def get_fields(struct_payload)
359
+ struct_payload['fields']
360
+ end
361
+
362
+ # Get the value of a struct field.
363
+ def get_struct(field)
364
+ field['structValue']
365
+ end
366
+
367
+ # Get the value of a string field.
368
+ def get_string(field)
369
+ field['stringValue']
370
+ end
371
+
372
+ # Get the value of a number field.
373
+ def get_number(field)
374
+ field['numberValue']
375
+ end
376
+
377
+ # The null value.
378
+ def null_value
379
+ { 'nullValue' => 'NULL_VALUE' }
380
+ end
381
+ end
metadata ADDED
@@ -0,0 +1,291 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vmik-fluent-plugin-google-cloud
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.5.alpha1
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Todd Derr
9
+ - Alex Robinson
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2017-02-15 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: fluentd
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '0.12'
23
+ - - <
24
+ - !ruby/object:Gem::Version
25
+ version: 0.15.0
26
+ type: :runtime
27
+ prerelease: false
28
+ version_requirements: !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '0.12'
34
+ - - <
35
+ - !ruby/object:Gem::Version
36
+ version: 0.15.0
37
+ - !ruby/object:Gem::Dependency
38
+ name: googleapis-common-protos
39
+ requirement: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: '1.3'
45
+ - - <
46
+ - !ruby/object:Gem::Version
47
+ version: '1.4'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: '1.3'
56
+ - - <
57
+ - !ruby/object:Gem::Version
58
+ version: '1.4'
59
+ - !ruby/object:Gem::Dependency
60
+ name: google-api-client
61
+ requirement: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ~>
65
+ - !ruby/object:Gem::Version
66
+ version: 0.9.0
67
+ - - <
68
+ - !ruby/object:Gem::Version
69
+ version: 0.10.0
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 0.9.0
78
+ - - <
79
+ - !ruby/object:Gem::Version
80
+ version: 0.10.0
81
+ - !ruby/object:Gem::Dependency
82
+ name: googleauth
83
+ requirement: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ~>
87
+ - !ruby/object:Gem::Version
88
+ version: '0.5'
89
+ - - <
90
+ - !ruby/object:Gem::Version
91
+ version: '0.6'
92
+ type: :runtime
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ~>
98
+ - !ruby/object:Gem::Version
99
+ version: '0.5'
100
+ - - <
101
+ - !ruby/object:Gem::Version
102
+ version: '0.6'
103
+ - !ruby/object:Gem::Dependency
104
+ name: grpc
105
+ requirement: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 1.1.0
111
+ - - <
112
+ - !ruby/object:Gem::Version
113
+ version: 1.2.0
114
+ type: :runtime
115
+ prerelease: false
116
+ version_requirements: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ~>
120
+ - !ruby/object:Gem::Version
121
+ version: 1.1.0
122
+ - - <
123
+ - !ruby/object:Gem::Version
124
+ version: 1.2.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: json
127
+ requirement: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ~>
131
+ - !ruby/object:Gem::Version
132
+ version: '1.8'
133
+ - - <
134
+ - !ruby/object:Gem::Version
135
+ version: '1.9'
136
+ type: :runtime
137
+ prerelease: false
138
+ version_requirements: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ~>
142
+ - !ruby/object:Gem::Version
143
+ version: '1.8'
144
+ - - <
145
+ - !ruby/object:Gem::Version
146
+ version: '1.9'
147
+ - !ruby/object:Gem::Dependency
148
+ name: mocha
149
+ requirement: !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ~>
153
+ - !ruby/object:Gem::Version
154
+ version: '1.1'
155
+ type: :development
156
+ prerelease: false
157
+ version_requirements: !ruby/object:Gem::Requirement
158
+ none: false
159
+ requirements:
160
+ - - ~>
161
+ - !ruby/object:Gem::Version
162
+ version: '1.1'
163
+ - !ruby/object:Gem::Dependency
164
+ name: rake
165
+ requirement: !ruby/object:Gem::Requirement
166
+ none: false
167
+ requirements:
168
+ - - ~>
169
+ - !ruby/object:Gem::Version
170
+ version: '10.3'
171
+ type: :development
172
+ prerelease: false
173
+ version_requirements: !ruby/object:Gem::Requirement
174
+ none: false
175
+ requirements:
176
+ - - ~>
177
+ - !ruby/object:Gem::Version
178
+ version: '10.3'
179
+ - !ruby/object:Gem::Dependency
180
+ name: rubocop
181
+ requirement: !ruby/object:Gem::Requirement
182
+ none: false
183
+ requirements:
184
+ - - ~>
185
+ - !ruby/object:Gem::Version
186
+ version: 0.35.0
187
+ type: :development
188
+ prerelease: false
189
+ version_requirements: !ruby/object:Gem::Requirement
190
+ none: false
191
+ requirements:
192
+ - - ~>
193
+ - !ruby/object:Gem::Version
194
+ version: 0.35.0
195
+ - !ruby/object:Gem::Dependency
196
+ name: webmock
197
+ requirement: !ruby/object:Gem::Requirement
198
+ none: false
199
+ requirements:
200
+ - - ~>
201
+ - !ruby/object:Gem::Version
202
+ version: '1.17'
203
+ type: :development
204
+ prerelease: false
205
+ version_requirements: !ruby/object:Gem::Requirement
206
+ none: false
207
+ requirements:
208
+ - - ~>
209
+ - !ruby/object:Gem::Version
210
+ version: '1.17'
211
+ - !ruby/object:Gem::Dependency
212
+ name: test-unit
213
+ requirement: !ruby/object:Gem::Requirement
214
+ none: false
215
+ requirements:
216
+ - - ~>
217
+ - !ruby/object:Gem::Version
218
+ version: '3.0'
219
+ type: :development
220
+ prerelease: false
221
+ version_requirements: !ruby/object:Gem::Requirement
222
+ none: false
223
+ requirements:
224
+ - - ~>
225
+ - !ruby/object:Gem::Version
226
+ version: '3.0'
227
+ description: ! " Fluentd output plugin for the Stackdriver Logging API, which will
228
+ make\n logs viewable in the Developer Console's log viewer and can optionally\n
229
+ \ store them in Google Cloud Storage and/or BigQuery.\n This is an official Google
230
+ Ruby gem.\n"
231
+ email:
232
+ - salty@google.com
233
+ executables: []
234
+ extensions: []
235
+ extra_rdoc_files: []
236
+ files:
237
+ - fluent-plugin-google-cloud.gemspec
238
+ - README.rdoc
239
+ - Gemfile
240
+ - vmik-fluent-plugin-google-cloud-0.5.5.gem
241
+ - LICENSE
242
+ - CONTRIBUTING
243
+ - test/helper.rb
244
+ - test/plugin/base_test.rb
245
+ - test/plugin/data/iam-credentials.json
246
+ - test/plugin/data/credentials.json
247
+ - test/plugin/data/c31e573fd7f62ed495c9ca3821a5a85cb036dee1-privatekey.p12
248
+ - test/plugin/data/invalid_credentials.json
249
+ - test/plugin/test_out_google_cloud.rb
250
+ - test/plugin/test_out_google_cloud_grpc.rb
251
+ - Rakefile
252
+ - lib/fluent/plugin/out_google_cloud.rb
253
+ - lib/google/logging/v1/log_entry_pb.rb
254
+ - lib/google/logging/v1/logging_pb.rb
255
+ - lib/google/logging/v1/logging_services_pb.rb
256
+ - lib/google/logging/type/http_request_pb.rb
257
+ - lib/google/logging/type/log_severity_pb.rb
258
+ homepage: https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud
259
+ licenses:
260
+ - Apache-2.0
261
+ post_install_message:
262
+ rdoc_options: []
263
+ require_paths:
264
+ - lib
265
+ required_ruby_version: !ruby/object:Gem::Requirement
266
+ none: false
267
+ requirements:
268
+ - - ! '>='
269
+ - !ruby/object:Gem::Version
270
+ version: '2.0'
271
+ required_rubygems_version: !ruby/object:Gem::Requirement
272
+ none: false
273
+ requirements:
274
+ - - ! '>'
275
+ - !ruby/object:Gem::Version
276
+ version: 1.3.1
277
+ requirements: []
278
+ rubyforge_project:
279
+ rubygems_version: 1.8.23
280
+ signing_key:
281
+ specification_version: 3
282
+ summary: fluentd output plugin for the Stackdriver Logging API
283
+ test_files:
284
+ - test/helper.rb
285
+ - test/plugin/base_test.rb
286
+ - test/plugin/data/iam-credentials.json
287
+ - test/plugin/data/credentials.json
288
+ - test/plugin/data/c31e573fd7f62ed495c9ca3821a5a85cb036dee1-privatekey.p12
289
+ - test/plugin/data/invalid_credentials.json
290
+ - test/plugin/test_out_google_cloud.rb
291
+ - test/plugin/test_out_google_cloud_grpc.rb