bugsnag 6.2.0 → 6.3.0.beta.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/bugsnag.rb +10 -2
- data/lib/bugsnag/configuration.rb +8 -1
- data/lib/bugsnag/delivery/synchronous.rb +107 -6
- data/lib/bugsnag/delivery/thread_queue.rb +2 -2
- data/lib/bugsnag/helpers.rb +24 -0
- data/lib/bugsnag/integrations/rack.rb +1 -0
- data/lib/bugsnag/integrations/rails/controller_methods.rb +1 -0
- data/lib/bugsnag/middleware/session_data.rb +21 -0
- data/lib/bugsnag/report.rb +12 -3
- data/lib/bugsnag/session_tracker.rb +157 -0
- data/spec/configuration_spec.rb +5 -0
- data/spec/integrations/sidekiq_spec.rb +1 -1
- data/spec/middleware_spec.rb +10 -10
- data/spec/rack_spec.rb +2 -2
- data/spec/rails3_request_spec.rb +2 -2
- data/spec/report_spec.rb +61 -61
- data/spec/session_tracker_spec.rb +153 -0
- data/spec/spec_helper.rb +17 -1
- data/spec/stacktrace_spec.rb +5 -5
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0643f03a70da437fa3983ee21f1f9ec4466085e
|
4
|
+
data.tar.gz: bdcdb50f10d93babed837ad0f6ec3ad174c765b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d4341b5a7e9566d16c4f9fee869d570824ee89a8092260f54c19791984241f163237beb564622850cb163479f5dff81d34860917f91f16eb639461bcca755f7
|
7
|
+
data.tar.gz: 541e02bf501da119d9ddb4acde6ca3df1c2805c4513c7ab201a837d5d18e54a9eefbf95205fa5dd433b0f811d56c801fec3b53d871a696e9c7b8738db1b12c35
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
6.
|
1
|
+
6.3.0.beta.0
|
data/lib/bugsnag.rb
CHANGED
@@ -7,6 +7,7 @@ require "bugsnag/meta_data"
|
|
7
7
|
require "bugsnag/report"
|
8
8
|
require "bugsnag/cleaner"
|
9
9
|
require "bugsnag/helpers"
|
10
|
+
require "bugsnag/session_tracker"
|
10
11
|
|
11
12
|
require "bugsnag/delivery"
|
12
13
|
require "bugsnag/delivery/synchronous"
|
@@ -38,6 +39,8 @@ module Bugsnag
|
|
38
39
|
configuration.warn("No valid API key has been set, notifications will not be sent")
|
39
40
|
@key_warning = true
|
40
41
|
end
|
42
|
+
|
43
|
+
session_tracker.config = configuration
|
41
44
|
end
|
42
45
|
|
43
46
|
# Explicitly notify of an exception
|
@@ -108,8 +111,8 @@ module Bugsnag
|
|
108
111
|
|
109
112
|
# Deliver
|
110
113
|
configuration.info("Notifying #{configuration.endpoint} of #{report.exceptions.last[:errorClass]}")
|
111
|
-
|
112
|
-
Bugsnag::Delivery[configuration.delivery_method].deliver(configuration.endpoint,
|
114
|
+
options = {:headers => report.headers, :trim_payload => true}
|
115
|
+
Bugsnag::Delivery[configuration.delivery_method].deliver(configuration.endpoint, report.as_json, configuration, options)
|
113
116
|
end
|
114
117
|
end
|
115
118
|
|
@@ -119,6 +122,11 @@ module Bugsnag
|
|
119
122
|
@configuration || LOCK.synchronize { @configuration ||= Bugsnag::Configuration.new }
|
120
123
|
end
|
121
124
|
|
125
|
+
def session_tracker
|
126
|
+
@session_tracker = nil unless defined?(@session_tracker)
|
127
|
+
@session_tracker || LOCK.synchronize { @session_tracker ||= Bugsnag::SessionTracker.new(configuration)}
|
128
|
+
end
|
129
|
+
|
122
130
|
# Allow access to "before notify" callbacks
|
123
131
|
def before_notify_callbacks
|
124
132
|
Bugsnag.configuration.request_data[:before_callbacks] ||= []
|
@@ -7,6 +7,7 @@ require "bugsnag/middleware/exception_meta_data"
|
|
7
7
|
require "bugsnag/middleware/ignore_error_class"
|
8
8
|
require "bugsnag/middleware/suggestion_data"
|
9
9
|
require "bugsnag/middleware/classify_error"
|
10
|
+
require "bugsnag/middleware/session_data"
|
10
11
|
|
11
12
|
module Bugsnag
|
12
13
|
class Configuration
|
@@ -22,7 +23,7 @@ module Bugsnag
|
|
22
23
|
attr_accessor :app_type
|
23
24
|
attr_accessor :meta_data_filters
|
24
25
|
attr_accessor :endpoint
|
25
|
-
attr_accessor :logger
|
26
|
+
attr_accessor :logger
|
26
27
|
attr_accessor :middleware
|
27
28
|
attr_accessor :internal_middleware
|
28
29
|
attr_accessor :proxy_host
|
@@ -32,10 +33,13 @@ module Bugsnag
|
|
32
33
|
attr_accessor :timeout
|
33
34
|
attr_accessor :hostname
|
34
35
|
attr_accessor :ignore_classes
|
36
|
+
attr_accessor :track_sessions
|
37
|
+
attr_accessor :session_endpoint
|
35
38
|
|
36
39
|
API_KEY_REGEX = /[0-9a-f]{32}/i
|
37
40
|
THREAD_LOCAL_NAME = "bugsnag_req_data"
|
38
41
|
DEFAULT_ENDPOINT = "https://notify.bugsnag.com"
|
42
|
+
DEFAULT_SESSION_ENDPOINT = "https://sessions.bugsnag.com"
|
39
43
|
|
40
44
|
DEFAULT_META_DATA_FILTERS = [
|
41
45
|
/authorization/i,
|
@@ -57,6 +61,8 @@ module Bugsnag
|
|
57
61
|
self.hostname = default_hostname
|
58
62
|
self.timeout = 15
|
59
63
|
self.notify_release_stages = nil
|
64
|
+
self.track_sessions = false
|
65
|
+
self.session_endpoint = DEFAULT_SESSION_ENDPOINT
|
60
66
|
|
61
67
|
# SystemExit and Interrupt are common Exception types seen with successful
|
62
68
|
# exits and are not automatically reported to Bugsnag
|
@@ -81,6 +87,7 @@ module Bugsnag
|
|
81
87
|
self.internal_middleware.use Bugsnag::Middleware::IgnoreErrorClass
|
82
88
|
self.internal_middleware.use Bugsnag::Middleware::SuggestionData
|
83
89
|
self.internal_middleware.use Bugsnag::Middleware::ClassifyError
|
90
|
+
self.internal_middleware.use Bugsnag::Middleware::SessionData
|
84
91
|
|
85
92
|
self.middleware = Bugsnag::MiddlewareStack.new
|
86
93
|
self.middleware.use Bugsnag::Middleware::Callbacks
|
@@ -4,13 +4,19 @@ require "uri"
|
|
4
4
|
module Bugsnag
|
5
5
|
module Delivery
|
6
6
|
class Synchronous
|
7
|
-
|
7
|
+
BACKOFF_THREADS = {}
|
8
|
+
BACKOFF_REQUESTS = {}
|
9
|
+
BACKOFF_LOCK = Mutex.new
|
8
10
|
|
9
11
|
class << self
|
10
|
-
def deliver(url, body, configuration)
|
12
|
+
def deliver(url, body, configuration, options={})
|
11
13
|
begin
|
12
|
-
response = request(url, body, configuration)
|
14
|
+
response = request(url, body, configuration, options)
|
13
15
|
configuration.debug("Request to #{url} completed, status: #{response.code}")
|
16
|
+
success = options[:success] || '200'
|
17
|
+
if options[:backoff] && !(response.code == success)
|
18
|
+
backoff(url, body, configuration, options)
|
19
|
+
end
|
14
20
|
rescue StandardError => e
|
15
21
|
# KLUDGE: Since we don't re-raise http exceptions, this breaks rspec
|
16
22
|
raise if e.class.to_s == "RSpec::Expectations::ExpectationNotMetError"
|
@@ -22,9 +28,14 @@ module Bugsnag
|
|
22
28
|
|
23
29
|
private
|
24
30
|
|
25
|
-
def request(url, body, configuration)
|
31
|
+
def request(url, body, configuration, options)
|
26
32
|
uri = URI.parse(url)
|
27
33
|
|
34
|
+
if options[:trim_payload]
|
35
|
+
body = Bugsnag::Helpers.trim_if_needed(body)
|
36
|
+
end
|
37
|
+
payload = ::JSON.dump(body)
|
38
|
+
|
28
39
|
if configuration.proxy_host
|
29
40
|
http = Net::HTTP.new(uri.host, uri.port, configuration.proxy_host, configuration.proxy_port, configuration.proxy_user, configuration.proxy_password)
|
30
41
|
else
|
@@ -39,14 +50,104 @@ module Bugsnag
|
|
39
50
|
http.ca_file = configuration.ca_file if configuration.ca_file
|
40
51
|
end
|
41
52
|
|
42
|
-
|
43
|
-
|
53
|
+
headers = options.key?(:headers) ? options[:headers] : {}
|
54
|
+
headers.merge!(default_headers)
|
55
|
+
|
56
|
+
request = Net::HTTP::Post.new(path(uri), headers)
|
57
|
+
request.body = payload
|
58
|
+
|
44
59
|
http.request(request)
|
45
60
|
end
|
46
61
|
|
62
|
+
def backoff(url, body, configuration, options)
|
63
|
+
# Ensure we have the latest configuration for making these requests
|
64
|
+
@latest_configuration = configuration
|
65
|
+
|
66
|
+
BACKOFF_LOCK.lock
|
67
|
+
begin
|
68
|
+
# Define an exit function once to handle outstanding requests
|
69
|
+
@registered_at_exit = false unless defined?(@registered_at_exit)
|
70
|
+
if !@registered_at_exit
|
71
|
+
@registered_at_exit = true
|
72
|
+
at_exit do
|
73
|
+
backoff_exit
|
74
|
+
end
|
75
|
+
end
|
76
|
+
if BACKOFF_REQUESTS[url] && !BACKOFF_REQUESTS[url].empty?
|
77
|
+
last_request = BACKOFF_REQUESTS[url].last
|
78
|
+
new_body_length = ::JSON.dump(body).length
|
79
|
+
old_body_length = ::JSON.dump(last_request[:body]).length
|
80
|
+
if new_body_length + old_body_length >= Bugsnag::Helpers::MAX_PAYLOAD_LENGTH
|
81
|
+
BACKOFF_REQUESTS[url].push({:body => body, :options => options})
|
82
|
+
else
|
83
|
+
Bugsnag::Helpers::deep_merge!(last_request, {:body => body, :options => options})
|
84
|
+
end
|
85
|
+
else
|
86
|
+
BACKOFF_REQUESTS[url] = [{:body => body, :options => options}]
|
87
|
+
end
|
88
|
+
if !(BACKOFF_THREADS[url] && BACKOFF_THREADS[url].status)
|
89
|
+
spawn_backoff_thread(url)
|
90
|
+
end
|
91
|
+
ensure
|
92
|
+
BACKOFF_LOCK.unlock
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def backoff_exit
|
97
|
+
# Kill existing threads
|
98
|
+
BACKOFF_THREADS.each do |url, thread|
|
99
|
+
thread.exit
|
100
|
+
end
|
101
|
+
# Retry outstanding requests once, then exit
|
102
|
+
BACKOFF_REQUESTS.each do |url, requests|
|
103
|
+
requests.map! do |req|
|
104
|
+
response = request(url, req[:body], @latest_configuration, req[:options])
|
105
|
+
success = req[:options][:success] || '200'
|
106
|
+
response.code == success
|
107
|
+
end
|
108
|
+
requests.reject! { |i| i }
|
109
|
+
@latest_configuration.warn("Requests to #{url} finished, #{requests.size} failed")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def spawn_backoff_thread(url)
|
114
|
+
new_thread = Thread.new(url) do |url|
|
115
|
+
interval = 2
|
116
|
+
while BACKOFF_REQUESTS[url].size > 0
|
117
|
+
sleep(interval)
|
118
|
+
interval = interval * 2
|
119
|
+
interval = 600 if interval > 600
|
120
|
+
BACKOFF_LOCK.lock
|
121
|
+
begin
|
122
|
+
BACKOFF_REQUESTS[url].map! do |req|
|
123
|
+
response = request(url, req[:body], @latest_configuration, req[:options])
|
124
|
+
success = req[:options][:success] || '200'
|
125
|
+
if response.code == success
|
126
|
+
@latest_configuration.debug("Request to #{url} completed, status: #{response.code}")
|
127
|
+
false
|
128
|
+
else
|
129
|
+
req
|
130
|
+
end
|
131
|
+
end
|
132
|
+
BACKOFF_REQUESTS[url].reject! { |i| !i }
|
133
|
+
ensure
|
134
|
+
BACKOFF_LOCK.unlock
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
BACKOFF_THREADS[url] = new_thread
|
139
|
+
end
|
140
|
+
|
47
141
|
def path(uri)
|
48
142
|
uri.path == "" ? "/" : uri.path
|
49
143
|
end
|
144
|
+
|
145
|
+
def default_headers
|
146
|
+
{
|
147
|
+
"Content-Type" => "application/json",
|
148
|
+
"Bugsnag-Sent-At" => Time.now().utc().strftime('%Y-%m-%dT%H:%M:%S')
|
149
|
+
}
|
150
|
+
end
|
50
151
|
end
|
51
152
|
end
|
52
153
|
end
|
@@ -8,7 +8,7 @@ module Bugsnag
|
|
8
8
|
MUTEX = Mutex.new
|
9
9
|
|
10
10
|
class << self
|
11
|
-
def deliver(url, body, configuration)
|
11
|
+
def deliver(url, body, configuration, options={})
|
12
12
|
@configuration = configuration
|
13
13
|
|
14
14
|
start_once!
|
@@ -19,7 +19,7 @@ module Bugsnag
|
|
19
19
|
end
|
20
20
|
|
21
21
|
# Add delivery to the worker thread
|
22
|
-
@queue.push proc { super(url, body, configuration) }
|
22
|
+
@queue.push proc { super(url, body, configuration, options) }
|
23
23
|
end
|
24
24
|
|
25
25
|
private
|
data/lib/bugsnag/helpers.rb
CHANGED
@@ -23,6 +23,30 @@ module Bugsnag
|
|
23
23
|
remove_metadata_from_events(reduced_value)
|
24
24
|
end
|
25
25
|
|
26
|
+
def self.deep_merge(l_hash, r_hash)
|
27
|
+
l_hash.merge(r_hash) do |key, l_val, r_val|
|
28
|
+
if l_val.is_a?(Hash) && r_val.is_a?(Hash)
|
29
|
+
deep_merge(l_val, r_val)
|
30
|
+
elsif l_val.is_a?(Array) && r_val.is_a?(Array)
|
31
|
+
l_val.concat(r_val)
|
32
|
+
else
|
33
|
+
r_val
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.deep_merge!(l_hash, r_hash)
|
39
|
+
l_hash.merge!(r_hash) do |key, l_val, r_val|
|
40
|
+
if l_val.is_a?(Hash) && r_val.is_a?(Hash)
|
41
|
+
deep_merge(l_val, r_val)
|
42
|
+
elsif l_val.is_a?(Array) && r_val.is_a?(Array)
|
43
|
+
l_val.concat(r_val)
|
44
|
+
else
|
45
|
+
r_val
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
26
50
|
private
|
27
51
|
|
28
52
|
TRUNCATION_INFO = '[TRUNCATED]'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Bugsnag::Middleware
|
2
|
+
class SessionData
|
3
|
+
def initialize(bugsnag)
|
4
|
+
@bugsnag = bugsnag
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(report)
|
8
|
+
session = Bugsnag::SessionTracker.get_current_session
|
9
|
+
unless session.nil?
|
10
|
+
if report.unhandled
|
11
|
+
session[:events][:unhandled] += 1
|
12
|
+
else
|
13
|
+
session[:events][:handled] += 1
|
14
|
+
end
|
15
|
+
report.session = session
|
16
|
+
end
|
17
|
+
|
18
|
+
@bugsnag.call(report)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/bugsnag/report.rb
CHANGED
@@ -17,8 +17,9 @@ module Bugsnag
|
|
17
17
|
|
18
18
|
MAX_EXCEPTIONS_TO_UNWRAP = 5
|
19
19
|
|
20
|
-
CURRENT_PAYLOAD_VERSION = "
|
20
|
+
CURRENT_PAYLOAD_VERSION = "4.0"
|
21
21
|
|
22
|
+
attr_reader :unhandled
|
22
23
|
attr_accessor :api_key
|
23
24
|
attr_accessor :app_type
|
24
25
|
attr_accessor :app_version
|
@@ -31,6 +32,7 @@ module Bugsnag
|
|
31
32
|
attr_accessor :meta_data
|
32
33
|
attr_accessor :raw_exceptions
|
33
34
|
attr_accessor :release_stage
|
35
|
+
attr_accessor :session
|
34
36
|
attr_accessor :severity
|
35
37
|
attr_accessor :severity_reason
|
36
38
|
attr_accessor :user
|
@@ -92,7 +94,7 @@ module Bugsnag
|
|
92
94
|
},
|
93
95
|
exceptions: exceptions,
|
94
96
|
groupingHash: grouping_hash,
|
95
|
-
|
97
|
+
session: session,
|
96
98
|
severity: severity,
|
97
99
|
severityReason: severity_reason,
|
98
100
|
unhandled: @unhandled,
|
@@ -108,7 +110,6 @@ module Bugsnag
|
|
108
110
|
|
109
111
|
# return the payload hash
|
110
112
|
{
|
111
|
-
:apiKey => api_key,
|
112
113
|
:notifier => {
|
113
114
|
:name => NOTIFIER_NAME,
|
114
115
|
:version => NOTIFIER_VERSION,
|
@@ -118,6 +119,14 @@ module Bugsnag
|
|
118
119
|
}
|
119
120
|
end
|
120
121
|
|
122
|
+
def headers
|
123
|
+
{
|
124
|
+
"Bugsnag-Api-Key" => api_key,
|
125
|
+
"Bugsnag-Payload-Version" => CURRENT_PAYLOAD_VERSION,
|
126
|
+
"Bugsnag-Sent-At" => Time.now().utc().strftime('%Y-%m-%dT%H:%M:%S')
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
121
130
|
def ignore?
|
122
131
|
@should_ignore
|
123
132
|
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'time'
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
module Bugsnag
|
6
|
+
class SessionTracker
|
7
|
+
|
8
|
+
THREAD_SESSION = "bugsnag_session"
|
9
|
+
TIME_THRESHOLD = 60
|
10
|
+
FALLBACK_TIME = 300
|
11
|
+
MAXIMUM_SESSION_COUNT = 50
|
12
|
+
SESSION_PAYLOAD_VERSION = "1.0"
|
13
|
+
|
14
|
+
attr_reader :session_counts
|
15
|
+
attr_writer :config
|
16
|
+
|
17
|
+
def self.set_current_session(session)
|
18
|
+
Thread.current[THREAD_SESSION] = session
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.get_current_session
|
22
|
+
Thread.current[THREAD_SESSION]
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(configuration)
|
26
|
+
@session_counts = {}
|
27
|
+
@config = configuration
|
28
|
+
@mutex = Mutex.new
|
29
|
+
@last_sent = Time.now
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_session
|
33
|
+
return unless @config.track_sessions
|
34
|
+
start_time = Time.now().utc().strftime('%Y-%m-%dT%H:%M:00')
|
35
|
+
new_session = {
|
36
|
+
:id => SecureRandom.uuid,
|
37
|
+
:startedAt => start_time,
|
38
|
+
:events => {
|
39
|
+
:handled => 0,
|
40
|
+
:unhandled => 0
|
41
|
+
}
|
42
|
+
}
|
43
|
+
SessionTracker.set_current_session(new_session)
|
44
|
+
add_thread = Thread.new { add_session(start_time) }
|
45
|
+
add_thread.join()
|
46
|
+
end
|
47
|
+
|
48
|
+
def send_sessions
|
49
|
+
@mutex.lock
|
50
|
+
begin
|
51
|
+
deliver_sessions
|
52
|
+
ensure
|
53
|
+
@mutex.unlock
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def add_session(min)
|
59
|
+
@mutex.lock
|
60
|
+
begin
|
61
|
+
@registered_at_exit = false unless defined?(@registered_at_exit)
|
62
|
+
if !@registered_at_exit
|
63
|
+
@registered_at_exit = true
|
64
|
+
at_exit do
|
65
|
+
if !@deliver_fallback.nil? && @deliver_fallback.status == 'sleep'
|
66
|
+
@deliver_fallback.terminate
|
67
|
+
end
|
68
|
+
deliver_sessions
|
69
|
+
end
|
70
|
+
end
|
71
|
+
@session_counts[min] ||= 0
|
72
|
+
@session_counts[min] += 1
|
73
|
+
if Time.now() - @last_sent > TIME_THRESHOLD
|
74
|
+
deliver_sessions
|
75
|
+
end
|
76
|
+
ensure
|
77
|
+
@mutex.unlock
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def deliver_sessions
|
82
|
+
return unless @config.track_sessions
|
83
|
+
sessions = []
|
84
|
+
@session_counts.each do |min, count|
|
85
|
+
sessions << {
|
86
|
+
:startedAt => min,
|
87
|
+
:sessionsStarted => count
|
88
|
+
}
|
89
|
+
if sessions.size >= MAXIMUM_SESSION_COUNT
|
90
|
+
deliver(sessions)
|
91
|
+
sessions = []
|
92
|
+
end
|
93
|
+
end
|
94
|
+
@session_counts = {}
|
95
|
+
reset_delivery_thread
|
96
|
+
deliver(sessions)
|
97
|
+
end
|
98
|
+
|
99
|
+
def reset_delivery_thread
|
100
|
+
if !@deliver_fallback.nil? && @deliver_fallback.status == 'sleep'
|
101
|
+
@deliver_fallback.terminate
|
102
|
+
end
|
103
|
+
@deliver_fallback = Thread.new do
|
104
|
+
sleep(FALLBACK_TIME)
|
105
|
+
deliver_sessions
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def deliver(sessionCounts)
|
110
|
+
if sessionCounts.length == 0
|
111
|
+
@config.debug("No sessions to deliver")
|
112
|
+
return
|
113
|
+
end
|
114
|
+
|
115
|
+
if !@config.valid_api_key?
|
116
|
+
@config.debug("Not delivering sessions due to an invalid api_key")
|
117
|
+
return
|
118
|
+
end
|
119
|
+
|
120
|
+
if !@config.should_notify_release_stage?
|
121
|
+
@config.debug("Not delivering sessions due to notify_release_stages :#{@config.notify_release_stages.inspect}")
|
122
|
+
return
|
123
|
+
end
|
124
|
+
|
125
|
+
if @config.delivery_method != :thread_queue
|
126
|
+
@config.debug("Not delivering sessions due to asynchronous delivery being disabled")
|
127
|
+
return
|
128
|
+
end
|
129
|
+
|
130
|
+
payload = {
|
131
|
+
:notifier => {
|
132
|
+
:name => Bugsnag::Report::NOTIFIER_NAME,
|
133
|
+
:url => Bugsnag::Report::NOTIFIER_URL,
|
134
|
+
:version => Bugsnag::Report::NOTIFIER_VERSION
|
135
|
+
},
|
136
|
+
:device => {
|
137
|
+
:hostname => @config.hostname
|
138
|
+
},
|
139
|
+
:app => {
|
140
|
+
:version => @config.app_version,
|
141
|
+
:releaseStage => @config.release_stage,
|
142
|
+
:type => @config.app_type
|
143
|
+
},
|
144
|
+
:sessionCounts => sessionCounts
|
145
|
+
}
|
146
|
+
|
147
|
+
headers = {
|
148
|
+
"Bugsnag-Api-Key" => @config.api_key,
|
149
|
+
"Bugsnag-Payload-Version" => SESSION_PAYLOAD_VERSION
|
150
|
+
}
|
151
|
+
|
152
|
+
options = {:headers => headers, :backoff => true, :success => '202'}
|
153
|
+
@last_sent = Time.now
|
154
|
+
Bugsnag::Delivery[@config.delivery_method].deliver(@config.session_endpoint, payload, @config, options)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|