google-cloud-error_reporting 0.24.0 → 0.25.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +87 -60
- data/lib/google-cloud-error_reporting.rb +93 -5
- data/lib/google/cloud/error_reporting.rb +238 -0
- data/lib/google/cloud/error_reporting/credentials.rb +41 -0
- data/lib/google/cloud/error_reporting/error_event.rb +313 -0
- data/lib/google/cloud/error_reporting/middleware.rb +84 -183
- data/lib/google/cloud/error_reporting/project.rb +224 -0
- data/lib/google/cloud/error_reporting/rails.rb +97 -127
- data/lib/google/cloud/error_reporting/service.rb +118 -0
- data/lib/google/cloud/error_reporting/version.rb +22 -0
- metadata +61 -13
@@ -0,0 +1,41 @@
|
|
1
|
+
# Copyright 2017 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
require "google/cloud/credentials"
|
17
|
+
|
18
|
+
module Google
|
19
|
+
module Cloud
|
20
|
+
module ErrorReporting
|
21
|
+
##
|
22
|
+
# @private Represents the OAuth 2.0 signing logic for ErrorReporting.
|
23
|
+
class Credentials < Google::Cloud::Credentials
|
24
|
+
SCOPE = ["https://www.googleapis.com/auth/cloud-platform"]
|
25
|
+
PATH_ENV_VARS = %w(ERROR_REPORTING_KEYFILE GOOGLE_CLOUD_KEYFILE)
|
26
|
+
JSON_ENV_VARS =
|
27
|
+
%w(ERROR_REPORTING_KEYFILE_JSON GOOGLE_CLOUD_KEYFILE_JSON)
|
28
|
+
|
29
|
+
##
|
30
|
+
# @private Create credentials with given scope and/or keyfile.
|
31
|
+
def self.credentials_with_scope keyfile, scope = nil
|
32
|
+
if keyfile.nil?
|
33
|
+
default(scope: scope)
|
34
|
+
else
|
35
|
+
new(keyfile, scope: scope)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,313 @@
|
|
1
|
+
# Copyright 2017 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
module Google
|
17
|
+
module Cloud
|
18
|
+
module ErrorReporting
|
19
|
+
##
|
20
|
+
# # ErrorEvent
|
21
|
+
#
|
22
|
+
# An individual error event to report to Stackdriver Error Reporting
|
23
|
+
# service.
|
24
|
+
#
|
25
|
+
# Google::Cloud::ErrorReporting::ErrorEvent is able to be transformed
|
26
|
+
# into
|
27
|
+
# {Google::Devtools::Clouderrorreporting::V1beta1::ReportedErrorEvent}
|
28
|
+
# gRPC structure. Once an error event is reported, the GCP
|
29
|
+
# Stackdriver ErrorReporting service is able to parse the message and
|
30
|
+
# backtrace, then group the error events by content.
|
31
|
+
#
|
32
|
+
# @see https://cloud.google.com/error-reporting/reference/rest/v1beta1/projects.events
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# require "google/cloud/error_reporting"
|
36
|
+
#
|
37
|
+
# error_reporting = Google::Cloud::ErrorReporting.new
|
38
|
+
#
|
39
|
+
# error_event = error_reporting.error_event "Error with Backtrace",
|
40
|
+
# timestamp: Time.now,
|
41
|
+
# service_name: "my_app_name",
|
42
|
+
# service_version: "v8"
|
43
|
+
# error_reporting.report error_event
|
44
|
+
#
|
45
|
+
class ErrorEvent
|
46
|
+
##
|
47
|
+
# Time when the event occurred. If not provided, the time when the event
|
48
|
+
# was received by the Error Reporting system will be used.
|
49
|
+
attr_accessor :event_time
|
50
|
+
|
51
|
+
##
|
52
|
+
# A message describing the error. The message can contain an exception
|
53
|
+
# stack in one of the supported programming languages and formats. In
|
54
|
+
# that case, the message is parsed and detailed exception information is
|
55
|
+
# returned when retrieving the error event again.
|
56
|
+
attr_accessor :message
|
57
|
+
|
58
|
+
##
|
59
|
+
# An identifier of the service, such as the name of the executable, job,
|
60
|
+
# or Google App Engine service name. This field is expected to have a
|
61
|
+
# low number of values that are relatively stable over time, as opposed
|
62
|
+
# to version, which can be changed whenever new code is deployed.
|
63
|
+
attr_accessor :service_name
|
64
|
+
|
65
|
+
##
|
66
|
+
# Represents the source code version that the developer provided, which
|
67
|
+
# could represent a version label or a Git SHA-1 hash, for example.
|
68
|
+
attr_accessor :service_version
|
69
|
+
|
70
|
+
##
|
71
|
+
# The type of HTTP request, such as GET, POST, etc.
|
72
|
+
attr_accessor :http_method
|
73
|
+
|
74
|
+
##
|
75
|
+
# The URL of the request.
|
76
|
+
attr_accessor :http_url
|
77
|
+
|
78
|
+
##
|
79
|
+
# The user agent information that is provided with the request.
|
80
|
+
attr_accessor :http_user_agent
|
81
|
+
|
82
|
+
##
|
83
|
+
# The referrer information that is provided with the request.
|
84
|
+
attr_accessor :http_referrer
|
85
|
+
|
86
|
+
##
|
87
|
+
# The HTTP response status code for the request.
|
88
|
+
attr_accessor :http_status
|
89
|
+
|
90
|
+
##
|
91
|
+
# The IP address from which the request originated. This can be IPv4,
|
92
|
+
# IPv6, or a token which is derived from the IP address, depending on
|
93
|
+
# the data that has been provided in the error report.
|
94
|
+
attr_accessor :http_remote_ip
|
95
|
+
|
96
|
+
##
|
97
|
+
# The user who caused or was affected by the crash. This can be a user
|
98
|
+
# ID, an email address, or an arbitrary token that uniquely identifies
|
99
|
+
# the user. When sending an error report, leave this field empty if the
|
100
|
+
# user was not logged in. In this case the Error Reporting system will
|
101
|
+
# use other data, such as remote IP address, to distinguish affected
|
102
|
+
# users. See affectedUsersCount in ErrorGroupStats.
|
103
|
+
attr_accessor :user
|
104
|
+
|
105
|
+
##
|
106
|
+
# The source code filename, which can include a truncated relative path,
|
107
|
+
# or a full path from a production machine.
|
108
|
+
attr_accessor :file_path
|
109
|
+
|
110
|
+
##
|
111
|
+
# 1-based. 0 indicates that the line number is unknown.
|
112
|
+
attr_accessor :line_number
|
113
|
+
|
114
|
+
##
|
115
|
+
# Human-readable name of a function or method. The value can include
|
116
|
+
# optional context like the class or package name. For example,
|
117
|
+
# my.package.MyClass.method in case of Java.
|
118
|
+
attr_accessor :function_name
|
119
|
+
|
120
|
+
##
|
121
|
+
# Build a new ErrorEvent from a
|
122
|
+
# Google::Devtools::Clouderrorreporting::V1beta1::ReportedErrorEvent
|
123
|
+
# object.
|
124
|
+
#
|
125
|
+
# @param [
|
126
|
+
# Google::Devtools::Clouderrorreporting::V1beta1::ReportedErrorEvent]
|
127
|
+
# grpc A
|
128
|
+
# Google::Devtools::Clouderrorreporting::V1beta1::ReportedErrorEvent
|
129
|
+
# object
|
130
|
+
#
|
131
|
+
# @return [ErrorEvent] A new ErrorEvent instance derived from given grpc
|
132
|
+
# object
|
133
|
+
#
|
134
|
+
def self.from_grpc grpc
|
135
|
+
return new if grpc.nil?
|
136
|
+
new.tap do |event|
|
137
|
+
event.event_time = extract_timestamp grpc.event_time
|
138
|
+
event.message = grpc.message
|
139
|
+
|
140
|
+
extract_service_context event, grpc.service_context
|
141
|
+
extract_error_context event, grpc.context
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
##
|
146
|
+
# @private Get a Time object from a Google::Protobuf::Timestamp object.
|
147
|
+
#
|
148
|
+
# @param [Google::Protobuf::Timestamp] timestamp_grpc A protobuf
|
149
|
+
# Timestamp object
|
150
|
+
#
|
151
|
+
# @return [Time] The time object derived from input grpc timestamp
|
152
|
+
#
|
153
|
+
def self.extract_timestamp timestamp_grpc
|
154
|
+
return nil if timestamp_grpc.nil?
|
155
|
+
Time.at timestamp_grpc.seconds, Rational(timestamp_grpc.nanos, 1000)
|
156
|
+
end
|
157
|
+
|
158
|
+
##
|
159
|
+
# @private Extract service context info from gRPC into an ErrorEvent.
|
160
|
+
def self.extract_service_context error_event, service_context_grpc
|
161
|
+
return nil if service_context_grpc.nil?
|
162
|
+
|
163
|
+
error_event.service_name = service_context_grpc.service
|
164
|
+
error_event.service_version = service_context_grpc.version
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# @private Extract error context info from gRPC into an ErrorEvent.
|
169
|
+
def self.extract_error_context error_event, error_context_grpc
|
170
|
+
return nil if error_context_grpc.nil?
|
171
|
+
|
172
|
+
error_event.user = error_context_grpc.user
|
173
|
+
extract_http_request error_event, error_context_grpc.http_request
|
174
|
+
extract_source_location error_event,
|
175
|
+
error_context_grpc.report_location
|
176
|
+
end
|
177
|
+
|
178
|
+
##
|
179
|
+
# @private Extract http request info from gRPC into an ErrorEvent.
|
180
|
+
def self.extract_http_request error_event, http_request_grpc
|
181
|
+
return nil if http_request_grpc.nil?
|
182
|
+
|
183
|
+
error_event.http_method = http_request_grpc["method"]
|
184
|
+
error_event.http_url = http_request_grpc.url
|
185
|
+
error_event.http_user_agent = http_request_grpc.user_agent
|
186
|
+
error_event.http_referrer = http_request_grpc.referrer
|
187
|
+
error_event.http_status = http_request_grpc.response_status_code
|
188
|
+
error_event.http_remote_ip = http_request_grpc.remote_ip
|
189
|
+
end
|
190
|
+
|
191
|
+
##
|
192
|
+
# @private Extract source location info from gRPC into an ErrorEvent.
|
193
|
+
def self.extract_source_location error_event, source_location_grpc
|
194
|
+
return nil if source_location_grpc.nil?
|
195
|
+
|
196
|
+
error_event.file_path = source_location_grpc.file_path
|
197
|
+
error_event.line_number = source_location_grpc.line_number
|
198
|
+
error_event.function_name = source_location_grpc.function_name
|
199
|
+
end
|
200
|
+
|
201
|
+
private_class_method :extract_timestamp,
|
202
|
+
:extract_service_context,
|
203
|
+
:extract_error_context,
|
204
|
+
:extract_http_request,
|
205
|
+
:extract_source_location
|
206
|
+
|
207
|
+
##
|
208
|
+
# Construct an ErrorEvent object based on a given exception.
|
209
|
+
#
|
210
|
+
# @param [Exception] exception A Ruby exception.
|
211
|
+
#
|
212
|
+
# @return [ErrorEvent] An ErrorEvent object containing information
|
213
|
+
# from the given exception.
|
214
|
+
def self.from_exception exception
|
215
|
+
backtrace = exception.backtrace
|
216
|
+
message = exception.message
|
217
|
+
|
218
|
+
unless backtrace.nil?
|
219
|
+
error_location = backtrace.first
|
220
|
+
|
221
|
+
message = "#{error_location}: #{message} (#{exception.class})\n\t" +
|
222
|
+
backtrace.drop(1).join("\n\t")
|
223
|
+
file_path, line_number, function_name = error_location.split(":")
|
224
|
+
function_name = function_name.to_s[/`(.*)'/, 1]
|
225
|
+
end
|
226
|
+
|
227
|
+
new.tap do |e|
|
228
|
+
e.message = message
|
229
|
+
e.file_path = file_path
|
230
|
+
e.line_number = line_number.to_i
|
231
|
+
e.function_name = function_name
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
##
|
236
|
+
# Convert ErrorEvent object to gRPC struct.
|
237
|
+
#
|
238
|
+
# @return [Devtools::Clouderrorreporting::V1beta1::ReportedErrorEvent]
|
239
|
+
# gRPC struct that represent an ErrorEvent.
|
240
|
+
def to_grpc
|
241
|
+
error_event_hash = {
|
242
|
+
event_time: event_time_hash,
|
243
|
+
message: message,
|
244
|
+
service_context: service_context_hash,
|
245
|
+
context: error_context_hash
|
246
|
+
}.delete_if { |_, v| v.nil? }
|
247
|
+
|
248
|
+
grpc_class =
|
249
|
+
Devtools::Clouderrorreporting::V1beta1::ReportedErrorEvent
|
250
|
+
grpc_class.decode_json error_event_hash.to_json
|
251
|
+
end
|
252
|
+
|
253
|
+
private
|
254
|
+
|
255
|
+
##
|
256
|
+
# @private Formats the event_time as the hash representation of
|
257
|
+
# Google::Protobuf::Timestamp struct.
|
258
|
+
#
|
259
|
+
def event_time_hash
|
260
|
+
return nil if event_time.nil?
|
261
|
+
{
|
262
|
+
seconds: event_time.to_i,
|
263
|
+
nanos: event_time.nsec
|
264
|
+
}
|
265
|
+
end
|
266
|
+
|
267
|
+
##
|
268
|
+
# @private Formats the service_name and service_version as the hash
|
269
|
+
# representation of
|
270
|
+
# Google::Devtools::Clouderrorreporting::V1beta1::SourceContext struct.
|
271
|
+
#
|
272
|
+
def service_context_hash
|
273
|
+
return nil if !service_name && !service_version
|
274
|
+
{
|
275
|
+
service: service_name,
|
276
|
+
version: service_version
|
277
|
+
}.delete_if { |_, v| v.nil? }
|
278
|
+
end
|
279
|
+
|
280
|
+
##
|
281
|
+
# @private Formats the error context info as the hash
|
282
|
+
# representation of
|
283
|
+
# Google::Devtools::Clouderrorreporting::V1beta1::ErrorContext struct.
|
284
|
+
#
|
285
|
+
def error_context_hash
|
286
|
+
http_request_hash = {
|
287
|
+
method: http_method,
|
288
|
+
url: http_url,
|
289
|
+
user_agent: http_user_agent,
|
290
|
+
referrer: http_referrer,
|
291
|
+
response_status_code: http_status,
|
292
|
+
remote_ip: http_remote_ip
|
293
|
+
}.delete_if { |_, v| v.nil? }
|
294
|
+
|
295
|
+
source_location_hash = {
|
296
|
+
file_path: file_path,
|
297
|
+
line_number: line_number,
|
298
|
+
function_name: function_name
|
299
|
+
}.delete_if { |_, v| v.nil? }
|
300
|
+
|
301
|
+
result = {
|
302
|
+
http_request: http_request_hash.empty? ? nil : http_request_hash,
|
303
|
+
user: user,
|
304
|
+
report_location:
|
305
|
+
source_location_hash.empty? ? nil : source_location_hash
|
306
|
+
}.delete_if { |_, v| v.nil? }
|
307
|
+
|
308
|
+
result.empty? ? nil : result
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
@@ -13,69 +13,51 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
|
16
|
-
require "google/cloud/env"
|
17
|
-
require "google/cloud/error_reporting/v1beta1"
|
18
|
-
require "rack"
|
19
|
-
require "rack/request"
|
20
|
-
|
21
16
|
module Google
|
22
17
|
module Cloud
|
23
18
|
module ErrorReporting
|
24
19
|
##
|
25
|
-
# Middleware
|
20
|
+
# # Middleware
|
26
21
|
#
|
27
22
|
# Google::Cloud::ErrorReporting::Middleware defines a Rack Middleware
|
28
23
|
# that can automatically catch upstream exceptions and report them
|
29
24
|
# to Stackdriver Error Reporting.
|
30
25
|
#
|
31
26
|
class Middleware
|
32
|
-
|
33
|
-
|
27
|
+
# A Google::Cloud::ErrorReporting::Project client used to report
|
28
|
+
# error events.
|
29
|
+
attr_reader :error_reporting
|
34
30
|
|
35
31
|
##
|
36
|
-
# Construct a new instance of Middleware
|
32
|
+
# Construct a new instance of Middleware.
|
37
33
|
#
|
38
|
-
# @param [Rack
|
39
|
-
# @param [
|
40
|
-
# Google::Cloud::ErrorReporting::
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
# @param [String] service_name Name of the service. Default to
|
47
|
-
# ENV["ERROR_REPORTING_SERVICE"] then "ruby". Automatically discovered
|
48
|
-
# if on GAE
|
49
|
-
# @param [String] service_version Version of the service. Optional.
|
50
|
-
# ENV["ERROR_REPORTING_VERSION"]. Automatically discovered if on GAE
|
51
|
-
# @param [Array<Class>] ignore_classes A single or an array of Exception
|
52
|
-
# classes to ignore
|
34
|
+
# @param [Rack::Application] app The Rack application
|
35
|
+
# @param [Google::Cloud::ErrorReporting::Project] error_reporting A
|
36
|
+
# Google::Cloud::ErrorReporting::Project client for reporting
|
37
|
+
# exceptions
|
38
|
+
# @param [Hash] *kwargs Hash of configuration settings. Used for
|
39
|
+
# backward API compatibility. See the [Configuration
|
40
|
+
# Guide](https://googlecloudplatform.github.io/google-cloud-ruby/#/docs/stackdriver/guides/instrumentation_configuration)
|
41
|
+
# for the prefered way to set configuration parameters.
|
53
42
|
#
|
54
43
|
# @return [Google::Cloud::ErrorReporting::Middleware] A new instance of
|
55
44
|
# Middleware
|
56
45
|
#
|
57
|
-
def initialize app,
|
58
|
-
|
59
|
-
|
60
|
-
service_name: nil,
|
61
|
-
service_version: nil,
|
62
|
-
ignore_classes: nil
|
46
|
+
def initialize app, error_reporting: nil, **kwargs
|
47
|
+
require "rack"
|
48
|
+
require "rack/request"
|
63
49
|
@app = app
|
64
|
-
@error_reporting = error_reporting
|
65
|
-
@service_name = service_name ||
|
66
|
-
ENV["ERROR_REPORTING_SERVICE"] ||
|
67
|
-
Google::Cloud.env.app_engine_service_id ||
|
68
|
-
"ruby"
|
69
|
-
@service_version = service_version ||
|
70
|
-
ENV["ERROR_REPORTING_VERSION"] ||
|
71
|
-
Google::Cloud.env.app_engine_service_version
|
72
|
-
@ignore_classes = Array(ignore_classes)
|
73
|
-
@project_id = project_id ||
|
74
|
-
ENV["ERROR_REPORTING_PROJECT"] ||
|
75
|
-
ENV["GOOGLE_CLOUD_PROJECT"] ||
|
76
|
-
Google::Cloud.env.project_id
|
77
50
|
|
78
|
-
|
51
|
+
load_config kwargs
|
52
|
+
|
53
|
+
@error_reporting =
|
54
|
+
error_reporting ||
|
55
|
+
ErrorReporting.new(project: configuration.project_id,
|
56
|
+
keyfile: configuration.keyfile)
|
57
|
+
|
58
|
+
# Set module default client to reuse the same client. Update module
|
59
|
+
# configuration parameters.
|
60
|
+
ErrorReporting.class_variable_set :@@default_client, @error_reporting
|
79
61
|
end
|
80
62
|
|
81
63
|
##
|
@@ -116,23 +98,22 @@ module Google
|
|
116
98
|
#
|
117
99
|
def report_exception env, exception
|
118
100
|
# Do not any exceptions that's specified by the ignore_classes list.
|
119
|
-
return if ignore_classes.include? exception.class
|
101
|
+
return if configuration.ignore_classes.include? exception.class
|
120
102
|
|
121
|
-
|
103
|
+
error_event = error_event_from_exception env, exception
|
122
104
|
|
123
105
|
# If this exception maps to a HTTP status code less than 500, do
|
124
106
|
# not report it.
|
125
|
-
status_code =
|
126
|
-
error_event_grpc.context.http_request.response_status_code.to_i
|
107
|
+
status_code = error_event.http_status.to_i
|
127
108
|
return if status_code > 0 && status_code < 500
|
128
109
|
|
129
|
-
error_reporting.
|
110
|
+
error_reporting.report error_event
|
130
111
|
end
|
131
112
|
|
132
113
|
##
|
133
|
-
# Creates a
|
134
|
-
#
|
135
|
-
# headers.
|
114
|
+
# Creates a {Google::Cloud::ErrorReporting::ErrorEvent} based on the
|
115
|
+
# exception. Fill in the HttpRequestContext section of the ErrorEvent
|
116
|
+
# based on the HTTP Request headers.
|
136
117
|
#
|
137
118
|
# When used in Rails environment. It replies on
|
138
119
|
# ActionDispatch::ExceptionWrapper class to derive a HTTP status code
|
@@ -141,56 +122,74 @@ module Google
|
|
141
122
|
# @param [Hash] env Rack environment hash
|
142
123
|
# @param [Exception] exception Exception to convert from
|
143
124
|
#
|
144
|
-
# @return [
|
145
|
-
#
|
146
|
-
# The gRPC ReportedErrorEvent object that's based
|
147
|
-
# on given exception
|
125
|
+
# @return [Google::Cloud::ErrorReporting::ErrorEvent] The gRPC
|
126
|
+
# ErrorEvent object that's based on given env and exception
|
148
127
|
#
|
149
|
-
def
|
150
|
-
error_event = ErrorEvent.from_exception exception
|
128
|
+
def error_event_from_exception env, exception
|
129
|
+
error_event = ErrorReporting::ErrorEvent.from_exception exception
|
151
130
|
|
152
131
|
# Inject service_context info into error_event object
|
153
|
-
error_event
|
154
|
-
|
155
|
-
version: service_version
|
156
|
-
}.delete_if { |_, v| v.nil? }
|
132
|
+
error_event.service_name = configuration.service_name
|
133
|
+
error_event.service_version = configuration.service_version
|
157
134
|
|
158
135
|
# Inject http_request_context info into error_event object
|
159
136
|
rack_request = Rack::Request.new env
|
160
|
-
error_event
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
error_event.to_grpc
|
137
|
+
error_event.http_method = rack_request.request_method
|
138
|
+
error_event.http_url = rack_request.url
|
139
|
+
error_event.http_user_agent = rack_request.user_agent
|
140
|
+
error_event.http_referrer = rack_request.referrer
|
141
|
+
error_event.http_status = http_status(exception)
|
142
|
+
error_event.http_remote_ip = rack_request.ip
|
143
|
+
|
144
|
+
error_event
|
170
145
|
end
|
171
146
|
|
147
|
+
private
|
148
|
+
|
172
149
|
##
|
173
|
-
#
|
174
|
-
#
|
175
|
-
#
|
176
|
-
#
|
177
|
-
|
178
|
-
|
179
|
-
|
150
|
+
# Consolidate configurations from various sources. Also set
|
151
|
+
# instrumentation config parameters to default values if not set
|
152
|
+
# already.
|
153
|
+
#
|
154
|
+
def load_config **kwargs
|
155
|
+
configuration.project_id = kwargs[:project_id] ||
|
156
|
+
configuration.project_id
|
157
|
+
configuration.keyfile = kwargs[:keyfile] ||
|
158
|
+
configuration.keyfile
|
159
|
+
configuration.service_name = kwargs[:service_name] ||
|
160
|
+
configuration.service_name
|
161
|
+
configuration.service_version = kwargs[:service_version] ||
|
162
|
+
configuration.service_version
|
163
|
+
configuration.ignore_classes = kwargs[:ignore_classes] ||
|
164
|
+
configuration.ignore_classes
|
165
|
+
|
166
|
+
init_default_config
|
180
167
|
end
|
181
168
|
|
182
|
-
|
169
|
+
##
|
170
|
+
# Fallback to default configuration values if not defined already
|
171
|
+
def init_default_config
|
172
|
+
configuration.project_id ||= Cloud.configure.project_id ||
|
173
|
+
ErrorReporting::Project.default_project
|
174
|
+
configuration.keyfile ||= Cloud.configure.keyfile
|
175
|
+
configuration.service_name ||=
|
176
|
+
ErrorReporting::Project.default_service_name
|
177
|
+
|
178
|
+
configuration.service_version ||=
|
179
|
+
ErrorReporting::Project.default_service_version
|
180
|
+
configuration.ignore_classes = Array(configuration.ignore_classes)
|
181
|
+
end
|
183
182
|
|
184
183
|
##
|
185
184
|
# Helper method to derive HTTP status code base on exception class in
|
186
|
-
# Rails. Returns nil if not in Rails environment
|
185
|
+
# Rails. Returns nil if not in Rails environment.
|
187
186
|
#
|
188
187
|
# @param [Exception] exception An Ruby exception
|
189
188
|
#
|
190
189
|
# @return [Integer] A number that represents HTTP status code or nil if
|
191
190
|
# status code can't be determined
|
192
191
|
#
|
193
|
-
def
|
192
|
+
def http_status exception
|
194
193
|
http_status = nil
|
195
194
|
if defined?(ActionDispatch::ExceptionWrapper) &&
|
196
195
|
ActionDispatch::ExceptionWrapper.respond_to?(
|
@@ -206,108 +205,10 @@ module Google
|
|
206
205
|
end
|
207
206
|
|
208
207
|
##
|
209
|
-
#
|
210
|
-
|
211
|
-
|
212
|
-
# Internal data structure mirroring gRPC ReportedErrorEvent structure
|
213
|
-
attr_reader :hash
|
214
|
-
|
215
|
-
##
|
216
|
-
# Construct a new ErrorEvent object
|
217
|
-
#
|
218
|
-
# @return [ErrorEvent] A new ErrorEvent object
|
219
|
-
def initialize
|
220
|
-
@hash = {}
|
221
|
-
end
|
222
|
-
|
223
|
-
##
|
224
|
-
# Construct an ErrorEvent object based on a given exception
|
225
|
-
#
|
226
|
-
# @param [Exception] exception A Ruby exception
|
227
|
-
#
|
228
|
-
# @return [ErrorEvent] An ErrorEvent object containing information
|
229
|
-
# from the given exception
|
230
|
-
def self.from_exception exception
|
231
|
-
exception_data = extract_exception exception
|
232
|
-
|
233
|
-
# Build error_context hash
|
234
|
-
error_context = {
|
235
|
-
user: ENV["USER"],
|
236
|
-
report_location: {
|
237
|
-
file_path: exception_data[:file_path],
|
238
|
-
function_name: exception_data[:function_name],
|
239
|
-
line_number: exception_data[:line_number].to_i
|
240
|
-
}.delete_if { |_, v| v.nil? }
|
241
|
-
}.delete_if { |_, v| v.nil? }
|
242
|
-
|
243
|
-
# Build error_event hash
|
244
|
-
error_event = ErrorEvent.new
|
245
|
-
t = Time.now
|
246
|
-
error_event.hash.merge!({
|
247
|
-
event_time: {
|
248
|
-
seconds: t.to_i,
|
249
|
-
nanos: t.nsec
|
250
|
-
},
|
251
|
-
message: exception_data[:message],
|
252
|
-
context: error_context
|
253
|
-
}.delete_if { |_, v| v.nil? })
|
254
|
-
|
255
|
-
error_event
|
256
|
-
end
|
257
|
-
|
258
|
-
##
|
259
|
-
# Helper method extract data from exception
|
260
|
-
#
|
261
|
-
# @param [Exception] exception A Ruby Exception
|
262
|
-
#
|
263
|
-
# @return [Hash] A hash containing formatted error message with
|
264
|
-
# backtrace, file_path, line_number, and function_name
|
265
|
-
def self.extract_exception exception
|
266
|
-
if exception.backtrace.nil? || exception.backtrace.empty?
|
267
|
-
message = exception.message
|
268
|
-
else
|
269
|
-
message = "#{exception.backtrace.first}: #{exception.message} " \
|
270
|
-
"(#{exception.class})\n\t" +
|
271
|
-
exception.backtrace.drop(1).join("\n\t")
|
272
|
-
file_path, line_number, function_name =
|
273
|
-
exception.backtrace.first.split(":")
|
274
|
-
function_name = function_name.to_s[/`(.*)'/, 1]
|
275
|
-
end
|
276
|
-
|
277
|
-
{
|
278
|
-
message: message,
|
279
|
-
file_path: file_path,
|
280
|
-
line_number: line_number,
|
281
|
-
function_name: function_name
|
282
|
-
}
|
283
|
-
end
|
284
|
-
private_class_method :extract_exception
|
285
|
-
|
286
|
-
##
|
287
|
-
# Get the value of the given key from internal hash
|
288
|
-
def [] key
|
289
|
-
hash[key]
|
290
|
-
end
|
291
|
-
|
292
|
-
##
|
293
|
-
# Write new value with the key in internal hash
|
294
|
-
def []= key, value
|
295
|
-
hash[key] = value
|
296
|
-
end
|
297
|
-
|
298
|
-
##
|
299
|
-
# Convert ErrorEvent object to gRPC struct
|
300
|
-
#
|
301
|
-
# @return [Devtools::Clouderrorreporting::V1beta1::ReportedErrorEvent]
|
302
|
-
# gRPC struct that represent an ErrorEvent
|
303
|
-
def to_grpc
|
304
|
-
grpc_module =
|
305
|
-
Devtools::Clouderrorreporting::V1beta1::ReportedErrorEvent
|
306
|
-
grpc_module.decode_json hash.to_json
|
307
|
-
end
|
208
|
+
# @private Get Google::Cloud::ErrorReporting.configure
|
209
|
+
def configuration
|
210
|
+
Google::Cloud::ErrorReporting.configure
|
308
211
|
end
|
309
|
-
|
310
|
-
private_constant :ErrorEvent
|
311
212
|
end
|
312
213
|
end
|
313
214
|
end
|