google-cloud-logging 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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