exceptionhandler 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/exceptionhandler.rb +113 -0
- metadata +84 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 692e4a01778c53380866d74732449d718f662745
|
4
|
+
data.tar.gz: 2e4499d00e7297f06907b7843c4ddf5ddcb184a8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4a2f46721280c3c7ba3f7c4a60bced301387da991770714072f13a38aa823b0af52294dd625d52a98fd01ef1bbb7848f73489db43ce4ba0f2ed96370440e8741
|
7
|
+
data.tar.gz: f339a472ad74f9e275fa94c36e425cbcb0300fd47459221770e6c0b8dfe859cb631dee4feea81740878fd1d8bb9c5faf94ab55d08c29bb140eaefd698091ff21
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'unirest'
|
3
|
+
require 'httpclient'
|
4
|
+
|
5
|
+
|
6
|
+
class ExceptionHandler
|
7
|
+
|
8
|
+
def initialize()
|
9
|
+
#Get the cluster name from Google metadata service
|
10
|
+
cluster_name="unknown_cluster"
|
11
|
+
begin
|
12
|
+
response = Unirest.get('http://metadata.google.internal/computeMetadata/v1/instance/attributes/cluster-name',headers:{ "Metadata-Flavor" => "Google"})
|
13
|
+
if response.code == 200
|
14
|
+
cluster_name=response.body
|
15
|
+
end
|
16
|
+
rescue
|
17
|
+
p "Couldn't determine cluster name."
|
18
|
+
end
|
19
|
+
|
20
|
+
#Grap the rest of the details from tags
|
21
|
+
environment = ENV['environment'] ? ENV['environment'] : "unknown_env"
|
22
|
+
app = ENV['DEIS_APP'] ? ENV['DEIS_APP'] : "unknown_app"
|
23
|
+
release = ENV['WORKFLOW_RELEASE'] ? ENV['WORKFLOW_RELEASE'] : "unknown_release"
|
24
|
+
|
25
|
+
@request_body_base = {:application => app, :version => release, :environment => environment, :cluster => cluster_name, :token => ENV['EXCEPTION_TOKEN']}
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(options)
|
29
|
+
if !options[:exception].nil?
|
30
|
+
|
31
|
+
trace_chain = trace_chain(options[:exception])
|
32
|
+
puts "Exception Caught ("+options[:exception].class.name+"): " + trace_chain.to_s
|
33
|
+
|
34
|
+
excep = options[:exception].class.name
|
35
|
+
backtrace = "#{ options[:exception].message } (#{ options[:exception].class })\n" <<
|
36
|
+
(options[:exception].backtrace || []).join("\n")
|
37
|
+
|
38
|
+
if ENV['EXCEPTION_URL']
|
39
|
+
excep = options[:exception].class.name
|
40
|
+
backtrace = "#{ options[:exception].message } (#{ options[:exception].class })\n" <<
|
41
|
+
(options[:exception].backtrace || []).join("\n")
|
42
|
+
|
43
|
+
# Create a hash id from the exception class and the stacktrace to identify unique occurences of the same exception class
|
44
|
+
hash_id = Digest::SHA256.hexdigest "#{options[:exception].class} #{options[:exception].backtrace}"
|
45
|
+
|
46
|
+
request_body = @request_body_base
|
47
|
+
request_body[:timestamp] = Time.now
|
48
|
+
request_body[:id] = hash_id
|
49
|
+
request_body[:exception] = excep
|
50
|
+
request_body[:detail] = backtrace
|
51
|
+
|
52
|
+
clnt = HTTPClient.new()
|
53
|
+
clnt.post_async("#{ENV['EXCEPTION_URL']}/exception", request_body)
|
54
|
+
end
|
55
|
+
|
56
|
+
else
|
57
|
+
puts options
|
58
|
+
end
|
59
|
+
|
60
|
+
#The whole point of this handler is to replace rollbar, so raise this exception to prevent trying to send to rollbar
|
61
|
+
raise Rollbar::Ignore
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def trace_chain(exception)
|
66
|
+
traces = [trace_data(exception)]
|
67
|
+
visited = [exception]
|
68
|
+
current_exception = exception
|
69
|
+
|
70
|
+
while current_exception.respond_to?(:cause) && (cause = current_exception.cause) && cause.is_a?(Exception) && !visited.include?(cause)
|
71
|
+
traces << trace_data(cause)
|
72
|
+
visited << cause
|
73
|
+
current_exception = cause
|
74
|
+
end
|
75
|
+
|
76
|
+
traces
|
77
|
+
end
|
78
|
+
|
79
|
+
def trace_data(current_exception)
|
80
|
+
frames = reduce_frames(current_exception)
|
81
|
+
# reverse so that the order is as rollbar expects
|
82
|
+
frames.reverse!
|
83
|
+
|
84
|
+
{
|
85
|
+
:frames => frames,
|
86
|
+
:exception => {
|
87
|
+
:class => current_exception.class.name,
|
88
|
+
:message => current_exception.message
|
89
|
+
}
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
def reduce_frames(current_exception)
|
94
|
+
exception_backtrace(current_exception).map do |frame|
|
95
|
+
# parse the line
|
96
|
+
match = frame.match(/(.*):(\d+)(?::in `([^']+)')?/)
|
97
|
+
|
98
|
+
if match
|
99
|
+
{ :filename => match[1], :lineno => match[2].to_i, :method => match[3] }
|
100
|
+
else
|
101
|
+
{ :filename => '<unknown>', :lineno => 0, :method => frame }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def exception_backtrace(current_exception)
|
107
|
+
return [] if current_exception.nil?
|
108
|
+
return current_exception.backtrace if current_exception.backtrace.respond_to?(:map)
|
109
|
+
return []
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: exceptionhandler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matt Knox
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httpclient
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.8'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.8.2.2
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.8'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.8.2.2
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: unirest
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.1'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.1.2
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '1.1'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.1.2
|
53
|
+
description: Log exceptions in a log friendly way.
|
54
|
+
email: matt.knox@sphero.com
|
55
|
+
executables: []
|
56
|
+
extensions: []
|
57
|
+
extra_rdoc_files: []
|
58
|
+
files:
|
59
|
+
- lib/exceptionhandler.rb
|
60
|
+
homepage:
|
61
|
+
licenses:
|
62
|
+
- MIT
|
63
|
+
metadata: {}
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 2.5.1
|
81
|
+
signing_key:
|
82
|
+
specification_version: 4
|
83
|
+
summary: Log exceptions in a log friendly way.
|
84
|
+
test_files: []
|