google-cloud-logging 2.0.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.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +18 -0
  3. data/AUTHENTICATION.md +178 -0
  4. data/CHANGELOG.md +407 -0
  5. data/CODE_OF_CONDUCT.md +40 -0
  6. data/CONTRIBUTING.md +188 -0
  7. data/INSTRUMENTATION.md +71 -0
  8. data/LICENSE +201 -0
  9. data/LOGGING.md +32 -0
  10. data/OVERVIEW.md +321 -0
  11. data/TROUBLESHOOTING.md +31 -0
  12. data/lib/google-cloud-logging.rb +161 -0
  13. data/lib/google/cloud/logging.rb +188 -0
  14. data/lib/google/cloud/logging/async_writer.rb +513 -0
  15. data/lib/google/cloud/logging/convert.rb +70 -0
  16. data/lib/google/cloud/logging/credentials.rb +44 -0
  17. data/lib/google/cloud/logging/entry.rb +528 -0
  18. data/lib/google/cloud/logging/entry/http_request.rb +167 -0
  19. data/lib/google/cloud/logging/entry/list.rb +178 -0
  20. data/lib/google/cloud/logging/entry/operation.rb +91 -0
  21. data/lib/google/cloud/logging/entry/source_location.rb +85 -0
  22. data/lib/google/cloud/logging/errors.rb +101 -0
  23. data/lib/google/cloud/logging/log/list.rb +156 -0
  24. data/lib/google/cloud/logging/logger.rb +633 -0
  25. data/lib/google/cloud/logging/metric.rb +168 -0
  26. data/lib/google/cloud/logging/metric/list.rb +170 -0
  27. data/lib/google/cloud/logging/middleware.rb +307 -0
  28. data/lib/google/cloud/logging/project.rb +838 -0
  29. data/lib/google/cloud/logging/rails.rb +232 -0
  30. data/lib/google/cloud/logging/resource.rb +85 -0
  31. data/lib/google/cloud/logging/resource_descriptor.rb +137 -0
  32. data/lib/google/cloud/logging/resource_descriptor/list.rb +175 -0
  33. data/lib/google/cloud/logging/service.rb +239 -0
  34. data/lib/google/cloud/logging/sink.rb +315 -0
  35. data/lib/google/cloud/logging/sink/list.rb +168 -0
  36. data/lib/google/cloud/logging/version.rb +22 -0
  37. metadata +304 -0
