google-cloud-logging 0.20.1 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aa3ebfa38e22e40778bd4a67a5d0f6373fd094a4
4
- data.tar.gz: a792bb01d9ba78eb0c728771eb07528280170bf0
3
+ metadata.gz: 8c9421790cb4f209636fe57644a348a9076ed293
4
+ data.tar.gz: 79e077faf17e8a77e8f4a471a3421207743d826c
5
5
  SHA512:
6
- metadata.gz: 4f751572455011147d48324f1159fa9d18ce447eb2bfa69bc8a150906386eaad5f033f4b8167da7d7cf84fcc1691bd3af2f04e82fa251abb194ce18e3b94a55b
7
- data.tar.gz: e8fc4fe86dc494fc4e3f1e2ea951f14fd6941a132394b8c26a1eddf620f6946da00832e1cd7556eed81aa5fe9fbe4f1fc5ab08b8ec34dc4e2cd6c8397731a70a
6
+ metadata.gz: 6d797aa5a7888d7b6f617439f37e8b20695fd4ac8c5b2f241ac52376bfdcf5154c2faf268e3411c09697d4ee37d13f3abe2f7428b5650ce7db3cdc581fae4eaf
7
+ data.tar.gz: 9c6ec7fe172ac640ebaa6c94c0501ed0e90b3b8004ba2387de6aadbaafcb134500a7d7ebf6a9aa921afa181ff663b48aa79d6271d2da86fdac2942d2cfbe1fc9
@@ -13,8 +13,8 @@
13
13
  # limitations under the License.
14
14
 
15
15
  ##
16
- # This file is here to be autorequired by bundler, so that the .bigquery and
17
- # #bigquery methods can be available, but the library and all dependencies won't
16
+ # This file is here to be autorequired by bundler, so that the .logging and
17
+ # #logging methods can be available, but the library and all dependencies won't
18
18
  # be loaded until required and used.
19
19
 
20
20
 
@@ -38,9 +38,9 @@ module Google
38
38
  # The default scope is:
39
39
  #
40
40
  # * `https://www.googleapis.com/auth/logging.admin`
41
- # @param [Integer] retries Number of times to retry requests on server
42
- # error. The default value is `3`. Optional.
43
41
  # @param [Integer] timeout Default timeout to use in requests. Optional.
42
+ # @param [Hash] client_config A hash of values to override the default
43
+ # behavior of the API client. Optional.
44
44
  #
45
45
  # @return [Google::Cloud::Logging::Project]
46
46
  #
@@ -49,7 +49,11 @@ module Google
49
49
  #
50
50
  # gcloud = Google::Cloud.new
51
51
  # logging = gcloud.logging
52
- # # ...
52
+ #
53
+ # entries = logging.entries
54
+ # entries.each do |e|
55
+ # puts "[#{e.timestamp}] #{e.log_name} #{e.payload.inspect}"
56
+ # end
53
57
  #
54
58
  # @example The default scope can be overridden with the `scope` option:
55
59
  # require "google/cloud"
@@ -58,10 +62,10 @@ module Google
58
62
  # platform_scope = "https://www.googleapis.com/auth/cloud-platform"
59
63
  # logging = gcloud.logging scope: platform_scope
60
64
  #
61
- def logging scope: nil, retries: nil, timeout: nil
65
+ def logging scope: nil, timeout: nil, client_config: nil
62
66
  Google::Cloud.logging @project, @keyfile, scope: scope,
63
- retries: (retries || @retries),
64
- timeout: (timeout || @timeout)
67
+ timeout: (timeout || @timeout),
68
+ client_config: client_config
65
69
  end
66
70
 
67
71
  ##
@@ -72,7 +76,7 @@ module Google
72
76
  # Guide](https://googlecloudplatform.github.io/google-cloud-ruby/#/docs/guides/authentication).
73
77
  #
74
78
  # @param [String] project Project identifier for the Stackdriver Logging
75
- # service.
79
+ # service you are connecting to.
76
80
  # @param [String, Hash] keyfile Keyfile downloaded from Google Cloud. If
