bugsnag 6.4.0 → 6.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +8 -0
 - 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 +6 -3
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 75340d844c86f98e0ef2519d4ca1416bf9de8ab8
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 7a384090af717661a8acdcd2e2b3184b138b77e9
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: eb256344706e647174e3dc9abac3376b7b3966c6f706fdb77dbaf2ae9c50527490d4ee591265a14a0787678f018affde73a0b3a5c7a30ea676da27bc7731612f
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 71b8138725c4b11278eafef1e9a02c61977fe4a6f0460684e582ca9276b1bc4d7841cd0130b643882e0fc7e640e0eb33df7456c6004f6bb5d3b1ee3c031bac0d
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,6 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            Changelog
         
     | 
| 
       2 
2 
     | 
    
         
             
            =========
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
      
 4 
     | 
    
         
            +
            ## 6.5.0 (04 Jan 2018)
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            ### Enhancements
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            * Adds support for tracking sessions and crash rate by setting the configuration option `configuration.track_sessions` to `true`.
         
     | 
| 
      
 9 
     | 
    
         
            +
              Sessions can be manually created using `Bugsnag.start_session`, and manually delivered using `Bugsnag.send_sessions`.
         
     | 
| 
      
 10 
     | 
    
         
            +
              | [#411](https://github.com/bugsnag/bugsnag-ruby/pull/411)
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
       4 
12 
     | 
    
         
             
            ## 6.4.0 (21 Dec 2017)
         
     | 
| 
       5 
13 
     | 
    
         | 
| 
       6 
14 
     | 
    
         
             
            ### Enhancements
         
     | 
    
        data/VERSION
    CHANGED
    
    | 
         @@ -1 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            6. 
     | 
| 
      
 1 
     | 
    
         
            +
            6.5.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
         
     | 
| 
         @@ -113,8 +116,8 @@ module Bugsnag 
     | 
|
| 
       113 
116 
     | 
    
         | 
| 
       114 
117 
     | 
    
         
             
                    # Deliver
         
     | 
| 
       115 
118 
     | 
    
         
             
                    configuration.info("Notifying #{configuration.endpoint} of #{report.exceptions.last[:errorClass]}")
         
     | 
| 
       116 
     | 
    
         
            -
                     
     | 
| 
       117 
     | 
    
         
            -
                    Bugsnag::Delivery[configuration.delivery_method].deliver(configuration.endpoint,  
     | 
| 
      
 119 
     | 
    
         
            +
                    options = {:headers => report.headers, :trim_payload => true}
         
     | 
| 
      
 120 
     | 
    
         
            +
                    Bugsnag::Delivery[configuration.delivery_method].deliver(configuration.endpoint, report.as_json, configuration, options)
         
     | 
| 
       118 
121 
     | 
    
         
             
                  end
         
     | 
| 
       119 
122 
     | 
    
         
             
                end
         
     | 
| 
       120 
123 
     | 
    
         | 
| 
         @@ -124,6 +127,11 @@ module Bugsnag 
     | 
|
| 
       124 
127 
     | 
    
         
             
                  @configuration || LOCK.synchronize { @configuration ||= Bugsnag::Configuration.new }
         
     | 
| 
       125 
128 
     | 
    
         
             
                end
         
     | 
| 
       126 
129 
     | 
    
         | 
| 
      
 130 
     | 
    
         
            +
                def session_tracker
         
     | 
| 
      
 131 
     | 
    
         
            +
                  @session_tracker = nil unless defined?(@session_tracker)
         
     | 
| 
      
 132 
     | 
    
         
            +
                  @session_tracker || LOCK.synchronize { @session_tracker ||= Bugsnag::SessionTracker.new(configuration)}
         
     | 
| 
      
 133 
     | 
    
         
            +
                end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
       127 
135 
     | 
    
         
             
                # Allow access to "before notify" callbacks
         
     | 
| 
       128 
136 
     | 
    
         
             
                def before_notify_callbacks
         
     | 
| 
       129 
137 
     | 
    
         
             
                  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
         
     |