@@ -0,0 +1,70 @@
1
+ # Copyright 2017 Google LLC
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
+ # https://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
+
16
+ module Google
17
+ module Cloud
18
+ module Logging
19
+ ##
20
+ # @private Conversion to/from Logging GRPC objects.
21
+ module Convert
22
+ ##
23
+ # @private Convert a Hash to a Google::Protobuf::Struct.
24
+ def self.hash_to_struct hash
25
+ # TODO: ArgumentError if hash is not a Hash
26
+ Google::Protobuf::Struct.new \
27
+ fields: Hash[hash.map { |k, v| [String(k), object_to_value(v)] }]
28
+ end
29
+
30
+ ##
31
+ # @private Convert an Array to a Google::Protobuf::ListValue.
32
+ def self.array_to_list array
33
+ # TODO: ArgumentError if array is not an Array
34
+ Google::Protobuf::ListValue.new \
35
+ values: array.map { |o| object_to_value o }
36
+ end
37
+
38
+ ##
39
+ # @private Convert an Object to a Google::Protobuf::Value.
40
+ def self.object_to_value obj
41
+ case obj
42
+ when NilClass then Google::Protobuf::Value.new null_value: :NULL_VALUE
43
+ when Numeric then Google::Protobuf::Value.new number_value: obj
44
+ when String then Google::Protobuf::Value.new string_value: obj
45
+ when TrueClass then Google::Protobuf::Value.new bool_value: true
46
+ when FalseClass then Google::Protobuf::Value.new bool_value: false
47
+ when Hash then
48
+ Google::Protobuf::Value.new struct_value: hash_to_struct(obj)
49
+ when Array then
50
+ Google::Protobuf::Value.new list_value: array_to_list(obj)
51
+ else
52
+ # TODO: Could raise ArgumentError here, or convert to a string
53
+ Google::Protobuf::Value.new string_value: obj.to_s
54
+ end
55
+ end
56
+
57
+ ##
58
+ # @private Convert a Google::Protobuf::Map to a Hash
59
+ def self.map_to_hash map
60
+ if map.respond_to? :to_h
61
+ map.to_h
62
+ else
63
+ # Enumerable doesn't have to_h on ruby 2.0...
64
+ Hash[map.to_a]
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,44 @@
1
+ # Copyright 2016 Google LLC
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
+ # https://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
+
16
+ require "google/cloud/logging/v2/logging_service/credentials"
17
+
18
+ module Google
19
+ module Cloud
20
+ module Logging
21
+ ##
22
+ # # Credentials
23
+ #
24
+ # Represents the authentication and authorization used to connect to the
25
+ # Stackdriver Logging API.
26
+ #
27
+ # @example
28
+ # require "google/cloud/logging"
29
+ #
30
+ # keyfile = "/path/to/keyfile.json"
31
+ # creds = Google::Cloud::Logging::Credentials.new keyfile
32
+ #
33
+ # logging = Google::Cloud::Logging.new(
34
+ # project_id: "my-project",
35
+ # credentials: creds
36
+ # )
37
+ #
38
+ # logging.project_id #=> "my-project"
39
+ #
40
+ class Credentials < Google::Cloud::Logging::V2::LoggingService::Credentials
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,528 @@
1
+ # Copyright 2016 Google LLC
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
+ # https://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
+
16
+ require "google/cloud/logging/convert"
17
+ require "google/cloud/logging/resource"
18
+ require "google/cloud/logging/entry/http_request"
19
+ require "google/cloud/logging/entry/operation"
20
+ require "google/cloud/logging/entry/source_location"
21
+ require "google/cloud/logging/entry/list"
22
+
23
+ module Google
24
+ module Cloud
25
+ module Logging
26
+ ##
27
+ # # Entry
28
+ #
29
+ # An individual entry in a log.
30
+ #
31
+ # Each log entry is composed of metadata and a payload. The metadata
32
+ # includes standard information used by Stackdriver Logging, such as when
33
+ # the entry was created and where it came from. The payload is the event
34
+ # record. Traditionally this is a message string, but in Stackdriver
35
+ # Logging it can also be a JSON or protocol buffer object. A single log
36
+ # can have entries with different payload types.
37
+ #
38
+ # A log is a named collection of entries. Logs can be produced by Google
39
+ # Cloud Platform services, by third-party services, or by your
40
+ # applications. For example, the log `compute.googleapis.com/activity_log`
41
+ # is produced by Google Compute Engine. Logs are simply referenced by name
42
+ # in google-cloud. There is no `Log` type in google-cloud or `Log`
43
+ # resource in the Stackdriver Logging API.
44
+ #
45
+ # @see https://cloud.google.com/logging/docs/view/logs_index List of Log
46
+ # Types
47
+ #
48
+ # @example
49
+ # require "google/cloud/logging"
50
+ #
51
+ # logging = Google::Cloud::Logging.new
52
+ #
53
+ # entry = logging.entry payload: "Job started.", log_name: "my_app_log"
54
+ # entry.resource.type = "gae_app"
55
+ # entry.resource.labels[:module_id] = "1"
56
+ # entry.resource.labels[:version_id] = "20150925t173233"
57
+ #
58
+ # logging.write_entries entry
59
+ #
60
+ # @example Provide a hash to write a JSON payload to the log:
61
+ # require "google/cloud/logging"
62
+ #
63
+ # logging = Google::Cloud::Logging.new
64
+ #
65
+ # payload = { "stats" => { "a" => 8, "b" => 12.5} }
66
+ # entry = logging.entry payload: payload, log_name: "my_app_log"
67
+ # entry.resource.type = "gae_app"
68
+ # entry.resource.labels[:module_id] = "1"
69
+ # entry.resource.labels[:version_id] = "20150925t173233"
70
+ #
71
+ # logging.write_entries entry
72
+ #
73
+ class Entry
74
+ ##
75
+ # Generate a pseudo-random, 16-character ID suitable for use as the log
76
+ # entry's {#insert_id}.
77
+ #
78
+ # @return [String]
79
+ #
80
+ # @example
81
+ # require "google/cloud/logging"
82
+ #
83
+ # insert_id = Google::Cloud::Logging::Entry.insert_id
84
+ #
85
+ def self.insert_id
86
+ rand(36**16).to_s 36
87
+ end
88
+
89
+ ##
90
+ # Create a new Entry instance. The {#resource} attribute is
91
+ # pre-populated with a new {Google::Cloud::Logging::Resource} instance.
92
+ # See also {Google::Cloud::Logging::Project#entry}.
93
+ def initialize
94
+ @labels = {}
95
+ @resource = Resource.new
96
+ @http_request = HttpRequest.new
97
+ @operation = Operation.new
98
+ @severity = :DEFAULT
99
+ @source_location = SourceLocation.new
100
+ @insert_id = Entry.insert_id
101
+ end
102
+
103
+ ##
104
+ # The resource name of the log to which this log entry belongs. The
105
+ # format of the name is `projects/<project-id>/logs/<log-id>`. e.g.
106
+ # `projects/my-projectid/logs/my_app_log` and
107
+ # `projects/1234567890/logs/library.googleapis.com%2Fbook_log`
108
+ #
109
+ # The log ID part of resource name must be less than 512 characters long
110
+ # and can only include the following characters: upper and lower case
111
+ # alphanumeric characters: `[A-Za-z0-9]`; and punctuation characters:
112
+ # forward-slash (`/`), underscore (`_`), hyphen (`-`), and period (`.`).
113
+ # Forward-slash (`/`) characters in the log ID must be URL-encoded.
114
+ attr_accessor :log_name
115
+
116
+ ##
117
+ # The monitored resource associated with this log entry. Example: a log
118
+ # entry that reports a database error would be associated with the
119
+ # monitored resource designating the particular database that reported
120
+ # the error.
121
+ # @return [Google::Cloud::Logging::Resource]
122
+ attr_accessor :resource
123
+
124
+ ##
125
+ # The time the event described by the log entry occurred. If omitted,
126
+ # Stackdriver Logging will use the time the log entry is written.
127
+ # @return [Time]
128
+ attr_accessor :timestamp
129
+
130
+ ##
131
+ # The severity level of the log entry. The default value is `:DEFAULT`.
132
+ # @return [Symbol]
133
+ attr_accessor :severity
134
+
135
+ ##
136
+ # Returns `true` if the severity level is `:DEFAULT`.
137
+ def default?
138
+ severity == :DEFAULT
139
+ end
140
+
141
+ ##
142
+ # Sets the severity level to `:DEFAULT`.
143
+ #
144
+ # @example
145
+ # require "google/cloud/logging"
146
+ #
147
+ # logging = Google::Cloud::Logging.new
148
+ #
149
+ # entry = logging.entry
150
+ # entry.severity = :DEBUG
151
+ # entry.default!
152
+ # entry.default? #=> true
153
+ # entry.severity #=> :DEFAULT
154
+ #
155
+ def default!
156
+ self.severity = :DEFAULT
157
+ end
158
+
159
+ ##
160
+ # Returns `true` if the severity level is `:DEBUG`.
161
+ def debug?
162
+ severity == :DEBUG
163
+ end
164
+
165
+ ##
166
+ # Sets the severity level to `:DEBUG`.
167
+ #
168
+ # @example
169
+ # require "google/cloud/logging"
170
+ #
171
+ # logging = Google::Cloud::Logging.new
172
+ #
173
+ # entry = logging.entry
174
+ # entry.severity #=> :DEFAULT
175
+ # entry.debug!
176
+ # entry.debug? #=> true
177
+ # entry.severity #=> :DEBUG
178
+ #
179
+ def debug!
180
+ self.severity = :DEBUG
181
+ end
182
+
183
+ ##
184
+ # Returns `true` if the severity level is `:INFO`.
185
+ def info?
186
+ severity == :INFO
187
+ end
188
+
189
+ ##
190
+ # Sets the severity level to `:INFO`.
191
+ #
192
+ # @example
193
+ # require "google/cloud/logging"
194
+ #
195
+ # logging = Google::Cloud::Logging.new
196
+ #
197
+ # entry = logging.entry
198
+ # entry.severity #=> :DEFAULT
199
+ # entry.info!
200
+ # entry.info? #=> true
201
+ # entry.severity #=> :INFO
202
+ #
203
+ def info!
204
+ self.severity = :INFO
205
+ end
206
+
207
+ ##
208
+ # Returns `true` if the severity level is `:NOTICE`.
209
+ def notice?
210
+ severity == :NOTICE
211
+ end
212
+
213
+ ##
214
+ # Sets the severity level to `:NOTICE`.
215
+ #
216
+ # @example
217
+ # require "google/cloud/logging"
218
+ #
219
+ # logging = Google::Cloud::Logging.new
220
+ #
221
+ # entry = logging.entry
222
+ # entry.severity #=> :DEFAULT
223
+ # entry.notice!
224
+ # entry.notice? #=> true
225
+ # entry.severity #=> :NOTICE
226
+ #
227
+ def notice!
228
+ self.severity = :NOTICE
229
+ end
230
+
231
+ ##
232
+ # Returns `true` if the severity level is `:WARNING`.
233
+ def warning?
234
+ severity == :WARNING
235
+ end
236
+
237
+ ##
238
+ # Sets the severity level to `:WARNING`.
239
+ #
240
+ # @example
241
+ # require "google/cloud/logging"
242
+ #
243
+ # logging = Google::Cloud::Logging.new
244
+ #
245
+ # entry = logging.entry
246
+ # entry.severity #=> :DEFAULT
247
+ # entry.warning!
248
+ # entry.warning? #=> true
249
+ # entry.severity #=> :WARNING
250
+ #
251
+ def warning!
252
+ self.severity = :WARNING
253
+ end
254
+
255
+ ##
256
+ # Returns `true` if the severity level is `:ERROR`.
257
+ def error?
258
+ severity == :ERROR
259
+ end
260
+
261
+ ##
262
+ # Sets the severity level to `:ERROR`.
263
+ #
264
+ # @example
265
+ # require "google/cloud/logging"
266
+ #
267
+ # logging = Google::Cloud::Logging.new
268
+ #
269
+ # entry = logging.entry
270
+ # entry.severity #=> :DEFAULT
271
+ # entry.error!
272
+ # entry.error? #=> true
273
+ # entry.severity #=> :ERROR
274
+ #
275
+ def error!
276
+ self.severity = :ERROR
277
+ end
278
+
279
+ ##
280
+ # Returns `true` if the severity level is `:CRITICAL`.
281
+ def critical?
282
+ severity == :CRITICAL
283
+ end
284
+
285
+ ##
286
+ # Sets the severity level to `:CRITICAL`.
287
+ #
288
+ # @example
289
+ # require "google/cloud/logging"
290
+ #
291
+ # logging = Google::Cloud::Logging.new
292
+ #
293
+ # entry = logging.entry
294
+ # entry.severity #=> :DEFAULT
295
+ # entry.critical!
296
+ # entry.critical? #=> true
297
+ # entry.severity #=> :CRITICAL
298
+ #
299
+ def critical!
300
+ self.severity = :CRITICAL
301
+ end
302
+
303
+ ##
304
+ # Returns `true` if the severity level is `:ALERT`.
305
+ def alert?
306
+ severity == :ALERT
307
+ end
308
+
309
+ ##
310
+ # Sets the severity level to `:ALERT`.
311
+ #
312
+ # @example
313
+ # require "google/cloud/logging"
314
+ #
315
+ # logging = Google::Cloud::Logging.new
316
+ #
317
+ # entry = logging.entry
318
+ # entry.severity #=> :DEFAULT
319
+ # entry.alert!
320
+ # entry.alert? #=> true
321
+ # entry.severity #=> :ALERT
322
+ #
323
+ def alert!
324
+ self.severity = :ALERT
325
+ end
326
+
327
+ ##
328
+ # Returns `true` if the severity level is `:EMERGENCY`.
329
+ def emergency?
330
+ severity == :EMERGENCY
331
+ end
332
+
333
+ ##
334
+ # Sets the severity level to `:EMERGENCY`.
335
+ #
336
+ # @example
337
+ # require "google/cloud/logging"
338
+ #
339
+ # logging = Google::Cloud::Logging.new
340
+ #
341
+ # entry = logging.entry
342
+ # entry.severity #=> :DEFAULT
343
+ # entry.emergency!
344
+ # entry.emergency? #=> true
345
+ # entry.severity #=> :EMERGENCY
346
+ #
347
+ def emergency!
348
+ self.severity = :EMERGENCY
349
+ end
350
+
351
+ ##
352
+ # A unique ID for the log entry. If you provide this field, the logging
353
+ # service considers other log entries in the same log with the same ID
354
+ # as duplicates which can be removed. If omitted, Stackdriver Logging
355
+ # will generate a unique ID for this log entry.
356
+ # @return [String]
357
+ attr_accessor :insert_id
358
+
359
+ ##
360
+ # A set of user-defined data that provides additional information about
361
+ # the log entry.
362
+ # @return [Hash]
363
+ attr_accessor :labels
364
+
365
+ ##
366
+ # The log entry payload, represented as either a string, a hash (JSON),
367
+ # or a hash (protocol buffer).
368
+ # @return [String, Hash]
369
+ attr_accessor :payload
370
+
371
+ ##
372
+ # Information about the HTTP request associated with this log entry, if
373
+ # applicable.
374
+ # @return [Google::Cloud::Logging::Entry::HttpRequest]
375
+ attr_reader :http_request
376
+
377
+ ##
378
+ # Information about an operation associated with the log entry, if
379
+ # applicable.
380
+ # @return [Google::Cloud::Logging::Entry::Operation]
381
+ attr_reader :operation
382
+
383
+ ##
384
+ # Resource name of the trace associated with the log entry, if any. If
385
+ # it contains a relative resource name, the name is assumed to be
386
+ # relative to `//tracing.googleapis.com`. Example:
387
+ # `projects/my-projectid/traces/06796866738c859f2f19b7cfb3214824`
388
+ # Optional.
389
+ # @return [String]
390
+ attr_accessor :trace
391
+
392
+ ##
393
+ # Source code location information associated with the log entry, if
394
+ # any.
395
+ # @return [Google::Cloud::Logging::Entry::SourceLocation]
396
+ attr_reader :source_location
397
+
398
+ ##
399
+ # The sampling decision of the trace associated with the log entry.
400
+ # Optional. A `true` value means that the trace resource name in the
401
+ # `trace` field was sampled for storage in a trace backend. A `false`
402
+ # means that the trace was not sampled for storage when this log entry
403
+ # was written, or the sampling decision was unknown at the time. A
404
+ # non-sampled `trace` value is still useful as a request correlation
405
+ # identifier. The default is `false`.
406
+ # @return [Boolean]
407
+ attr_accessor :trace_sampled
408
+
409
+ ##
410
+ # @private Determines if the Entry has any data.
411
+ def empty?
412
+ log_name.nil? &&
413
+ timestamp.nil? &&
414
+ (labels.nil? || labels.empty?) &&
415
+ payload.nil? &&
416
+ resource.empty? &&
417
+ http_request.empty? &&
418
+ operation.empty? &&
419
+ trace.nil? &&
420
+ source_location.empty? &&
421
+ trace_sampled.nil?
422
+ end
423
+
424
+ ##
425
+ # @private Exports the Entry to a Google::Cloud::Logging::V2::LogEntry object.
426
+ def to_grpc
427
+ grpc = Google::Cloud::Logging::V2::LogEntry.new(
428
+ log_name: log_name.to_s,
429
+ timestamp: timestamp_grpc,
430
+ # TODO: verify severity is the correct type?
431
+ severity: severity,
432
+ insert_id: insert_id.to_s,
433
+ labels: labels_grpc,
434
+ resource: resource.to_grpc,
435
+ http_request: http_request.to_grpc,
436
+ operation: operation.to_grpc,
437
+ trace: trace.to_s,
438
+ source_location: source_location.to_grpc,
439
+ trace_sampled: !(!trace_sampled)
440
+ )
441
+ # Add payload
442
+ append_payload grpc
443
+ grpc
444
+ end
445
+
446
+ ##
447
+ # @private New Entry from a Google::Cloud::Logging::V2::LogEntry object.
448
+ def self.from_grpc grpc
449
+ return new if grpc.nil?
450
+ new.tap do |e|
451
+ e.log_name = grpc.log_name
452
+ e.timestamp = extract_timestamp grpc
453
+ e.severity = grpc.severity
454
+ e.insert_id = grpc.insert_id
455
+ e.labels = Convert.map_to_hash grpc.labels
456
+ e.payload = extract_payload grpc
457
+ e.instance_variable_set :@resource,
458
+ Resource.from_grpc(grpc.resource)
459
+ e.instance_variable_set :@http_request,
460
+ HttpRequest.from_grpc(grpc.http_request)
461
+ e.instance_variable_set :@operation,
462
+ Operation.from_grpc(grpc.operation)
463
+ e.trace = grpc.trace
464
+ e.instance_variable_set :@source_location,
465
+ SourceLocation.from_grpc(
466
+ grpc.source_location
467
+ )
468
+ e.trace_sampled = grpc.trace_sampled
469
+ end
470
+ end
471
+
472
+ ##
473
+ # @private Formats the timestamp as a Google::Protobuf::Timestamp
474
+ # object.
475
+ def timestamp_grpc
476
+ return nil if timestamp.nil?
477
+ # TODO: ArgumentError if timestamp is not a Time object?
478
+ Google::Protobuf::Timestamp.new(
479
+ seconds: timestamp.to_i,
480
+ nanos: timestamp.nsec
481
+ )
482
+ end
483
+
484
+ ##
485
+ # @private Formats the labels so they can be saved to a
486
+ # Google::Cloud::Logging::V2::LogEntry object.
487
+ def labels_grpc
488
+ return {} if labels.nil?
489
+ # Coerce symbols to strings
490
+ Hash[labels.map do |k, v|
491
+ v = String(v) if v.is_a? Symbol
492
+ [String(k), v]
493
+ end]
494
+ end
495
+
496
+ ##
497
+ # @private Adds the payload data to a Google::Cloud::Logging::V2::LogEntry
498
+ # object.
499
+ def append_payload grpc
500
+ grpc.proto_payload = nil
501
+ grpc.json_payload = nil
502
+ grpc.text_payload = nil
503
+
504
+ if payload.is_a? Google::Protobuf::Any
505
+ grpc.proto_payload = payload
506
+ elsif payload.respond_to? :to_hash
507
+ grpc.json_payload = Convert.hash_to_struct payload.to_hash
508
+ else
509
+ grpc.text_payload = payload.to_s
510
+ end
511
+ end
512
+
513
+ ##
514
+ # @private Extract payload data from Google API Client object.
515
+ def self.extract_payload grpc
516
+ grpc.proto_payload || grpc.json_payload || grpc.text_payload
517
+ end
518
+
519
+ ##
520
+ # @private Get a Time object from a Google::Protobuf::Timestamp object.
521
+ def self.extract_timestamp grpc
522
+ return nil if grpc.timestamp.nil?
523
+ Time.at grpc.timestamp.seconds, Rational(grpc.timestamp.nanos, 1000)
524
+ end
525
+ end
526
+ end
527
+ end
528
+ end