77
81
  # file path the file must be readable.
78
82
  # @param [String, Array<String>] scope The OAuth 2.0 scopes controlling the
@@ -83,37 +87,28 @@ module Google
83
87
  # The default scope is:
84
88
  #
85
89
  # * `https://www.googleapis.com/auth/logging.admin`
86
- # @param [Integer] retries Number of times to retry requests on server
87
- # error. The default value is `3`. Optional.
88
90
  # @param [Integer] timeout Default timeout to use in requests. Optional.
91
+ # @param [Hash] client_config A hash of values to override the default
92
+ # behavior of the API client. Optional.
89
93
  #
90
94
  # @return [Google::Cloud::Logging::Project]
91
95
  #
92
96
  # @example
93
- # require "google/cloud/logging"
97
+ # require "google/cloud"
94
98
  #
95
- # gcloud = Google::Cloud.new
96
- # logging = gcloud.logging
97
- # # ...
99
+ # logging = Google::Cloud.logging
98
100
  #
99
- def self.logging project = nil, keyfile = nil, scope: nil, retries: nil,
100
- timeout: nil
101
+ # entries = logging.entries
102
+ # entries.each do |e|
103
+ # puts "[#{e.timestamp}] #{e.log_name} #{e.payload.inspect}"
104
+ # end
105
+ #
106
+ def self.logging project = nil, keyfile = nil, scope: nil, timeout: nil,
107
+ client_config: nil
101
108
  require "google/cloud/logging"
102
- project ||= Google::Cloud::Logging::Project.default_project
103
- project = project.to_s # Always cast to a string
104
- fail ArgumentError, "project is missing" if project.empty?
105
-
106
- if keyfile.nil?
107
- credentials = Google::Cloud::Logging::Credentials.default(
108
- scope: scope)
109
- else
110
- credentials = Google::Cloud::Logging::Credentials.new(
111
- keyfile, scope: scope)
112
- end
113
-
114
- Google::Cloud::Logging::Project.new(
115
- Google::Cloud::Logging::Service.new(
116
- project, credentials, retries: retries, timeout: timeout))
109
+ Google::Cloud::Logging.new project: project, keyfile: keyfile,
110
+ scope: scope, timeout: timeout,
111
+ client_config: client_config
117
112
  end
118
113
  end
119
114
  end
@@ -44,6 +44,11 @@ module Google
44
44
  # about the options for connecting in the [Authentication
45
45
  # Guide](https://googlecloudplatform.github.io/google-cloud-ruby/#/docs/guides/authentication).
46
46
  #
47
+ # If you just want to write your application's logs to the Stackdriver
48
+ # Logging service, you may find it easiest to use the [Ruby Logger
49
+ # implementation](#creating-a-ruby-logger-implementation) provided by this
50
+ # library. Otherwise, read on to learn more about the Logging API.
51
+ #
47
52
  # ## Listing log entries
48
53
  #
49
54
  # Stackdriver Logging gathers log entries from many services, including
@@ -55,10 +60,9 @@ module Google
55
60
  # {Google::Cloud::Logging::Entry} records belonging to your project:
56
61
  #
57
62
  # ```ruby
58
- # require "google/cloud"
63
+ # require "google/cloud/logging"
59
64
  #
60
- # gcloud = Google::Cloud.new
61
- # logging = gcloud.logging
65
+ # logging = Google::Cloud::Logging.new
62
66
  # entries = logging.entries
63
67
  # entries.each do |e|
64
68
  # puts "[#{e.timestamp}] #{e.log_name} #{e.payload.inspect}"
@@ -75,10 +79,9 @@ module Google
75
79
  # Stackdriver Logging API.
76
80
  #
77
81
  # ```ruby
78
- # require "google/cloud"
82
+ # require "google/cloud/logging"
79
83
  #
80
- # gcloud = Google::Cloud.new
81
- # logging = gcloud.logging
84
+ # logging = Google::Cloud::Logging.new
82
85
  # entries = logging.entries filter: "log:syslog"
