google-cloud-logging 1.5.7 → 1.6.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/CONTRIBUTING.md +1 -1
  4. data/lib/google-cloud-logging.rb +7 -5
  5. data/lib/google/cloud/logging.rb +22 -8
  6. data/lib/google/cloud/logging/async_writer.rb +308 -187
  7. data/lib/google/cloud/logging/convert.rb +15 -9
  8. data/lib/google/cloud/logging/entry.rb +43 -13
  9. data/lib/google/cloud/logging/entry/source_location.rb +3 -3
  10. data/lib/google/cloud/logging/errors.rb +101 -0
  11. data/lib/google/cloud/logging/log/list.rb +1 -1
  12. data/lib/google/cloud/logging/logger.rb +6 -4
  13. data/lib/google/cloud/logging/middleware.rb +24 -11
  14. data/lib/google/cloud/logging/project.rb +38 -15
  15. data/lib/google/cloud/logging/rails.rb +56 -5
  16. data/lib/google/cloud/logging/resource.rb +1 -1
  17. data/lib/google/cloud/logging/service.rb +42 -32
  18. data/lib/google/cloud/logging/v2/config_service_v2_client.rb +1 -1
  19. data/lib/google/cloud/logging/v2/credentials.rb +1 -1
  20. data/lib/google/cloud/logging/v2/doc/google/api/distribution.rb +1 -37
  21. data/lib/google/cloud/logging/v2/doc/google/api/label.rb +1 -1
  22. data/lib/google/cloud/logging/v2/doc/google/api/metric.rb +1 -13
  23. data/lib/google/cloud/logging/v2/doc/google/api/monitored_resource.rb +1 -1
  24. data/lib/google/cloud/logging/v2/doc/google/logging/type/http_request.rb +1 -1
  25. data/lib/google/cloud/logging/v2/doc/google/logging/v2/log_entry.rb +1 -1
  26. data/lib/google/cloud/logging/v2/doc/google/logging/v2/logging.rb +1 -12
  27. data/lib/google/cloud/logging/v2/doc/google/logging/v2/logging_config.rb +1 -1
  28. data/lib/google/cloud/logging/v2/doc/google/logging/v2/logging_metrics.rb +1 -1
  29. data/lib/google/cloud/logging/v2/doc/google/protobuf/any.rb +1 -1
  30. data/lib/google/cloud/logging/v2/doc/google/protobuf/duration.rb +1 -1
  31. data/lib/google/cloud/logging/v2/doc/google/protobuf/empty.rb +1 -1
  32. data/lib/google/cloud/logging/v2/doc/google/protobuf/field_mask.rb +1 -1
  33. data/lib/google/cloud/logging/v2/doc/google/protobuf/struct.rb +1 -1
  34. data/lib/google/cloud/logging/v2/doc/google/protobuf/timestamp.rb +1 -1
  35. data/lib/google/cloud/logging/v2/logging_service_v2_client.rb +1 -1
  36. data/lib/google/cloud/logging/v2/logging_service_v2_client_config.json +1 -1
  37. data/lib/google/cloud/logging/v2/metrics_service_v2_client.rb +1 -1
  38. data/lib/google/cloud/logging/version.rb +1 -1
  39. metadata +5 -4
@@ -23,25 +23,31 @@ module Google
23
23
  # @private Convert a Hash to a Google::Protobuf::Struct.
24
24
  def self.hash_to_struct hash
25
25
  # TODO: ArgumentError if hash is not a Hash
26
- Google::Protobuf::Struct.new fields:
27
- Hash[hash.map { |k, v| [String(k), object_to_value(v)] }]
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) }
28
36
  end
29
37
 
30
38
  ##
31
39
  # @private Convert an Object to a Google::Protobuf::Value.
32
40
  def self.object_to_value obj
33
41
  case obj
34
- when NilClass then Google::Protobuf::Value.new null_value:
35
- :NULL_VALUE
42
+ when NilClass then Google::Protobuf::Value.new null_value: :NULL_VALUE
36
43
  when Numeric then Google::Protobuf::Value.new number_value: obj
37
44
  when String then Google::Protobuf::Value.new string_value: obj
38
45
  when TrueClass then Google::Protobuf::Value.new bool_value: true
39
46
  when FalseClass then Google::Protobuf::Value.new bool_value: false
