backtraceio 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/backtraceio.rb +175 -0
  3. metadata +45 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a8ea87a4910899d828fcaeed57759aa4ac97c6e2d502b5d9926733781b29dce1
4
+ data.tar.gz: e8634b05a9cbef7786efbb6e1a4a8b7c60c8ed388ba75bf699f5716dd4b45c41
5
+ SHA512:
6
+ metadata.gz: 4cca2963e0b73bbd932d7bafc05d6c27eefe2626c875f5c03989cac79b78bde0e41b8950f6acf106805ee122a8d9b5ff7737409ae17d5f29b5f918ec7c65d420
7
+ data.tar.gz: a64d0aa3d5aebab4930f4cdb0aa5a521fbaeebe428047e453648ff71063ebc39279d64590fb2b4e3fad2200aee6c77a7090955d2fc781de7022d6959273ac3a0
@@ -0,0 +1,175 @@
1
+ require 'json'
2
+ require 'securerandom'
3
+ require 'socket'
4
+ require 'time'
5
+ require 'uri'
6
+ require 'net/http'
7
+ require 'net/https'
8
+
9
+ module BacktraceIO
10
+
11
+ class SubmissionTarget
12
+
13
+ @@token = ''
14
+ @@url = ''
15
+
16
+ def initialize(token, url)
17
+ @token = token
18
+ @url = url
19
+ end
20
+
21
+ def submit(processed, ignoreSSL=false)
22
+ uri = URI.parse(@url)
23
+ uri.query = "format=json&token=" + @token
24
+ uri.path = "/api/post"
25
+ req = Net::HTTP::Post.new(uri.request_uri, "Content-Type"=>"application/json")
26
+ req.body = processed.to_json
27
+ http = Net::HTTP.new(uri.host, uri.port)
28
+ http.use_ssl = uri.scheme == "https"
29
+ if ignoreSSL
30
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
31
+ end
32
+ http.request(req)
33
+ end
34
+
35
+ def self.token
36
+ @@token
37
+ end
38
+
39
+ def self.token=(token)
40
+ @@token = token
41
+ end
42
+
43
+ def self.url
44
+ @@url
45
+ end
46
+
47
+ def self.url=(url)
48
+ @@url = url
49
+ end
50
+ end
51
+
52
+ class Report
53
+
54
+ attr_accessor :uuid
55
+ attr_accessor :timestamp
56
+ attr_accessor :threads
57
+ attr_accessor :mainThread
58
+ attr_accessor :attributes
59
+ attr_accessor :annotations
60
+ attr_accessor :lang
61
+ attr_accessor :langVersion
62
+ attr_accessor :agent
63
+ attr_accessor :agentVersion
64
+ attr_accessor :sourceCode
65
+
66
+ def initialize
67
+ self.uuid = SecureRandom.uuid
68
+ self.timestamp = Time.now.to_i
69
+ self.sourceCode = {}
70
+
71
+ self.threads = Thread.list.map do |t|
72
+ processed = process_thread t
73
+ [processed[:name], processed]
74
+ end.to_h
75
+
76
+ self.mainThread = "main"
77
+
78
+ self.attributes = {}
79
+ self.annotations = {}
80
+
81
+ add_default_attributes
82
+
83
+ self.lang = 'ruby'
84
+ self.langVersion = RUBY_VERSION
85
+ self.agent = 'backtrace-ruby'
86
+ self.agentVersion = '0.1.0'
87
+ end
88
+
89
+ def to_hash
90
+ fields = [
91
+ :uuid, :timestamp, :lang, :langVersion, :agent, :agentVersion,
92
+ :mainThread, :threads, :attributes, :annotations, :sourceCode
93
+ ]
94
+ fields.map{ |sym| [sym, self.send(sym)] }.to_h
95
+ end
96
+
97
+ def to_json
98
+ self.to_hash.to_json
99
+ end
100
+
101
+ def get_source_code_for_location(bl)
102
+ lines = File.read(bl.path).each_line.to_a
103
+ min = [bl.lineno-20, 0].max
104
+ max = [bl.lineno+20, lines.size].min
105
+ text = lines[min..max].join
106
+
107
+ if lines.all?{ |l| l =~ /^\s*$/ }
108
+ p text
109
+ return nil
110
+ end
111
+
112
+ self.sourceCode[bl.object_id] = {
113
+ text: text,
114
+ startLine: min+1,
115
+ startColumn: 1,
116
+ startPos: 0,
117
+ path: bl.path,
118
+ }
119
+
120
+ bl.object_id
121
+ end
122
+
123
+ def make_thread_callstack(t)
124
+ t.backtrace_locations.map do |bl|
125
+ data = {
126
+ funcName: bl.base_label,
127
+ line: bl.lineno.to_s,
128
+ library: bl.path,
129
+ }
130
+ source = get_source_code_for_location bl
131
+ data[:sourceCode] = source if source
132
+ data
133
+ end
134
+ end
135
+
136
+ def process_thread(t)
137
+ name = t == Thread.main ? 'main' : t.object_id.to_s
138
+ fault = Thread.current == t or t.status == nil
139
+
140
+ {
141
+ name: name,
142
+ fault: fault,
143
+ stack: make_thread_callstack(t),
144
+ }
145
+ end
146
+
147
+ def add_exception_data(e)
148
+ t = Thread.current
149
+ thread_name = name = t == Thread.main ? 'main' : t.object_id.to_s
150
+
151
+ self.threads[thread_name][:stack] = make_thread_callstack e
152
+ end
153
+
154
+ def add_default_attributes
155
+ self.attributes['application'] = $0
156
+ self.attributes['hostname'] = Socket.gethostname
157
+ end
158
+ end
159
+
160
+ def BacktraceIO.register_error_handler(token, url)
161
+ SubmissionTarget.token = token
162
+ SubmissionTarget.url = url
163
+
164
+ at_exit do
165
+ if $! and $!.class != SystemExit
166
+ ex = $!
167
+ report = BacktraceIO::Report.new
168
+ report.add_exception_data ex
169
+ st = SubmissionTarget.new SubmissionTarget.token, SubmissionTarget.url
170
+ st.submit report.to_hash
171
+ end
172
+ end
173
+ end
174
+
175
+ end
metadata ADDED
@@ -0,0 +1,45 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: backtraceio
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Will Andrews
8
+ - Ian Rice
9
+ - Paweł Zakrzewski
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2018-06-21 00:00:00.000000000 Z
14
+ dependencies: []
15
+ description: Backtrace I/O integration
16
+ email: team@backtrace.io
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/backtraceio.rb
22
+ homepage: https://github.com/backtrace-labs/backtrace-ruby
23
+ licenses:
24
+ - MIT
25
+ metadata: {}
26
+ post_install_message:
27
+ rdoc_options: []
28
+ require_paths:
29
+ - lib
30
+ required_ruby_version: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ requirements: []
41
+ rubygems_version: 3.1.2
42
+ signing_key:
43
+ specification_version: 4
44
+ summary: Backtrace I/O integration
45
+ test_files: []