83
86
  # entries.each do |e|
84
87
  # puts "[#{e.timestamp}] #{e.payload.inspect}"
@@ -88,10 +91,9 @@ module Google
88
91
  # You can also order the log entries by `timestamp`.
89
92
  #
90
93
  # ```ruby
91
- # require "google/cloud"
94
+ # require "google/cloud/logging"
92
95
  #
93
- # gcloud = Google::Cloud.new
94
- # logging = gcloud.logging
96
+ # logging = Google::Cloud::Logging.new
95
97
  # entries = logging.entries order: "timestamp desc"
96
98
  # entries.each do |e|
97
99
  # puts "[#{e.timestamp}] #{e.log_name} #{e.payload.inspect}"
@@ -121,11 +123,9 @@ module Google
121
123
  # logs](https://cloud.google.com/logging/docs/export/configure_export#setting_product_name_short_permissions_for_writing_exported_logs).
122
124
  #
123
125
  # ```ruby
124
- # require "google/cloud"
126
+ # require "google/cloud/logging"
125
127
  #
126
- # gcloud = Google::Cloud.new
127
- # logging = gcloud.logging
128
- # storage = gcloud.storage
128
+ # storage = Google::Cloud::Storage.new
129
129
  #
130
130
  # bucket = storage.create_bucket "my-logs-bucket"
131
131
  #
@@ -133,6 +133,10 @@ module Google
133
133
  # email = "cloud-logs@google.com"
134
134
  # bucket.acl.add_owner "group-#{email}"
135
135
  #
136
+ # require "google/cloud/logging"
137
+ #
138
+ # logging = Google::Cloud::Logging.new
139
+ #
136
140
  # sink = logging.create_sink "my-sink",
137
141
  # "storage.googleapis.com/#{bucket.id}"
138
142
  # ```
@@ -147,10 +151,9 @@ module Google
147
151
  # {Google::Cloud::Logging::Project#sinks}.
148
152
  #
149
153
  # ```ruby
150
- # require "google/cloud"
154
+ # require "google/cloud/logging"
151
155
  #
152
- # gcloud = Google::Cloud.new
153
- # logging = gcloud.logging
156
+ # logging = Google::Cloud::Logging.new
154
157
  # sinks = logging.sinks
155
158
  # sinks.each do |s|
156
159
  # puts "#{s.name}: #{s.filter} -> #{s.destination}"
@@ -172,10 +175,9 @@ module Google
172
175
  # filter](https://cloud.google.com/logging/docs/view/advanced_filters).
173
176
  #
174
177
  # ```ruby
175
- # require "google/cloud"
178
+ # require "google/cloud/logging"
176
179
  #
177
- # gcloud = Google::Cloud.new
178
- # logging = gcloud.logging
180
+ # logging = Google::Cloud::Logging.new
179
181
  # metric = logging.create_metric "errors", "severity>=ERROR"
180
182
  # ```
181
183
  #
@@ -185,10 +187,9 @@ module Google
185
187
  # {Google::Cloud::Logging::Project#metrics}.
186
188
  #
187
189
  # ```ruby
188
- # require "google/cloud"
190
+ # require "google/cloud/logging"
189
191
  #
190
- # gcloud = Google::Cloud.new
191
- # logging = gcloud.logging
192
+ # logging = Google::Cloud::Logging.new
192
193
  # metrics = logging.metrics
193
194
  # metrics.each do |m|
194
195
  # puts "#{m.name}: #{m.filter}"
@@ -205,10 +206,9 @@ module Google
205
206
  # contain a log name and a resource.
206
207
  #
207
208
  # ```ruby
208
- # require "google/cloud"
209
+ # require "google/cloud/logging"
209
210
  #
210
- # gcloud = Google::Cloud.new
211
- # logging = gcloud.logging
211
+ # logging = Google::Cloud::Logging.new
212
212
  #
213
213
  # entry = logging.entry
214
214
  # entry.payload = "Job started."
@@ -225,10 +225,9 @@ module Google
225
225
  # these values from the individual entries.
