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,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