google-cloud-logging 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.yardopts +18 -0
- data/AUTHENTICATION.md +178 -0
- data/CHANGELOG.md +407 -0
- data/CODE_OF_CONDUCT.md +40 -0
- data/CONTRIBUTING.md +188 -0
- data/INSTRUMENTATION.md +71 -0
- data/LICENSE +201 -0
- data/LOGGING.md +32 -0
- data/OVERVIEW.md +321 -0
- data/TROUBLESHOOTING.md +31 -0
- data/lib/google-cloud-logging.rb +161 -0
- data/lib/google/cloud/logging.rb +188 -0
- data/lib/google/cloud/logging/async_writer.rb +513 -0
- data/lib/google/cloud/logging/convert.rb +70 -0
- data/lib/google/cloud/logging/credentials.rb +44 -0
- data/lib/google/cloud/logging/entry.rb +528 -0
- data/lib/google/cloud/logging/entry/http_request.rb +167 -0
- data/lib/google/cloud/logging/entry/list.rb +178 -0
- data/lib/google/cloud/logging/entry/operation.rb +91 -0
- data/lib/google/cloud/logging/entry/source_location.rb +85 -0
- data/lib/google/cloud/logging/errors.rb +101 -0
- data/lib/google/cloud/logging/log/list.rb +156 -0
- data/lib/google/cloud/logging/logger.rb +633 -0
- data/lib/google/cloud/logging/metric.rb +168 -0
- data/lib/google/cloud/logging/metric/list.rb +170 -0
- data/lib/google/cloud/logging/middleware.rb +307 -0
- data/lib/google/cloud/logging/project.rb +838 -0
- data/lib/google/cloud/logging/rails.rb +232 -0
- data/lib/google/cloud/logging/resource.rb +85 -0
- data/lib/google/cloud/logging/resource_descriptor.rb +137 -0
- data/lib/google/cloud/logging/resource_descriptor/list.rb +175 -0
- data/lib/google/cloud/logging/service.rb +239 -0
- data/lib/google/cloud/logging/sink.rb +315 -0
- data/lib/google/cloud/logging/sink/list.rb +168 -0
- data/lib/google/cloud/logging/version.rb +22 -0
- 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
|