226
226
  #
227
227
  # ```ruby
228
- # require "google/cloud"
228
+ # require "google/cloud/logging"
229
229
  #
230
- # gcloud = Google::Cloud.new
231
- # logging = gcloud.logging
230
+ # logging = Google::Cloud::Logging.new
232
231
  #
233
232
  # entry1 = logging.entry
234
233
  # entry1.payload = "Job started."
@@ -246,6 +245,36 @@ module Google
246
245
  # labels: labels
247
246
  # ```
248
247
  #
248
+ # Normally, writing log entries is done synchronously; the call to
249
+ # {Google::Cloud::Logging::Project#write_entries} will block until it has
250
+ # either completed transmitting the data or encountered an error. To "fire
251
+ # and forget" without blocking, use {Google::Cloud::Logging::AsyncWriter};
252
+ # it spins up a background thread that writes log entries in batches. Calls
253
+ # to {Google::Cloud::Logging::AsyncWriter#write_entries} simply add entries
254
+ # to its work queue and return immediately.
255
+ #
256
+ # ```ruby
257
+ # require "google/cloud/logging"
258
+ #
259
+ # logging = Google::Cloud::Logging.new
260
+ # async = logging.async_writer
261
+ #
262
+ # entry1 = logging.entry
263
+ # entry1.payload = "Job started."
264
+ # entry2 = logging.entry
265
+ # entry2.payload = "Job completed."
266
+ # labels = { job_size: "large", job_code: "red" }
267
+ #
268
+ # resource = logging.resource "gae_app",
269
+ # "module_id" => "1",
270
+ # "version_id" => "20150925t173233"
271
+ #
272
+ # async.write_entries [entry1, entry2],
273
+ # log_name: "my_app_log",
274
+ # resource: resource,
275
+ # labels: labels
276
+ # ```
277
+ #
249
278
  # ### Creating a Ruby Logger implementation
250
279
  #
251
280
  # If your environment requires a logger instance that is API-compatible with
@@ -254,10 +283,9 @@ module Google
254
283
  # {Google::Cloud::Logging::Project#logger} to create one.
255
284
  #
256
285
  # ```ruby
257
- # require "google/cloud"
286
+ # require "google/cloud/logging"
258
287
  #
259
- # gcloud = Google::Cloud.new
260
- # logging = gcloud.logging
288
+ # logging = Google::Cloud::Logging.new
261
289
  #
262
290
  # resource = logging.resource "gae_app",
263
291
  # module_id: "1",
@@ -267,27 +295,89 @@ module Google
267
295
  # logger.info "Job started."
268
296
  # ```
269
297
  #
270
- # ## Configuring retries and timeout
298
+ # By default, the logger instance writes log entries asynchronously in a
299
+ # background thread using an {Google::Cloud::Logging::AsyncWriter}. If you
300
+ # want to customize or disable asynchronous writing, you may call the
301
+ # Logger constructor directly.
271
302
  #
272
- # You can configure how many times API requests may be automatically
273
- # retried. When an API request fails, the response will be inspected to see
274
- # if the request meets criteria indicating that it may succeed on retry,
275
- # such as `500` and `503` status codes or a specific internal error code
276
- # such as `rateLimitExceeded`. If it meets the criteria, the request will be
277
- # retried after a delay. If another error occurs, the delay will be
278
- # increased before a subsequent attempt, until the `retries` limit is
279
- # reached.
303
+ # ```ruby
304
+ # require "google/cloud/logging"
280
305
  #
281
- # You can also set the request `timeout` value in seconds.
306
+ # logging = Google::Cloud::Logging.new
307
+ #
308
+ # resource = logging.resource "gae_app",
309
+ # module_id: "1",
310
+ # version_id: "20150925t173233"
311
+ #
312
+ # logger = Google::Cloud::Logging::Logger.new logging,
313
+ # "my_app_log",
314
+ # resource,
315
+ # {env: :production}
316
+ # logger.info "Log entry written synchronously."
317
+ # ```
318
+ #
319
+ # ## Configuring timeout
320
+ #
321
+ # You can configure the request `timeout` value in seconds.
282
322
  #
