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,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
@@ -0,0 +1,156 @@
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
+ require "delegate"
17
+
18
+ module Google
19
+ module Cloud
20
+ module Logging
21
+ class Log
22
+ ##
23
+ # Log::List is a special case Array with additional values.
24
+ class List < DelegateClass(::Array)
25
+ ##
26
+ # If not empty, indicates that there are more records that match
27
+ # the request and this value should be passed to continue.
28
+ attr_accessor :token
29
+
30
+ ##
31
+ # @private Create a new Log::List with an array of log names.
32
+ def initialize arr = []
33
+ super arr
34
+ end
35
+
36
+ ##
37
+ # Whether there is a next page of logs.
38
+ #
39
+ # @return [Boolean]
40
+ #
41
+ # @example
42
+ # require "google/cloud/logging"
43
+ #
44
+ # logging = Google::Cloud::Logging.new
45
+ #
46
+ # logs = logging.logs
47
+ # if logs.next?
48
+ # next_logs = logs.next
49
+ # end
50
+ #
51
+ def next?
52
+ !token.nil?
53
+ end
54
+
55
+ ##
56
+ # Retrieve the next page of logs.
57
+ #
58
+ # @return [Log::List]
59
+ #
60
+ # @example
61
+ # require "google/cloud/logging"
62
+ #
63
+ # logging = Google::Cloud::Logging.new
64
+ #
65
+ # logs = logging.logs
66
+ # if logs.next?
67
+ # next_logs = logs.next
68
+ # end
69
+ #
70
+ def next
71
+ return nil unless next?
72
+ ensure_service!
73
+ grpc = @service.list_logs token: token, resource: @resource,
74
+ max: @max
75
+ self.class.from_grpc grpc, @service, resource: @resource,
76
+ max: @max
77
+ end
78
+
79
+ ##
80
+ # Retrieves remaining results by repeatedly invoking {#next} until
81
+ # {#next?} returns `false`. Calls the given block once for each
82
+ # result, which is passed as the argument to the block.
83
+ #
84
+ # An Enumerator is returned if no block is given.
85
+ #
86
+ # This method will make repeated API calls until all remaining results
87
+ # are retrieved. (Unlike `#each`, for example, which merely iterates
88
+ # over the results returned by a single API call.) Use with caution.
89
+ #
90
+ # @param [Integer] request_limit The upper limit of API requests to
91
+ # make to load all log names. Default is no limit.
92
+ # @yield [log] The block for accessing each log name.
93
+ # @yieldparam [String] log The log name.
94
+ #
95
+ # @return [Enumerator]
96
+ #
97
+ # @example Iterating each log name by passing a block:
98
+ # require "google/cloud/logging"
99
+ #
100
+ # logging = Google::Cloud::Logging.new
101
+ # logs = logging.logs
102
+ #
103
+ # logs.all { |l| puts l }
104
+ #
105
+ # @example Limit the number of API calls made:
106
+ # require "google/cloud/logging"
107
+ #
108
+ # logging = Google::Cloud::Logging.new
109
+ # logs = logging.logs
110
+ #
111
+ # logs.all(request_limit: 10) { |l| puts l }
112
+ #
113
+ def all request_limit: nil
114
+ request_limit = request_limit.to_i if request_limit
115
+ unless block_given?
116
+ return enum_for :all, request_limit: request_limit
117
+ end
118
+ results = self
119
+ loop do
120
+ results.each { |r| yield r }
121
+ if request_limit
122
+ request_limit -= 1
123
+ break if request_limit < 0
124
+ end
125
+ break unless results.next?
126
+ results = results.next
127
+ end
128
+ end
129
+
130
+ ##
131
+ # @private New Log::List from a
132
+ # Google::Cloud::Logging::V2::ListLogsResponse object.
133
+ def self.from_grpc grpc_list, service, resource: nil, max: nil
134
+ logs = new Array(grpc_list.log_names)
135
+ token = grpc_list.next_page_token
136
+ token = nil if token == "".freeze
137
+ logs.instance_variable_set :@token, token
138
+ logs.instance_variable_set :@service, service
139
+ logs.instance_variable_set :@resource, resource
140
+ logs.instance_variable_set :@max, max
141
+ logs
142
+ end
143
+
144
+ protected
145
+
146
+ ##
147
+ # @private Raise an error unless an active connection to the service
148
+ # is available.
149
+ def ensure_service!
150
+ raise "Must have active connection to service" unless @service
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,633 @@
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 "logger"
17
+ require "concurrent"
18
+
19
+ module Google
20
+ module Cloud
21
+ module Logging
22
+ ##
23
+ # # Logger
24
+ #
25
+ # An API-compatible replacement for ruby's Logger that logs to the
26
+ # Stackdriver Logging Service.
27
+ #
28
+ # @example
29
+ # require "google/cloud/logging"
30
+ #
31
+ # logging = Google::Cloud::Logging.new
32
+ #
33
+ # resource = logging.resource "gae_app",
34
+ # module_id: "1",
35
+ # version_id: "20150925t173233"
36
+ #
37
+ # logger = logging.logger "my_app_log", resource, env: :production
38
+ # logger.info "Job started."
39
+ #
40
+ # @example Provide a hash to write a JSON payload to the log:
41
+ # require "google/cloud/logging"
42
+ #
43
+ # logging = Google::Cloud::Logging.new
44
+ #
45
+ # resource = logging.resource "gae_app",
46
+ # module_id: "1",
47
+ # version_id: "20150925t173233"
48
+ #
49
+ # logger = logging.logger "my_app_log", resource, env: :production
50
+ #
51
+ # payload = { "stats" => { "a" => 8, "b" => 12.5} }
52
+ # logger.info payload
53
+ #
54
+ class Logger
55
+ ##
56
+ # A RequestInfo represents data about the request being handled by the
57
+ # current thread. It is used to configure logs coming from that thread.
58
+ #
59
+ # The trace_id is a String that controls the trace ID sent with the log
60
+ # entry. If it is nil, no trace ID is sent.
61
+ #
62
+ # The log_name is a String that controls the name of the Stackdriver
63
+ # log to write to. If it is nil, the default log_name for this Logger
64
+ # is used.
65
+ RequestInfo = ::Struct.new :trace_id, :log_name, :env, :trace_sampled
66
+
67
+ ##
68
+ # The Google Cloud writer object that calls to `#write_entries` are made
69
+ # on. Either an AsyncWriter or Project object.
70
+ attr_reader :writer
71
+
72
+ ##
73
+ # The Google Cloud log_name to write the log entry with.
74
+ attr_reader :log_name
75
+ alias progname log_name
76
+
77
+ ##
78
+ # The Google Cloud resource to write the log entry with.
79
+ attr_reader :resource
80
+
81
+ ##
82
+ # The Google Cloud labels to write the log entry with.
83
+ attr_reader :labels
84
+
85
+ ##
86
+ # The logging severity threshold (e.g. `Logger::INFO`)
87
+ attr_reader :level
88
+ alias sev_threshold level
89
+ alias local_level level
90
+
91
+ ##
92
+ # Boolean flag that indicates whether this logger can be silenced or
93
+ # not.
94
+ attr_accessor :silencer
95
+
96
+ ##
97
+ # This logger does not use a formatter, but it provides a default
98
+ # Logger::Formatter for API compatibility with the standard Logger.
99
+ attr_accessor :formatter
100
+
101
+ ##
102
+ # This logger does not use a formatter, but it implements this
103
+ # attribute for API compatibility with the standard Logger.
104
+ attr_accessor :datetime_format
105
+
106
+ ##
107
+ # The project ID this logger is sending data to. If set, this value is
108
+ # used to set the trace field of log entries.
109
+ attr_accessor :project
110
+
111
+ ##
112
+ # This logger treats progname as an alias for log_name.
113
+ def progname= name
114
+ @log_name = name
115
+ end
116
+
117
+ ##
118
+ # A Hash of Thread IDs to Stackdriver request trace ID. The
119
+ # Stackdriver trace ID is a shared request identifier across all
120
+ # Stackdriver services.
121
+ #
122
+ # This method is deprecated and returns a Hash containing only the
123
+ # current Thread ID/trace_id now.
124
+ #
125
+ # @deprecated Use request_info
126
+ #
127
+ def trace_ids
128
+ current_request_info = request_info
129
+ return {} if current_request_info.nil?
130
+ { current_thread_id => current_request_info.trace_id }
131
+ end
132
+
133
+ ##
134
+ # Create a new Logger instance.
135
+ #
136
+ # @param [#write_entries] writer The object that will transmit log
137
+ # entries. Generally, to create a logger that blocks on transmitting
138
+ # log entries, pass the Project; otherwise, to create a logger that
139
+ # transmits log entries in the background, pass an AsyncWriter. You
140
+ # may also pass any other object that responds to `#write_entries`.
141
+ # @param [String] log_name A log resource name to be associated with the
142
+ # written log entries.
143
+ # @param [Google::Cloud::Logging::Resource] resource The monitored
144
+ # resource to be associated with written log entries.
145
+ # @param [Hash] labels A set of user-defined data to be associated with
146
+ # written log entries.
147
+ #
148
+ # @return [Google::Cloud::Logging::Logger] a Logger object that can be
149
+ # used in place of a ruby standard library logger object.
150
+ #
151
+ # @example
152
+ # require "google/cloud/logging"
153
+ #
154
+ # logging = Google::Cloud::Logging.new
155
+ #
156
+ # writer = logging.async_writer max_queue_size: 1000
157
+ #
158
+ # resource = logging.resource "gae_app", labels: {
159
+ # "module_id" => "1",
160
+ # "version_id" => "20150925t173233"
161
+ # }
162
+ #
163
+ # logger = Google::Cloud::Logging::Logger.new writer,
164
+ # "my_app_log",
165
+ # resource,
166
+ # env: :production
167
+ # logger.info "Job started."
168
+ #
169
+ def initialize writer, log_name, resource, labels = nil
170
+ @writer = writer
171
+ @log_name = log_name
172
+ @resource = resource
173
+ @labels = labels || {}
174
+ @level = 0 # DEBUG is the default behavior
175
+ @request_info_var = Concurrent::ThreadLocalVar.new
176
+ @closed = false
177
+ # Unused, but present for API compatibility
178
+ @formatter = ::Logger::Formatter.new
179
+ @datetime_format = ""
180
+ @silencer = true
181
+
182
+ # The writer is usually a Project or AsyncWriter.
183
+ logging = @writer.respond_to?(:logging) ? @writer.logging : @writer
184
+ @project = logging.project if logging.respond_to? :project
185
+ end
186
+
187
+ ##
188
+ # Log a `DEBUG` entry.
189
+ #
190
+ # @param [String, Hash] message The log entry payload, represented as
191
+ # either a string, a hash (JSON), or a hash (protocol buffer).
192
+ # @yield Evaluates to the message to log. This is not evaluated unless
193
+ # the logger's level is sufficient to log the message. This allows you
194
+ # to create potentially expensive logging messages that are only
195
+ # called when the logger is configured to show them.
196
+ #
197
+ def debug message = nil, &block
198
+ if block_given?
199
+ add ::Logger::DEBUG, nil, message, &block
200
+ else
201
+ add ::Logger::DEBUG, message
202
+ end
203
+ end
204
+
205
+ ##
206
+ # Log an `INFO` entry.
207
+ #
208
+ # @param [String, Hash] message The log entry payload, represented as
209
+ # either a string, a hash (JSON), or a hash (protocol buffer).
210
+ # @yield Evaluates to the message to log. This is not evaluated unless
211
+ # the logger's level is sufficient to log the message. This allows you
212
+ # to create potentially expensive logging messages that are only
213
+ # called when the logger is configured to show them.
214
+ #
215
+ def info message = nil, &block
216
+ if block_given?
217
+ add ::Logger::INFO, nil, message, &block
218
+ else
219
+ add ::Logger::INFO, message
220
+ end
221
+ end
222
+
223
+ ##
224
+ # Log a `WARN` entry.
225
+ #
226
+ # @param [String, Hash] message The log entry payload, represented as
227
+ # either a string, a hash (JSON), or a hash (protocol buffer).
228
+ # @yield Evaluates to the message to log. This is not evaluated unless
229
+ # the logger's level is sufficient to log the message. This allows you
230
+ # to create potentially expensive logging messages that are only
231
+ # called when the logger is configured to show them.
232
+ #
233
+ def warn message = nil, &block
234
+ if block_given?
235
+ add ::Logger::WARN, nil, message, &block
236
+ else
237
+ add ::Logger::WARN, message
238
+ end
239
+ end
240
+
241
+ ##
242
+ # Log an `ERROR` entry.
243
+ #
244
+ # @param [String, Hash] message The log entry payload, represented as
245
+ # either a string, a hash (JSON), or a hash (protocol buffer).
246
+ # @yield Evaluates to the message to log. This is not evaluated unless
247
+ # the logger's level is sufficient to log the message. This allows you
248
+ # to create potentially expensive logging messages that are only
249
+ # called when the logger is configured to show them.
250
+ #
251
+ def error message = nil, &block
252
+ if block_given?
253
+ add ::Logger::ERROR, nil, message, &block
254
+ else
255
+ add ::Logger::ERROR, message
256
+ end
257
+ end
258
+
259
+ ##
260
+ # Log a `FATAL` entry.
261
+ #
262
+ # @param [String, Hash] message The log entry payload, represented as
263
+ # either a string, a hash (JSON), or a hash (protocol buffer).
264
+ # @yield Evaluates to the message to log. This is not evaluated unless
265
+ # the logger's level is sufficient to log the message. This allows you
266
+ # to create potentially expensive logging messages that are only
267
+ # called when the logger is configured to show them.
268
+ #
269
+ def fatal message = nil, &block
270
+ if block_given?
271
+ add ::Logger::FATAL, nil, message, &block
272
+ else
273
+ add ::Logger::FATAL, message
274
+ end
275
+ end
276
+
277
+ ##
278
+ # Log an `UNKNOWN` entry. This will be printed no matter what the
279
+ # logger's current severity level is.
280
+ #
281
+ # @param [String, Hash] message The log entry payload, represented as
282
+ # either a string, a hash (JSON), or a hash (protocol buffer).
283
+ # @yield Evaluates to the message to log. This is not evaluated unless
284
+ # the logger's level is sufficient to log the message. This allows you
285
+ # to create potentially expensive logging messages that are only
286
+ # called when the logger is configured to show them.
287
+ #
288
+ def unknown message = nil, &block
289
+ if block_given?
290
+ add ::Logger::UNKNOWN, nil, message, &block
291
+ else
292
+ add ::Logger::UNKNOWN, message
293
+ end
294
+ end
295
+
296
+ ##
297
+ # Log a message if the given severity is high enough. This is the
298
+ # generic logging method. Users will be more inclined to use {#debug},
299
+ # {#info}, {#warn}, {#error}, and {#fatal}.
300
+ #
301
+ # @param [Integer, String, Symbol] severity the integer code for or the
302
+ # name of the severity level
303
+ # @param [String, Hash] message The log entry payload, represented as
304
+ # either a string, a hash (JSON), or a hash (protocol buffer).
305
+ # @yield Evaluates to the message to log. This is not evaluated unless
306
+ # the logger's level is sufficient to log the message. This allows you
307
+ # to create potentially expensive logging messages that are only
308
+ # called when the logger is configured to show them.
309
+ #
310
+ def add severity, message = nil, progname = nil
311
+ return if @closed
312
+
313
+ severity = derive_severity(severity) || ::Logger::UNKNOWN
314
+ return true if severity < @level
315
+
316
+ if message.nil?
317
+ if block_given?
318
+ message = yield
319
+ else
320
+ message = progname
321
+ # progname = nil # TODO: Figure out what to do with the progname
322
+ end
323
+ end
324
+
325
+ write_entry severity, message unless @closed
326
+ true
327
+ end
328
+ alias log add
329
+
330
+ ##
331
+ # Logs the given message at UNKNOWN severity.
332
+ #
333
+ # @param [String] msg The log entry payload as a string.
334
+ #
335
+ def << msg
336
+ unknown msg
337
+ self
338
+ end
339
+
340
+ ##
341
+ # Returns `true` if the current severity level allows for sending
342
+ # `DEBUG` messages.
343
+ def debug?
344
+ @level <= ::Logger::DEBUG
345
+ end
346
+
347
+ ##
348
+ # Returns `true` if the current severity level allows for sending `INFO`
349
+ # messages.
350
+ def info?
351
+ @level <= ::Logger::INFO
352
+ end
353
+
354
+ ##
355
+ # Returns `true` if the current severity level allows for sending `WARN`
356
+ # messages.
357
+ def warn?
358
+ @level <= ::Logger::WARN
359
+ end
360
+
361
+ ##
362
+ # Returns `true` if the current severity level allows for sending
363
+ # `ERROR` messages.
364
+ def error?
365
+ @level <= ::Logger::ERROR
366
+ end
367
+
368
+ ##
369
+ # Returns `true` if the current severity level allows for sending
370
+ # `FATAL` messages.
371
+ def fatal?
372
+ @level <= ::Logger::FATAL
373
+ end
374
+
375
+ ##
376
+ # Returns `true` if the current severity level allows for sending
377
+ # `UNKNOWN` messages.
378
+ def unknown?
379
+ @level <= ::Logger::UNKNOWN
380
+ end
381
+
382
+ ##
383
+ # Sets the logging severity level.
384
+ #
385
+ # @param [Integer, String, Symbol] severity the integer code for or the
386
+ # name of the severity level
387
+ #
388
+ # @example
389
+ # require "google/cloud/logging"
390
+ #
391
+ # logging = Google::Cloud::Logging.new
392
+ #
393
+ # resource = logging.resource "gae_app",
394
+ # module_id: "1",
395
+ # version_id: "20150925t173233"
396
+ #
397
+ # logger = logging.logger "my_app_log", resource, env: :production
398
+ #
399
+ # logger.level = "INFO"
400
+ # logger.debug "Job started." # No log entry written
401
+ #
402
+ def level= severity
403
+ new_level = derive_severity severity
404
+ if new_level.nil?
405
+ raise ArgumentError, "invalid log level: #{severity}"
406
+ end
407
+ @level = new_level
408
+ end
409
+ alias sev_threshold= level=
410
+ alias local_level= level=
411
+
412
+ ##
413
+ # Close the logging "device". This effectively disables logging from
414
+ # this logger; any further log messages will be silently ignored. The
415
+ # logger may be re-enabled by calling #reopen.
416
+ #
417
+ def close
418
+ @closed = true
419
+ self
420
+ end
421
+
422
+ ##
423
+ # Re-enable logging if the logger has been closed.
424
+ #
425
+ # Note that this method accepts a "logdev" argument for compatibility
426
+ # with the standard Ruby Logger class; however, this argument is
427
+ # ignored because this logger does not use a log device.
428
+ #
429
+ def reopen _logdev = nil
430
+ @closed = false
431
+ self
432
+ end
433
+
434
+ ##
435
+ # Track a given trace_id by associating it with the current
436
+ # Thread
437
+ #
438
+ # @deprecated Use add_request_info
439
+ #
440
+ def add_trace_id trace_id
441
+ add_request_info trace_id: trace_id
442
+ end
443
+
444
+ ##
445
+ # Associate request data with the current Thread. You may provide
446
+ # either the individual pieces of data (trace ID, log name) or a
447
+ # populated RequestInfo object.
448
+ #
449
+ # @param [RequestInfo] info Info about the current request. Optional.
450
+ # If not present, a new RequestInfo is created using the remaining
451
+ # parameters.
452
+ # @param [String, nil] trace_id The trace ID, or `nil` if no trace ID
453
+ # should be logged.
454
+ # @param [String, nil] log_name The log name to use, or nil to use
455
+ # this logger's default.
456
+ # @param [Hash, nil] env The request's Rack environment or `nil` if not
457
+ # available.
458
+ #
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
462
+
463
+ @request_info_var.value = info
464
+
465
+ info
466
+ end
467
+
468
+ ##
469
+ # Get the request data for the current Thread
470
+ #
471
+ # @return [RequestInfo, nil] The request data for the current thread,
472
+ # or `nil` if there is no data set.
473
+ #
474
+ def request_info
475
+ @request_info_var.value
476
+ end
477
+
478
+ ##
479
+ # Untrack the RequestInfo that's associated with current Thread
480
+ #
481
+ # @return [RequestInfo] The info that's being deleted
482
+ #
483
+ def delete_request_info
484
+ @request_info_var.value = nil
485
+ end
486
+
487
+ ##
488
+ # @deprecated Use delete_request_info
489
+ alias delete_trace_id delete_request_info
490
+
491
+ ##
492
+ # No-op method. Created to match the spec of ActiveSupport::Logger#flush
493
+ # method when used in Rails application.
494
+ def flush
495
+ self
496
+ end
497
+
498
+ ##
499
+ # Filter out low severity messages within block.
500
+ #
501
+ # @param [Integer] temp_level Severity threshold to filter within the
502
+ # block. Messages with lower severity will be blocked. Default
503
+ # ::Logger::ERROR
504
+ #
505
+ # @example
506
+ # require "google/cloud/logging"
507
+ #
508
+ # logging = Google::Cloud::Logging.new
509
+ #
510
+ # resource = logging.resource "gae_app",
511
+ # module_id: "1",
512
+ # version_id: "20150925t173233"
513
+ #
514
+ # logger = logging.logger "my_app_log", resource, env: :production
515
+ #
516
+ # logger.silence do
517
+ # logger.info "Info message" # No log entry written
518
+ # logger.error "Error message" # Log entry written
519
+ # end
520
+ def silence temp_level = ::Logger::ERROR
521
+ if silencer
522
+ begin
523
+ old_level = level
524
+ self.level = temp_level
525
+
526
+ yield self
527
+ ensure
528
+ self.level = old_level
529
+ end
530
+ else
531
+ yield self
532
+ end
533
+ end
534
+
535
+ protected
536
+
537
+ ##
538
+ # @private Write a log entry to the Stackdriver Logging service.
539
+ def write_entry severity, message
540
+ entry = Entry.new.tap do |e|
541
+ e.timestamp = Time.now
542
+ e.severity = gcloud_severity severity
543
+ e.payload = message
544
+ end
545
+
546
+ actual_log_name = log_name
547
+ info = request_info
548
+ if info
549
+ actual_log_name = info.log_name || actual_log_name
550
+ unless info.trace_id.nil? || @project.nil?
551
+ entry.trace = "projects/#{@project}/traces/#{info.trace_id}"
552
+ end
553
+ entry.trace_sampled = info.trace_sampled if entry.trace_sampled.nil?
554
+ end
555
+
556
+ writer.write_entries entry, log_name: actual_log_name,
557
+ resource: resource,
558
+ labels: entry_labels(info)
559
+ end
560
+
561
+ ##
562
+ # @private generate the labels hash for a log entry.
563
+ def entry_labels info
564
+ merged_labels = {}
565
+
566
+ if info && !info.trace_id.nil?
567
+ merged_labels["traceId"] = info.trace_id
568
+ if Google::Cloud.env.app_engine?
569
+ merged_labels["appengine.googleapis.com/trace_id"] = info.trace_id
570
+ end
571
+ end
572
+
573
+ request_env = info && info.env || {}
574
+
575
+ compute_labels(request_env).merge merged_labels
576
+ end
577
+
578
+ ##
579
+ # @private Get the logger level number from severity value object.
580
+ def derive_severity severity
581
+ return severity if severity.is_a? Integer
582
+
583
+ downcase_severity = severity.to_s.downcase
584
+ case downcase_severity
585
+ when "debug".freeze then ::Logger::DEBUG
586
+ when "info".freeze then ::Logger::INFO
587
+ when "warn".freeze then ::Logger::WARN
588
+ when "error".freeze then ::Logger::ERROR
589
+ when "fatal".freeze then ::Logger::FATAL
590
+ when "unknown".freeze then ::Logger::UNKNOWN
591
+ end
592
+ end
593
+
594
+ ##
595
+ # @private Get Google Cloud deverity from logger level number.
596
+ def gcloud_severity severity_int
597
+ %i[DEBUG INFO WARNING ERROR CRITICAL DEFAULT][severity_int]
598
+ rescue StandardError
599
+ :DEFAULT
600
+ end
601
+
602
+ ##
603
+ # @private Get current thread id
604
+ def current_thread_id
605
+ Thread.current.object_id
606
+ end
607
+
608
+ private
609
+
610
+ ##
611
+ # @private Compute values for labels
612
+ def compute_labels request_env
613
+ Hash[
614
+ labels.map do |k, value_or_proc|
615
+ [k, compute_label_value(request_env, value_or_proc)]
616
+ end
617
+ ]
618
+ end
619
+
620
+ ##
621
+ # @private Compute individual label value.
622
+ # Value can be a Proc (function of the request env) or a static value.
623
+ def compute_label_value request_env, value_or_proc
624
+ if value_or_proc.respond_to? :call
625
+ value_or_proc.call request_env
626
+ else
627
+ value_or_proc
628
+ end
629
+ end
630
+ end
631
+ end
632
+ end
633
+ end