40
- when Hash then Google::Protobuf::Value.new struct_value:
41
- hash_to_struct(obj)
42
- when Array then Google::Protobuf::Value.new list_value:
43
- Google::Protobuf::ListValue.new(values:
44
- obj.map { |o| object_to_value(o) })
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)
45
51
  else
46
52
  # TODO: Could raise ArgumentError here, or convert to a string
47
53
  Google::Protobuf::Value.new string_value: obj.to_s
@@ -71,6 +71,21 @@ module Google
71
71
  # logging.write_entries entry
72
72
  #
73
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
+
74
89
  ##
75
90
  # Create a new Entry instance. The {#resource} attribute is
76
91
  # pre-populated with a new {Google::Cloud::Logging::Resource} instance.
@@ -82,6 +97,7 @@ module Google
82
97
  @operation = Operation.new
83
98
  @severity = :DEFAULT
84
99
  @source_location = SourceLocation.new
100
+ @insert_id = Entry.insert_id
85
101
  end
86
102
 
87
103
  ##
@@ -379,36 +395,48 @@ module Google
379
395
  # @return [Google::Cloud::Logging::Entry::SourceLocation]
380
396
  attr_reader :source_location
381
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
+
382
409
  ##
383
410
  # @private Determines if the Entry has any data.
384
411
  def empty?
385
412
  log_name.nil? &&
386
413
  timestamp.nil? &&
387
- insert_id.nil? &&
388
414
  (labels.nil? || labels.empty?) &&
389
415
  payload.nil? &&
390
416
  resource.empty? &&
391
417
  http_request.empty? &&
392
418
  operation.empty? &&
393
419
  trace.nil? &&
394
- source_location.empty?
420
+ source_location.empty? &&
421
+ trace_sampled.nil?
395
422
  end
396
423
 
397
424
  ##
398
425
  # @private Exports the Entry to a Google::Logging::V2::LogEntry object.
399
426
  def to_grpc
400
427
  grpc = Google::Logging::V2::LogEntry.new(
401
- log_name: log_name.to_s,
402
- timestamp: timestamp_grpc,
428
+ log_name: log_name.to_s,
429
+ timestamp: timestamp_grpc,
403
430
  # TODO: verify severity is the correct type?
404
- severity: severity,
405
- insert_id: insert_id.to_s,
406
- labels: labels_grpc,
407
- resource: resource.to_grpc,
408
- http_request: http_request.to_grpc,
409
- operation: operation.to_grpc,
410
- trace: trace.to_s,
411
- source_location: source_location.to_grpc
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)
412
440
  )
413
441
  # Add payload
414
442
  append_payload grpc
@@ -437,6 +465,7 @@ module Google
437
465
  SourceLocation.from_grpc(
438
466
  grpc.source_location
439
467
  )
468
+ e.trace_sampled = grpc.trace_sampled
440
469
  end
441
470
  end
442
471
 
@@ -448,7 +477,7 @@ module Google
448
477
  # TODO: ArgumentError if timestamp is not a Time object?
449
478
  Google::Protobuf::Timestamp.new(
450
479
  seconds: timestamp.to_i,
451
- nanos: timestamp.nsec
480
+ nanos: timestamp.nsec
452
481
  )
453
482
  end
454
483
 
@@ -456,6 +485,7 @@ module Google
456
485
  # @private Formats the labels so they can be saved to a
457
486
  # Google::Logging::V2::LogEntry object.
458
487
  def labels_grpc
488
+ return {} if labels.nil?
459
489
  # Coerce symbols to strings