283
323
  # ```ruby
284
- # require "google/cloud"
324
+ # require "google/cloud/logging"
285
325
  #
286
- # gcloud = Google::Cloud.new
287
- # logging = gcloud.logging retries: 10, timeout: 120
326
+ # logging = Google::Cloud::Logging.new timeout: 120
288
327
  # ```
289
328
  #
290
329
  module Logging
330
+ ##
331
+ # Creates a new object for connecting to the Stackdriver Logging service.
332
+ # Each call creates a new connection.
333
+ #
334
+ # For more information on connecting to Google Cloud see the
335
+ # [Authentication
336
+ # Guide](https://googlecloudplatform.github.io/google-cloud-ruby/#/docs/guides/authentication).
337
+ #
338
+ # @param [String] project Project identifier for the Stackdriver Logging
339
+ # service.
340
+ # @param [String, Hash] keyfile Keyfile downloaded from Google Cloud. If
341
+ # file path the file must be readable.
342
+ # @param [String, Array<String>] scope The OAuth 2.0 scopes controlling
343
+ # the set of resources and operations that the connection can access.
344
+ # See [Using OAuth 2.0 to Access Google
345
+ # APIs](https://developers.google.com/identity/protocols/OAuth2).
346
+ #
347
+ # The default scope is:
348
+ #
349
+ # * `https://www.googleapis.com/auth/logging.admin`
350
+ # @param [Integer] timeout Default timeout to use in requests. Optional.
351
+ # @param [Hash] client_config A hash of values to override the default
352
+ # behavior of the API client. Optional.
353
+ #
354
+ # @return [Google::Cloud::Logging::Project]
355
+ #
356
+ # @example
357
+ # require "google/cloud/logging"
358
+ #
359
+ # logging = Google::Cloud::Logging.new
360
+ #
361
+ # entries = logging.entries
362
+ # entries.each do |e|
363
+ # puts "[#{e.timestamp}] #{e.log_name} #{e.payload.inspect}"
364
+ # end
365
+ #
366
+ def self.new project: nil, keyfile: nil, scope: nil, timeout: nil,
367
+ client_config: nil
368
+ project ||= Google::Cloud::Logging::Project.default_project
369
+ project = project.to_s # Always cast to a string
370
+ fail ArgumentError, "project is missing" if project.empty?
371
+
372
+ credentials =
373
+ Google::Cloud::Logging::Credentials.credentials_with_scope keyfile,
374
+ scope
375
+
376
+ Google::Cloud::Logging::Project.new(
377
+ Google::Cloud::Logging::Service.new(
378
+ project, credentials, timeout: timeout,
379
+ client_config: client_config))
380
+ end
291
381
  end
292
382
  end
293
383
  end