460
490
  Hash[labels.map do |k, v|
461
491
  v = String(v) if v.is_a? Symbol
@@ -61,9 +61,9 @@ module Google
61
61
  def to_grpc
62
62
  return nil if empty?
63
63
  Google::Logging::V2::LogEntrySourceLocation.new(
64
- file: file.to_s,
65
- line: line,
66
- function: function.to_s
64
+ file: file.to_s,
65
+ line: line,
66
+ function: function.to_s
67
67
  )
68
68
  end
69
69
 
@@ -0,0 +1,101 @@
1
+ # Copyright 2018 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/errors"
17
+
18
+ module Google
19
+ module Cloud
20
+ module Logging
21
+ ##
22
+ # # AsyncWriterError
23
+ #
24
+ # Used to indicate a problem preventing {AsyncWriter} from asynchronously
25
+ # calling the API. This can occur when the {AsyncWriter} has too few
26
+ # resources allocated for the amount of usage.
27
+ #
28
+ # @example
29
+ # require "google/cloud/logging"
30
+ # require "google/cloud/error_reporting"
31
+ #
32
+ # logging = Google::Cloud::Logging.new
33
+ #
34
+ # resource = logging.resource "gae_app",
35
+ # module_id: "1",
36
+ # version_id: "20150925t173233"
37
+ #
38
+ # async = logging.async_writer
39
+ #
40
+ # # Register to be notified when unhandled errors occur.
41
+ # async.on_error do |error|
42
+ # # error can be a AsyncWriterError, with entries
43
+ # Google::Cloud::ErrorReporting.report error
44
+ # end
45
+ #
46
+ # logger = async.logger "my_app_log", resource, env: :production
47
+ # logger.info "Job started."
48
+ #
49
+ class AsyncWriterError < Google::Cloud::Error
50
+ # @!attribute [r] count
51
+ # @return [Array<Google::Cloud::Logging::Entry>] entries The entry
52
+ # objects that were not written to the API due to the error.
53
+ attr_reader :entries
54
+
55
+ def initialize message, entries = nil
56
+ super(message)
57
+ @entries = entries if entries
58
+ end
59
+ end
60
+
61
+ ##
62
+ # # AsyncWriteEntriesError
63
+ #
64
+ # Used to indicate a problem when {AsyncWriter} writes log entries to the
65
+ # API. This can occur when the API returns an error.
66
+ #
67
+ # @example
68
+ # require "google/cloud/logging"
69
+ # require "google/cloud/error_reporting"
70
+ #
71
+ # logging = Google::Cloud::Logging.new
72
+ #
73
+ # resource = logging.resource "gae_app",
74
+ # module_id: "1",
75
+ # version_id: "20150925t173233"
76
+ #
77
+ # async = logging.async_writer
78
+ #
79
+ # # Register to be notified when unhandled errors occur.
80
+ # async.on_error do |error|
81
+ # # error can be a AsyncWriteEntriesError, with entries
82
+ # Google::Cloud::ErrorReporting.report error
83
+ # end
84
+ #
85
+ # logger = async.logger "my_app_log", resource, env: :production
86
+ # logger.info "Job started."
87
+ #
88
+ class AsyncWriteEntriesError < Google::Cloud::Error
89
+ # @!attribute [r] count
90
+ # @return [Array<Google::Cloud::Logging::Entry>] entries The entry
91
+ # objects that were not written to the API due to the error.
92
+ attr_reader :entries
93
+
94
+ def initialize message, entries = nil
95
+ super(message)
96
+ @entries = entries if entries
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -73,7 +73,7 @@ module Google
73
73
  grpc = @service.list_logs token: token, resource: @resource,
74
74
  max: @max
75
75
  self.class.from_grpc grpc, @service, resource: @resource,
76
- max: @max
76
+ max: @max
77
77
  end
78
78
 
79
79
  ##
@@ -62,7 +62,7 @@ module Google
62
62
  # The log_name is a String that controls the name of the Stackdriver
63
63
  # log to write to. If it is nil, the default log_name for this Logger
64
64
  # is used.
65
- RequestInfo = ::Struct.new :trace_id, :log_name, :env
65
+ RequestInfo = ::Struct.new :trace_id, :log_name, :env, :trace_sampled
66
66
 
67
67
  ##
68
68
  # The Google Cloud writer object that calls to `#write_entries` are made
@@ -456,8 +456,9 @@ module Google
456
456
  # @param [Hash, nil] env The request's Rack environment or `nil` if not
457
457
  # available.
458
458
  #
459
- def add_request_info info: nil, env: nil, trace_id: nil, log_name: nil
460
- info ||= RequestInfo.new trace_id, log_name, env
459
+ def add_request_info info: nil, env: nil, trace_id: nil, log_name: nil,
460
+ trace_sampled: nil
461
+ info ||= RequestInfo.new trace_id, log_name, env, trace_sampled
461
462
 
462
463
  @request_info_var.value = info
463
464
 
@@ -549,11 +550,12 @@ module Google
549
550
  unless info.trace_id.nil? || @project.nil?
550
551
  entry.trace = "projects/#{@project}/traces/#{info.trace_id}"
551
552
  end
553
+ entry.trace_sampled = info.trace_sampled if entry.trace_sampled.nil?
552
554
  end
553
555
 
554
556
  writer.write_entries entry, log_name: actual_log_name,
555
557
  resource: resource,
556
- labels: entry_labels(info)
558
+ labels: entry_labels(info)
557
559
  end
558
560
 
559
561
  ##
@@ -28,7 +28,8 @@ module Google
28
28
  # A default value for the log_name_map argument. Directs health check
29
29
  # logs to a separate log name so they don't spam the main log.
30
30
  DEFAULT_LOG_NAME_MAP =
31
- { "/_ah/health" => "ruby_health_check_log" }.freeze
31
+ { "/_ah/health" => "ruby_health_check_log",
32
+ "/healthz" => "ruby_health_check_log" }.freeze
32
33
 
33
34
  ##
34
35
  # The Google::Cloud::Logging::Logger instance
@@ -43,6 +44,8 @@ module Google
43
44
  # to track Stackdriver request trace ID. It also properly sets
44
45
  # env["rack.logger"] to this assigned logger for accessing. If not
45
46
  # specified, a default logger with be used.
47
+ # @param [Proc] on_init A callback to be invoked when the middleware is
48
+ # initialized. The callback takes no arguments. Optional.
46
49
  # @param [Hash] kwargs Hash of configuration settings. Used for
47
50
  # backward API compatibility. See the [Configuration
48
51
  # Guide](https://googleapis.github.io/google-cloud-ruby/docs/stackdriver/latest/file.INSTRUMENTATION_CONFIGURATION)
@@ -51,23 +54,26 @@ module Google
51
54
  # @return [Google::Cloud::Logging::Middleware] A new
52
55
  # Google::Cloud::Logging::Middleware instance
53
56
  #
54
- def initialize app, logger: nil, **kwargs
57
+ def initialize app, logger: nil, on_init: nil, **kwargs
55
58
  @app = app
56
59
 
57
60
  load_config kwargs
58
61
 
59
- if logger
60
- @logger = logger
61
- else
62
+ logger ||= Middleware.logger
63
+ logger ||= begin
62
64
  log_name = configuration.log_name
63
- logging = Logging.new project_id: configuration.project_id,
65
+ logging = Logging.new project_id: configuration.project_id,
64
66
  credentials: configuration.credentials
65
67
  resource = Middleware.build_monitored_resource(
66
68
  configuration.monitored_resource.type,
67
69
  configuration.monitored_resource.labels
68
70
  )
69
- @logger = logging.logger log_name, resource
71
+ Middleware.logger = logging.logger log_name, resource
70
72
  end
73
+
74
+ on_init.call if on_init
75
+
76
+ @logger = logger
71
77
  end
72
78
 
73
79
  ##
@@ -185,6 +191,12 @@ module Google
185
191
  end
186
192
  end
187
193
 
194
+ class << self
195
+ ##
196
+ # @private Global logger object
197
+ attr_accessor :logger
198
+ end
199
+
188
200
  ##
189
201
  # @private Extract information from current environment and construct
190
202
  # the correct monitoring resource types and labels.
@@ -226,19 +238,20 @@ module Google
226
238
  type, labels =
227
239
  if Google::Cloud.env.app_engine?
228
240
  ["gae_app", {
229
- module_id: Google::Cloud.env.app_engine_service_id,
241
+ module_id: Google::Cloud.env.app_engine_service_id,
230
242
  version_id: Google::Cloud.env.app_engine_service_version
231
243
  }]
232
244
  elsif Google::Cloud.env.container_engine?
245
+ namespace_id = Google::Cloud.env.container_engine_namespace_id
246
+ namespace_id ||= "default"
233
247
  ["container", {
234
248
  cluster_name: Google::Cloud.env.container_engine_cluster_name,
235
- namespace_id: \
236
- Google::Cloud.env.container_engine_namespace_id || "default"
249
+ namespace_id: namespace_id
237
250
  }]
238
251
  elsif Google::Cloud.env.compute_engine?
239
252
  ["gce_instance", {
240
253
  instance_id: Google::Cloud.env.instance_name,
241
- zone: Google::Cloud.env.instance_zone
254
+ zone: Google::Cloud.env.instance_zone
242
255
  }]
243
256
  else
244
257
  ["global", {}]
@@ -206,8 +206,10 @@ module Google
206
206
  #
207
207
  def entry log_name: nil, resource: nil, timestamp: nil, severity: nil,
208
208
  insert_id: nil, labels: nil, payload: nil
209
+ ensure_service!
210
+
209
211
  e = Entry.new
210
- e.log_name = log_name if log_name
212
+ e.log_name = service.log_path(log_name) if log_name
211
213
  e.resource = resource if resource
212
214
  e.timestamp = timestamp if timestamp
213
215
  e.severity = severity if severity
@@ -240,8 +242,8 @@ module Google
240
242
  # `entries`, except when a log entry specifies its own `key:value`
241
243
  # item with the same key. See also {Entry#labels=}.
242
244
  # @param [Boolean] partial_success Whether valid entries should be
243
- # written even if some other entries fail due to INVALID_ARGUMENT or
244
- # PERMISSION_DENIED errors when communicating to the Stackdriver
245
+ # written even if some other entries fail due to `INVALID_ARGUMENT` or
246
+ # `PERMISSION_DENIED` errors when communicating to the Stackdriver
245
247
  # Logging API.
246
248
  #
247
249
  # @return [Boolean] Returns `true` if the entries were written.
@@ -304,22 +306,36 @@ module Google
304
306
  end
305
307
 
306
308
  ##
307
- # Creates an object that batches and transmits log entries
308
- # asynchronously.
309
+ # Creates an object that buffers, batches, and transmits log entries
310
+ # efficiently. Writing log entries to this object is asynchronous and
311
+ # will not block.
309
312
  #
310
- # Use this object to transmit log entries efficiently. It keeps a queue
311
- # of log entries, and runs a background thread that transmits them to
312
- # the logging service in batches. Generally, adding to the queue will
313
- # not block.
313
+ # Batches that cannot be delivered immediately are queued. When the
314
+ # queue is full new batch requests will raise errors that can be
315
+ # consumed using the {AsyncWriter#on_error} callback. This provides back
316
+ # pressure in case the writer cannot keep up with requests.
314
317
  #
315
318
  # This object is thread-safe; it may accept write requests from
316
319
  # multiple threads simultaneously, and will serialize them when
317
320
  # executing in the background thread.
318
321
  #
319
- # @param [Integer] max_queue_size The maximum number of log entries
320
- # that may be queued before write requests will begin to block.
321
- # This provides back pressure in case the transmitting thread cannot
322
- # keep up with requests.
322
+ # @param [Integer] max_batch_count The maximum number of log entries
323
+ # that may be buffered and sent in a batch.
324
+ # @param [Integer] max_batch_bytes The maximum byte size of log entries
325
+ # that may be buffered and sent in a batch.
326
+ # @param [Integer] max_queue_size The maximum number of pending
327
+ # write_entries requests that may be queued.
328
+ # @param [Numeric] interval The number of seconds to buffer log entries
329
+ # before a batch is written. Default is 5.
330
+ # @param [Integer] threads The number of threads used to make
331
+ # batched write_entries requests. Default is 10.
332
+ # @param [Boolean] partial_success Whether valid entries should be
333
+ # written even if some other entries fail due to `INVALID_ARGUMENT` or
334
+ # `PERMISSION_DENIED` errors when communicating to the Stackdriver
335
+ # Logging API.
336
+ #
337
+ # @return [Google::Cloud::Logging::AsyncWriter] an AsyncWriter object
338
+ # that buffers, batches, and transmits log entries efficiently.
323
339
  #
324
340
  # @example
325
341
  # require "google/cloud/logging"
@@ -341,8 +357,15 @@ module Google
341
357
  # resource: resource,
342
358
  # labels: labels
343
359
  #
344
- def async_writer max_queue_size: AsyncWriter::DEFAULT_MAX_QUEUE_SIZE
345
- AsyncWriter.new self, max_queue_size
360
+ def async_writer max_batch_count: 10000, max_batch_bytes: 10000000,
361
+ max_queue_size: 100, interval: 5, threads: 10,
362
+ partial_success: false
363
+
364
+ AsyncWriter.new self, max_count: max_batch_count,
365
+ max_bytes: max_batch_bytes,
366
+ max_queue: max_queue_size,
367
+ interval: interval, threads: threads,
368
+ partial_success: partial_success
346
369
  end
347
370
 
348
371
  ##