@@ -0,0 +1,399 @@
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
+
16
+ module Google
17
+ module Cloud
18
+ module Logging
19
+ ##
20
+ # # AsyncWriter
21
+ #
22
+ # An object that batches and transmits log entries asynchronously.
23
+ #
24
+ # Use this object to transmit log entries efficiently. It keeps a queue
25
+ # of log entries, and runs a background thread that transmits them to
26
+ # the logging service in batches. Generally, adding to the queue will
27
+ # not block.
28
+ #
29
+ # This object is thread-safe; it may accept write requests from
30
+ # multiple threads simultaneously, and will serialize them when
31
+ # executing in the background thread.
32
+ #
33
+ # @example
34
+ # require "google/cloud/logging"
35
+ #
36
+ # logging = Google::Cloud::Logging.new
37
+ #
38
+ # async = logging.async_writer
39
+ #
40
+ # entry1 = logging.entry payload: "Job started."
41
+ # entry2 = logging.entry payload: "Job completed."
42
+ #
43
+ # labels = { job_size: "large", job_code: "red" }
44
+ # resource = logging.resource "gae_app",
45
+ # "module_id" => "1",
46
+ # "version_id" => "20150925t173233"
47
+ #
48
+ # async.write_entries [entry1, entry2],
49
+ # log_name: "my_app_log",
50
+ # resource: resource,
51
+ # labels: labels
52
+ #
53
+ class AsyncWriter
54
+ DEFAULT_MAX_QUEUE_SIZE = 10000
55
+
56
+ ##
57
+ # @private Item in the log entries queue.
58
+ QueueItem = Struct.new(:entries, :log_name, :resource, :labels) do
59
+ def try_combine next_item
60
+ if log_name == next_item.log_name &&
61
+ resource == next_item.resource &&
62
+ labels == next_item.labels
63
+ entries.concat(next_item.entries)
64
+ true
65
+ else
66
+ false
67
+ end
68
+ end
69
+ end
70
+
71
+ ##
72
+ # @private The logging object.
73
+ attr_accessor :logging
74
+
75
+ ##
76
+ # @private The maximum size of the entries queue, or nil if not set.
77
+ attr_accessor :max_queue_size
78
+
79
+ ##
80
+ # The current state. Either :running, :suspended, :stopping, or :stopped
81
+ attr_reader :state
82
+
83
+ ##
84
+ # The last exception thrown by the background thread, or nil if nothing
85
+ # has been thrown.
86
+ attr_reader :last_exception
87
+
88
+ ##
89
+ # @private Creates a new AsyncWriter instance.
90
+ def initialize logging, max_queue_size = DEFAULT_MAX_QUEUE_SIZE
91
+ @logging = logging
92
+ @max_queue_size = max_queue_size
93
+ @startup_lock = Mutex.new
94
+ @thread = nil
95
+ @state = :running
96
+ end
97
+
98
+ ##
99
+ # Asynchronously write one or more log entries to the Stackdriver
100
+ # Logging service.
101
+ #
102
+ # Unlike the main write_entries method, this method usually does not
103
+ # block. The actual write RPCs will happen in the background, and may
104
+ # be batched with related calls. However, if the queue is full, this
105
+ # method will block until enough space has cleared out.
106
+ #
107
+ # @param [Google::Cloud::Logging::Entry,
108
+ # Array<Google::Cloud::Logging::Entry>] entries One or more entry
109
+ # objects to write. The log entries must have values for all required
110
+ # fields.
111
+ # @param [String] log_name A default log ID for those log entries in
112
+ # `entries` that do not specify their own `log_name`. See also
113
+ # {Entry#log_name=}.
114
+ # @param [Resource] resource A default monitored resource for those log
115
+ # entries in entries that do not specify their own resource. See also
116
+ # {Entry#resource}.
117
+ # @param [Hash{Symbol,String => String}] labels User-defined `key:value`
118
+ # items that are added to the `labels` field of each log entry in
119
+ # `entries`, except when a log entry specifies its own `key:value`
120
+ # item with the same key. See also {Entry#labels=}.
121
+ #
122
+ # @return [Google::Cloud::Logging::AsyncWriter] Returns self.
123
+ #
124
+ # @example
125
+ # require "google/cloud/logging"
126
+ #
127
+ # logging = Google::Cloud::Logging.new
128
+ # async = logging.async_writer
129
+ #
130
+ # entry = logging.entry payload: "Job started.",
131
+ # log_name: "my_app_log"
132
+ # entry.resource.type = "gae_app"
133
+ # entry.resource.labels[:module_id] = "1"
134
+ # entry.resource.labels[:version_id] = "20150925t173233"
135
+ #
136
+ # async.write_entries entry
137
+ #
138
+ def write_entries entries, log_name: nil, resource: nil, labels: nil
139
+ ensure_thread
140
+ entries = Array(entries)
141
+ @lock.synchronize do
142
+ fail "AsyncWriter has been stopped" unless writable?
143
+ queue_item = QueueItem.new entries, log_name, resource, labels
144
+ if @queue.empty? || !@queue.last.try_combine(queue_item)
145
+ @queue.push queue_item
146
+ end
147
+ @queue_size += entries.size
148
+ @lock_cond.broadcast
149
+ while @max_queue_size && @queue_size > @max_queue_size
150
+ @lock_cond.wait
151
+ end
152
+ end
153
+ self
154
+ end
155
+
156
+ ##
157
+ # Creates a logger instance that is API-compatible with Ruby's standard
158
+ # library [Logger](http://ruby-doc.org/stdlib/libdoc/logger/rdoc).
159
+ #
160
+ # The logger will use AsyncWriter to transmit log entries on a
161
+ # background thread.
162
+ #
163
+ # @param [String] log_name A log resource name to be associated with the
164
+ # written log entries.
165
+ # @param [Google::Cloud::Logging::Resource] resource The monitored
166
+ # resource to be associated with written log entries.
167
+ # @param [Hash] labels A set of user-defined data to be associated with
168
+ # written log entries.
169
+ #
170
+ # @return [Google::Cloud::Logging::Logger] a Logger object that can be
171
+ # used in place of a ruby standard library logger object.
172
+ #
173
+ # @example
174
+ # require "google/cloud/logging"
175
+ #
176
+ # logging = Google::Cloud::Logging.new
177
+ #
178
+ # resource = logging.resource "gae_app",
179
+ # module_id: "1",
180
+ # version_id: "20150925t173233"
181
+ #
182
+ # async = logging.async_writer
183
+ # logger = async.logger "my_app_log", resource, env: :production
184
+ # logger.info "Job started."
185
+ #
186
+ def logger log_name, resource, labels = {}
187
+ Logger.new self, log_name, resource, labels
188
+ end
189
+
190
+ ##
191
+ # Stops this asynchronous writer.
192
+ #
193
+ # After this call succeeds, the state will change to :stopping, and
194
+ # you may not issue any additional write_entries calls. Any previously
195
+ # issued writes will complete. Once any existing backlog has been
196
+ # cleared, the state will change to :stopped.
197
+ #
198
+ # @return [Boolean] Returns true if the writer was running, or false
199
+ # if the writer had already been stopped.
200
+ #
201
+ def stop
202
+ ensure_thread
203
+ @lock.synchronize do
204
+ if state != :stopped
205
+ @state = :stopping
206
+ @lock_cond.broadcast
207
+ true
208
+ else
209
+ false
210
+ end
211
+ end
212
+ end
213
+
214
+ ##
215
+ # Suspends this asynchronous writer.
216
+ #
217
+ # After this call succeeds, the state will change to :suspended, and
218
+ # the writer will stop sending RPCs until resumed.
219
+ #
220
+ # @return [Boolean] Returns true if the writer had been running and was
221
+ # suspended, otherwise false.
222
+ #
223
+ def suspend
224
+ ensure_thread
225
+ @lock.synchronize do
226
+ if state == :running
227
+ @state = :suspended
228
+ @lock_cond.broadcast
229
+ true
230
+ else
231
+ false
232
+ end
233
+ end
234
+ end
235
+
236
+ ##
237
+ # Resumes this suspended asynchronous writer.
238
+ #
239
+ # After this call succeeds, the state will change to :running, and
240
+ # the writer will resume sending RPCs.
241
+ #
242
+ # @return [Boolean] Returns true if the writer had been suspended and
243
+ # is now running, otherwise false.
244
+ #
245
+ def resume
246
+ ensure_thread
247
+ @lock.synchronize do
248
+ if state == :suspended
249
+ @state = :running
250
+ @lock_cond.broadcast
251
+ true
252
+ else
253
+ false
254
+ end
255
+ end
256
+ end
257
+
258
+ ##
259
+ # Returns true if this writer is running.
260
+ #
261
+ # @return [Boolean] Returns true if the writer is currently running.
262
+ #
263
+ def running?
264
+ ensure_thread
265
+ @lock.synchronize do
266
+ state == :running
267
+ end
268
+ end
269
+
270
+ ##
271
+ # Returns true if this writer is suspended.
272
+ #
273
+ # @return [Boolean] Returns true if the writer is currently suspended.
274
+ #
275
+ def suspended?
276
+ ensure_thread
277
+ @lock.synchronize do
278
+ state == :suspended
279
+ end
280
+ end
281
+
282
+ ##
283
+ # Returns true if this writer is still accepting writes. This means
284
+ # it is either running or suspended.
285
+ #
286
+ # @return [Boolean] Returns true if the writer is accepting writes.
287
+ #
288
+ def writable?
289
+ ensure_thread
290
+ @lock.synchronize do
291
+ state == :suspended || state == :running
292
+ end
293
+ end
294
+
295
+ ##
296
+ # Returns true if this writer is fully stopped.
297
+ #
298
+ # @return [Boolean] Returns true if the writer is fully stopped.
299
+ #
300
+ def stopped?
301
+ ensure_thread
302
+ @lock.synchronize do
303
+ state == :stopped
304
+ end
305
+ end
306
+
307
+ ##
308
+ # Blocks until this asynchronous writer has been stopped, or the given
309
+ # timeout (if present) has elapsed.
310
+ #
311
+ # @param [Number] timeout Timeout in seconds, or nil for no timeout.
312
+ #
313
+ # @return [Boolean] Returns true if the writer is stopped, or false
314
+ # if the timeout expired.
315
+ #
316
+ def wait_until_stopped timeout = nil
317
+ ensure_thread
318
+ deadline = timeout ? ::Time.new.to_f + timeout : nil
319
+ @lock.synchronize do
320
+ until state == :stopped
321
+ cur_time = ::Time.new.to_f
322
+ return false if deadline && cur_time >= deadline
323
+ @lock_cond.wait(deadline ? deadline - cur_time : nil)
324
+ end
325
+ end
326
+ true
327
+ end
328
+
329
+ protected
330
+
331
+ ##
332
+ # @private Ensures the background thread is running. This is called
333
+ # at the start of all public methods, and kicks off the thread lazily.
334
+ # It also ensures the thread gets restarted (with an empty queue) in
335
+ # case this object is forked into a child process.
336
+ #
337
+ def ensure_thread
338
+ @startup_lock.synchronize do
339
+ if (@thread.nil? || !@thread.alive?) && @state != :stopped
340
+ @queue_size = 0
341
+ @queue = []
342
+ @lock = Monitor.new
343
+ @lock_cond = @lock.new_cond
344
+ @thread = Thread.new { run_backgrounder }
345
+ end
346
+ end
347
+ end
348
+
349
+ ##
350
+ # @private The background thread implementation, which continuously
351
+ # waits for performs work, and returns only when fully stopped.
352
+ #
353
+ def run_backgrounder
354
+ loop do
355
+ queue_item = wait_next_item
356
+ return unless queue_item
357
+ begin
358
+ logging.write_entries(
359
+ queue_item.entries,
360
+ log_name: queue_item.log_name,
361
+ resource: queue_item.resource,
362
+ labels: queue_item.labels
363
+ )
364
+ rescue => e
365
+ # Ignore any exceptions thrown from the background thread, but
366
+ # keep running to ensure its state behavior remains consistent.
367
+ @last_exception = e
368
+ end
369
+ end
370
+ end
371
+
372
+ ##
373
+ # @private Wait for and dequeue the next set of log entries to transmit.
374
+ #
375
+ # @return [QueueItem,NilClass] Returns the next set of entries. If
376
+ # the writer has been stopped and no more entries are left in the
377
+ # queue, returns nil.
378
+ #
379
+ def wait_next_item
380
+ @lock.synchronize do
381
+ while state == :suspended ||
382
+ (state == :running && @queue.empty?)
383
+ @lock_cond.wait
384
+ end
385
+ if @queue.empty?
386
+ @state = :stopped
387
+ nil
388
+ else
389
+ queue_item = @queue.shift
390
+ @queue_size -= queue_item.entries.size
391
+ @lock_cond.broadcast
392
+ queue_item
393
+ end
394
+ end
395
+ end
396
+ end
397
+ end
398
+ end
399
+ end