raygun4ruby 3.2.6 → 4.0.1

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.
Files changed (232) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests.yml +48 -0
  3. data/.gitignore +22 -21
  4. data/.rspec +1 -1
  5. data/Appraisals +19 -0
  6. data/CHANGELOG.md +173 -133
  7. data/Gemfile +4 -4
  8. data/LICENSE.txt +22 -22
  9. data/README.md +430 -420
  10. data/Rakefile +32 -27
  11. data/examples/sinatras_raygun.rb +17 -17
  12. data/gemfiles/rails_6.gemfile +9 -0
  13. data/gemfiles/rails_7.gemfile +10 -0
  14. data/gemfiles/rails_7_sidekiq_6.gemfile +10 -0
  15. data/lib/generators/raygun/install_generator.rb +26 -26
  16. data/lib/raygun/affected_user.rb +59 -59
  17. data/lib/raygun/breadcrumbs/breadcrumb.rb +34 -34
  18. data/lib/raygun/breadcrumbs/store.rb +86 -86
  19. data/lib/raygun/breadcrumbs.rb +34 -34
  20. data/lib/raygun/client.rb +313 -308
  21. data/lib/raygun/configuration.rb +202 -194
  22. data/lib/raygun/demo_exception.rb +22 -22
  23. data/lib/raygun/error.rb +10 -10
  24. data/lib/raygun/error_subscriber.rb +25 -0
  25. data/lib/raygun/javascript_tracker.rb +42 -42
  26. data/lib/raygun/middleware/breadcrumbs_store_initializer.rb +19 -19
  27. data/lib/raygun/middleware/javascript_exception_tracking.rb +40 -32
  28. data/lib/raygun/middleware/rack_exception_interceptor.rb +18 -18
  29. data/lib/raygun/middleware/rails_insert_affected_user.rb +26 -26
  30. data/lib/raygun/railtie.rb +47 -39
  31. data/lib/raygun/services/apply_whitelist_filter_to_payload.rb +27 -27
  32. data/lib/raygun/sidekiq.rb +61 -71
  33. data/lib/raygun/version.rb +3 -3
  34. data/lib/raygun.rb +197 -179
  35. data/lib/raygun4ruby.rb +1 -1
  36. data/lib/resque/failure/raygun.rb +25 -25
  37. data/lib/tasks/raygun.tasks +7 -7
  38. data/raygun4ruby.gemspec +43 -45
  39. data/spec/features/javascript_spec.rb +48 -48
  40. data/spec/rails_applications/6.1.4/Gemfile +56 -0
  41. data/spec/{dummy/README.rdoc → rails_applications/6.1.4/README.md} +24 -28
  42. data/spec/{dummy → rails_applications/6.1.4}/Rakefile +6 -6
  43. data/spec/rails_applications/6.1.4/app/assets/config/manifest.js +2 -0
  44. data/spec/{dummy → rails_applications/6.1.4}/app/assets/images/.keep +0 -0
  45. data/spec/{dummy → rails_applications/6.1.4}/app/assets/stylesheets/application.css +15 -15
  46. data/spec/rails_applications/6.1.4/app/channels/application_cable/channel.rb +4 -0
  47. data/spec/rails_applications/6.1.4/app/channels/application_cable/connection.rb +4 -0
  48. data/spec/rails_applications/6.1.4/app/controllers/application_controller.rb +2 -0
  49. data/spec/{dummy → rails_applications/6.1.4}/app/controllers/concerns/.keep +0 -0
  50. data/spec/{dummy → rails_applications/6.1.4}/app/controllers/home_controller.rb +4 -4
  51. data/spec/{dummy → rails_applications/6.1.4}/app/helpers/application_helper.rb +2 -2
  52. data/spec/rails_applications/6.1.4/app/javascript/channels/consumer.js +6 -0
  53. data/spec/rails_applications/6.1.4/app/javascript/channels/index.js +5 -0
  54. data/spec/rails_applications/6.1.4/app/javascript/packs/application.js +13 -0
  55. data/spec/rails_applications/6.1.4/app/jobs/application_job.rb +7 -0
  56. data/spec/rails_applications/6.1.4/app/mailers/application_mailer.rb +4 -0
  57. data/spec/rails_applications/6.1.4/app/models/application_record.rb +3 -0
  58. data/spec/{dummy/app/mailers → rails_applications/6.1.4/app/models/concerns}/.keep +0 -0
  59. data/spec/{dummy → rails_applications/6.1.4}/app/views/home/index.html.erb +3 -3
  60. data/spec/{dummy → rails_applications/6.1.4}/app/views/home/index.json.erb +1 -1
  61. data/spec/rails_applications/6.1.4/app/views/layouts/application.html.erb +13 -0
  62. data/spec/rails_applications/6.1.4/app/views/layouts/mailer.html.erb +13 -0
  63. data/spec/rails_applications/6.1.4/app/views/layouts/mailer.text.erb +1 -0
  64. data/spec/rails_applications/6.1.4/bin/rails +5 -0
  65. data/spec/rails_applications/6.1.4/bin/rake +5 -0
  66. data/spec/rails_applications/6.1.4/bin/setup +36 -0
  67. data/spec/rails_applications/6.1.4/bin/spring +14 -0
  68. data/spec/rails_applications/6.1.4/bin/yarn +17 -0
  69. data/spec/rails_applications/6.1.4/config/application.rb +22 -0
  70. data/spec/rails_applications/6.1.4/config/boot.rb +3 -0
  71. data/spec/rails_applications/6.1.4/config/cable.yml +10 -0
  72. data/spec/rails_applications/6.1.4/config/credentials.yml.enc +1 -0
  73. data/spec/{dummy → rails_applications/6.1.4}/config/database.yml +25 -25
  74. data/spec/{dummy → rails_applications/6.1.4}/config/environment.rb +5 -5
  75. data/spec/rails_applications/6.1.4/config/environments/development.rb +76 -0
  76. data/spec/rails_applications/6.1.4/config/environments/production.rb +120 -0
  77. data/spec/rails_applications/6.1.4/config/environments/test.rb +60 -0
  78. data/spec/rails_applications/6.1.4/config/initializers/application_controller_renderer.rb +8 -0
  79. data/spec/rails_applications/6.1.4/config/initializers/assets.rb +14 -0
  80. data/spec/rails_applications/6.1.4/config/initializers/backtrace_silencers.rb +8 -0
  81. data/spec/rails_applications/6.1.4/config/initializers/content_security_policy.rb +30 -0
  82. data/spec/{dummy → rails_applications/6.1.4}/config/initializers/cookies_serializer.rb +5 -3
  83. data/spec/{dummy → rails_applications/6.1.4}/config/initializers/filter_parameter_logging.rb +6 -4
  84. data/spec/{dummy → rails_applications/6.1.4}/config/initializers/inflections.rb +16 -16
  85. data/spec/{dummy → rails_applications/6.1.4}/config/initializers/mime_types.rb +4 -4
  86. data/spec/rails_applications/6.1.4/config/initializers/permissions_policy.rb +11 -0
  87. data/spec/{dummy → rails_applications/6.1.4}/config/initializers/wrap_parameters.rb +14 -14
  88. data/spec/{dummy → rails_applications/6.1.4}/config/locales/en.yml +33 -23
  89. data/spec/rails_applications/6.1.4/config/master.key +1 -0
  90. data/spec/rails_applications/6.1.4/config/puma.rb +43 -0
  91. data/spec/rails_applications/6.1.4/config/routes.rb +4 -0
  92. data/spec/rails_applications/6.1.4/config/spring.rb +6 -0
  93. data/spec/rails_applications/6.1.4/config/storage.yml +34 -0
  94. data/spec/{dummy → rails_applications/6.1.4}/config.ru +6 -4
  95. data/spec/rails_applications/6.1.4/db/seeds.rb +7 -0
  96. data/spec/{dummy → rails_applications/6.1.4}/db/test.sqlite3 +0 -0
  97. data/spec/{dummy/app/models → rails_applications/6.1.4/lib/assets}/.keep +0 -0
  98. data/spec/{dummy/app/models/concerns → rails_applications/6.1.4/lib/tasks}/.keep +0 -0
  99. data/spec/rails_applications/6.1.4/package.json +11 -0
  100. data/spec/{dummy → rails_applications/6.1.4}/public/404.html +67 -67
  101. data/spec/{dummy → rails_applications/6.1.4}/public/422.html +67 -67
  102. data/spec/{dummy → rails_applications/6.1.4}/public/500.html +66 -66
  103. data/spec/{dummy/lib/assets/.keep → rails_applications/6.1.4/public/apple-touch-icon-precomposed.png} +0 -0
  104. data/spec/{dummy/lib/tasks/.keep → rails_applications/6.1.4/public/apple-touch-icon.png} +0 -0
  105. data/spec/{dummy → rails_applications/6.1.4}/public/favicon.ico +0 -0
  106. data/spec/rails_applications/6.1.4/public/robots.txt +1 -0
  107. data/spec/{dummy/log → rails_applications/6.1.4/storage}/.keep +0 -0
  108. data/spec/rails_applications/7.1.3/.dockerignore +37 -0
  109. data/spec/rails_applications/7.1.3/.gitattributes +9 -0
  110. data/spec/rails_applications/7.1.3/.gitignore +35 -0
  111. data/spec/rails_applications/7.1.3/.ruby-version +1 -0
  112. data/spec/rails_applications/7.1.3/Dockerfile +62 -0
  113. data/spec/rails_applications/7.1.3/Gemfile +67 -0
  114. data/spec/rails_applications/7.1.3/README.md +24 -0
  115. data/spec/rails_applications/7.1.3/Rakefile +6 -0
  116. data/spec/rails_applications/7.1.3/app/assets/config/manifest.js +4 -0
  117. data/spec/{dummy/test/controllers → rails_applications/7.1.3/app/assets/images}/.keep +0 -0
  118. data/spec/rails_applications/7.1.3/app/assets/stylesheets/application.css +15 -0
  119. data/spec/rails_applications/7.1.3/app/channels/application_cable/channel.rb +4 -0
  120. data/spec/rails_applications/7.1.3/app/channels/application_cable/connection.rb +4 -0
  121. data/spec/rails_applications/7.1.3/app/controllers/application_controller.rb +2 -0
  122. data/spec/{dummy/test/fixtures → rails_applications/7.1.3/app/controllers/concerns}/.keep +0 -0
  123. data/spec/rails_applications/7.1.3/app/controllers/home_controller.rb +2 -0
  124. data/spec/rails_applications/7.1.3/app/helpers/application_helper.rb +2 -0
  125. data/spec/rails_applications/7.1.3/app/helpers/home_helper.rb +2 -0
  126. data/spec/rails_applications/7.1.3/app/javascript/application.js +3 -0
  127. data/spec/rails_applications/7.1.3/app/javascript/controllers/application.js +9 -0
  128. data/spec/rails_applications/7.1.3/app/javascript/controllers/hello_controller.js +7 -0
  129. data/spec/rails_applications/7.1.3/app/javascript/controllers/index.js +11 -0
  130. data/spec/rails_applications/7.1.3/app/jobs/application_job.rb +7 -0
  131. data/spec/rails_applications/7.1.3/app/mailers/application_mailer.rb +4 -0
  132. data/spec/rails_applications/7.1.3/app/models/application_record.rb +3 -0
  133. data/spec/{dummy/test/helpers → rails_applications/7.1.3/app/models/concerns}/.keep +0 -0
  134. data/spec/rails_applications/7.1.3/app/views/home/index.html.erb +3 -0
  135. data/spec/rails_applications/7.1.3/app/views/home/index.json.erb +1 -0
  136. data/spec/rails_applications/7.1.3/app/views/layouts/application.html.erb +16 -0
  137. data/spec/rails_applications/7.1.3/app/views/layouts/mailer.html.erb +13 -0
  138. data/spec/rails_applications/7.1.3/app/views/layouts/mailer.text.erb +1 -0
  139. data/spec/rails_applications/7.1.3/bin/bundle +109 -0
  140. data/spec/rails_applications/7.1.3/bin/docker-entrypoint +8 -0
  141. data/spec/rails_applications/7.1.3/bin/importmap +4 -0
  142. data/spec/rails_applications/7.1.3/bin/rails +4 -0
  143. data/spec/rails_applications/7.1.3/bin/rake +4 -0
  144. data/spec/rails_applications/7.1.3/bin/setup +33 -0
  145. data/spec/rails_applications/7.1.3/config/application.rb +27 -0
  146. data/spec/rails_applications/7.1.3/config/boot.rb +4 -0
  147. data/spec/rails_applications/7.1.3/config/cable.yml +11 -0
  148. data/spec/rails_applications/7.1.3/config/credentials.yml.enc +1 -0
  149. data/spec/rails_applications/7.1.3/config/database.yml +25 -0
  150. data/spec/rails_applications/7.1.3/config/environment.rb +5 -0
  151. data/spec/rails_applications/7.1.3/config/environments/development.rb +76 -0
  152. data/spec/rails_applications/7.1.3/config/environments/production.rb +97 -0
  153. data/spec/rails_applications/7.1.3/config/environments/test.rb +64 -0
  154. data/spec/rails_applications/7.1.3/config/importmap.rb +7 -0
  155. data/spec/rails_applications/7.1.3/config/initializers/assets.rb +12 -0
  156. data/spec/rails_applications/7.1.3/config/initializers/content_security_policy.rb +25 -0
  157. data/spec/rails_applications/7.1.3/config/initializers/filter_parameter_logging.rb +8 -0
  158. data/spec/rails_applications/7.1.3/config/initializers/inflections.rb +16 -0
  159. data/spec/rails_applications/7.1.3/config/initializers/permissions_policy.rb +13 -0
  160. data/spec/rails_applications/7.1.3/config/locales/en.yml +31 -0
  161. data/spec/rails_applications/7.1.3/config/puma.rb +35 -0
  162. data/spec/rails_applications/7.1.3/config/routes.rb +11 -0
  163. data/spec/rails_applications/7.1.3/config/storage.yml +34 -0
  164. data/spec/rails_applications/7.1.3/config.ru +6 -0
  165. data/spec/rails_applications/7.1.3/db/seeds.rb +9 -0
  166. data/spec/{dummy/test/integration → rails_applications/7.1.3/lib/assets}/.keep +0 -0
  167. data/spec/{dummy/test/mailers → rails_applications/7.1.3/lib/tasks}/.keep +0 -0
  168. data/spec/rails_applications/7.1.3/public/404.html +67 -0
  169. data/spec/rails_applications/7.1.3/public/422.html +67 -0
  170. data/spec/rails_applications/7.1.3/public/500.html +66 -0
  171. data/spec/{dummy/test/models/.keep → rails_applications/7.1.3/public/apple-touch-icon-precomposed.png} +0 -0
  172. data/spec/{dummy/vendor/assets/javascripts/.keep → rails_applications/7.1.3/public/apple-touch-icon.png} +0 -0
  173. data/spec/{dummy/vendor/assets/stylesheets/.keep → rails_applications/7.1.3/public/favicon.ico} +0 -0
  174. data/spec/rails_applications/7.1.3/public/robots.txt +1 -0
  175. data/spec/rails_applications/7.1.3/storage/.keep +0 -0
  176. data/spec/rails_applications/7.1.3/test/application_system_test_case.rb +5 -0
  177. data/spec/rails_applications/7.1.3/test/channels/application_cable/connection_test.rb +13 -0
  178. data/spec/rails_applications/7.1.3/test/controllers/.keep +0 -0
  179. data/spec/rails_applications/7.1.3/test/controllers/home_controller_test.rb +7 -0
  180. data/spec/rails_applications/7.1.3/test/fixtures/files/.keep +0 -0
  181. data/spec/rails_applications/7.1.3/test/helpers/.keep +0 -0
  182. data/spec/rails_applications/7.1.3/test/integration/.keep +0 -0
  183. data/spec/rails_applications/7.1.3/test/mailers/.keep +0 -0
  184. data/spec/rails_applications/7.1.3/test/models/.keep +0 -0
  185. data/spec/rails_applications/7.1.3/test/system/.keep +0 -0
  186. data/spec/rails_applications/7.1.3/test/test_helper.rb +15 -0
  187. data/spec/rails_applications/7.1.3/vendor/.keep +0 -0
  188. data/spec/rails_applications/7.1.3/vendor/javascript/.keep +0 -0
  189. data/spec/rails_helper.rb +8 -4
  190. data/spec/raygun/breadcrumbs/breadcrumb_spec.rb +171 -171
  191. data/spec/raygun/breadcrumbs/store_spec.rb +170 -170
  192. data/spec/services/apply_whitelist_filter_to_payload_spec.rb +251 -251
  193. data/spec/spec_helper.rb +24 -24
  194. data/spec/support/fake_logger.rb +17 -17
  195. data/test/integration/client_test.rb +19 -19
  196. data/test/rails_helper.rb +6 -0
  197. data/test/test_helper.rb +76 -72
  198. data/test/unit/affected_user_test.rb +136 -136
  199. data/test/unit/client_test.rb +812 -812
  200. data/test/unit/configuration_test.rb +202 -206
  201. data/test/unit/error_subscriber_test.rb +43 -0
  202. data/test/unit/raygun_test.rb +106 -25
  203. data/test/unit/resque_failure_test.rb +27 -24
  204. data/test/unit/sidekiq_failure_test.rb +122 -32
  205. metadata +186 -125
  206. data/.travis.yml +0 -20
  207. data/spec/dummy/.gitignore +0 -17
  208. data/spec/dummy/Gemfile +0 -47
  209. data/spec/dummy/app/assets/config/manifest.js +0 -3
  210. data/spec/dummy/app/assets/javascripts/application.js +0 -13
  211. data/spec/dummy/app/controllers/application_controller.rb +0 -5
  212. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  213. data/spec/dummy/bin/bundle +0 -3
  214. data/spec/dummy/bin/rails +0 -9
  215. data/spec/dummy/bin/rake +0 -9
  216. data/spec/dummy/bin/setup +0 -29
  217. data/spec/dummy/bin/spring +0 -17
  218. data/spec/dummy/config/application.rb +0 -26
  219. data/spec/dummy/config/boot.rb +0 -3
  220. data/spec/dummy/config/environments/development.rb +0 -41
  221. data/spec/dummy/config/environments/production.rb +0 -79
  222. data/spec/dummy/config/environments/test.rb +0 -42
  223. data/spec/dummy/config/initializers/assets.rb +0 -11
  224. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  225. data/spec/dummy/config/initializers/session_store.rb +0 -3
  226. data/spec/dummy/config/initializers/to_time_preserves_timezone.rb +0 -10
  227. data/spec/dummy/config/routes.rb +0 -58
  228. data/spec/dummy/config/secrets.yml +0 -22
  229. data/spec/dummy/db/seeds.rb +0 -7
  230. data/spec/dummy/public/robots.txt +0 -5
  231. data/spec/dummy/test/test_helper.rb +0 -10
  232. data/spec/raygun/raygun_spec.rb +0 -47
data/lib/raygun/client.rb CHANGED
@@ -1,308 +1,313 @@
1
- module Raygun
2
- # client for the Raygun REST APIv1
3
- # as per https://raygun.com/documentation/product-guides/crash-reporting/api/
4
- class Client
5
-
6
- ENV_IP_ADDRESS_KEYS = %w(action_dispatch.remote_ip raygun.remote_ip REMOTE_ADDR)
7
- NO_API_KEY_MESSAGE = "[RAYGUN] Just a note, you've got no API Key configured, which means we can't report exceptions. Specify your Raygun API key using Raygun#setup (find yours at https://app.raygun.com)"
8
- MAX_BREADCRUMBS_SIZE = 100_000
9
-
10
- include HTTParty
11
-
12
- def initialize
13
- @api_key = require_api_key
14
- @headers = {
15
- "X-ApiKey" => @api_key
16
- }
17
-
18
- enable_http_proxy if Raygun.configuration.proxy_settings[:address]
19
- self.class.base_uri Raygun.configuration.api_url
20
- self.class.default_timeout(Raygun.configuration.error_report_send_timeout)
21
- end
22
-
23
- def require_api_key
24
- Raygun.configuration.api_key || print_api_key_warning
25
- end
26
-
27
- def track_exception(exception_instance, env = {}, user = nil)
28
- create_entry(build_payload_hash(exception_instance, env, user))
29
- end
30
-
31
- private
32
-
33
- def enable_http_proxy
34
- self.class.http_proxy(Raygun.configuration.proxy_settings[:address],
35
- Raygun.configuration.proxy_settings[:port] || "80",
36
- Raygun.configuration.proxy_settings[:username],
37
- Raygun.configuration.proxy_settings[:password])
38
- end
39
-
40
- def client_details
41
- {
42
- name: Raygun::CLIENT_NAME,
43
- version: Raygun::VERSION,
44
- clientUrl: Raygun::CLIENT_URL
45
- }
46
- end
47
-
48
- def error_details(exception)
49
- details = {
50
- className: exception.class.to_s,
51
- message: exception.message.to_s.encode('UTF-16', :undef => :replace, :invalid => :replace).encode('UTF-8'),
52
- stackTrace: (exception.backtrace || []).map { |line| stack_trace_for(line) },
53
- }
54
-
55
- details.update(innerError: error_details(exception.cause)) if exception.respond_to?(:cause) && exception.cause
56
-
57
- details
58
- end
59
-
60
- def stack_trace_for(line)
61
- # see http://www.ruby-doc.org/core-2.0/Exception.html#method-i-backtrace
62
- file_name, line_number, method = line.split(":")
63
- {
64
- lineNumber: line_number,
65
- fileName: file_name,
66
- methodName: method ? method.gsub(/^in `(.*?)'$/, "\\1") : "(none)"
67
- }
68
- end
69
-
70
- def hostname
71
- Socket.gethostname
72
- end
73
-
74
- def version
75
- Raygun.configuration.version
76
- end
77
-
78
- def user_information(env)
79
- env["raygun.affected_user"]
80
- end
81
-
82
- def affected_user_present?(env)
83
- !!env["raygun.affected_user"]
84
- end
85
-
86
- def rack_env
87
- ENV["RACK_ENV"]
88
- end
89
-
90
- def rails_env
91
- ENV["RAILS_ENV"]
92
- end
93
-
94
- def request_information(env)
95
- Raygun.log('retrieving request information')
96
-
97
- return {} if env.nil? || env.empty?
98
- {
99
- hostName: env["SERVER_NAME"],
100
- url: env["PATH_INFO"],
101
- httpMethod: env["REQUEST_METHOD"],
102
- iPAddress: "#{ip_address_from(env)}",
103
- queryString: Rack::Utils.parse_nested_query(env["QUERY_STRING"]),
104
- headers: headers(env),
105
- form: form_params(env),
106
- rawData: raw_data(env)
107
- }
108
- end
109
-
110
- def headers(rack_env)
111
- rack_env.select { |k, v| k.to_s.start_with?("HTTP_") }.inject({}) do |hsh, (k, v)|
112
- hsh[normalize_raygun_header_key(k)] = v
113
- hsh
114
- end
115
- end
116
-
117
- def normalize_raygun_header_key(key)
118
- key.sub(/^HTTP_/, '')
119
- .sub(/_/, ' ')
120
- .split.map(&:capitalize).join(' ')
121
- .sub(/ /, '-')
122
- end
123
-
124
- def form_params(env)
125
- Raygun.log('retrieving form params')
126
-
127
- params = action_dispatch_params(env) || rack_params(env) || {}
128
- filter_params_with_blacklist(params, env["action_dispatch.parameter_filter"])
129
- end
130
-
131
- def action_dispatch_params(env)
132
- env["action_dispatch.request.parameters"]
133
- end
134
-
135
- def rack_params(env)
136
- request = Rack::Request.new(env)
137
- request.params if env["rack.input"]
138
- end
139
-
140
- def raw_data(rack_env)
141
- Raygun.log('retrieving raw data')
142
- request = Rack::Request.new(rack_env)
143
-
144
- return unless Raygun.configuration.record_raw_data
145
- return if request.get?
146
- Raygun.log('passed raw_data checks')
147
-
148
- input = rack_env['rack.input']
149
-
150
- if input && !request.form_data?
151
- input.rewind
152
-
153
- body = input.read(4096) || ''
154
- input.rewind
155
-
156
- body
157
- else
158
- {}
159
- end
160
- end
161
-
162
- def filter_custom_data(env)
163
- params = env.delete(:custom_data) || {}
164
- filter_params_with_blacklist(params, env["action_dispatch.parameter_filter"])
165
- end
166
-
167
- # see https://raygun.com/documentation/product-guides/crash-reporting/api/
168
- def build_payload_hash(exception_instance, env = {}, user = nil)
169
- Raygun.log('building payload hash')
170
- custom_data = filter_custom_data(env) || {}
171
- exception_custom_data = if exception_instance.respond_to?(:raygun_custom_data)
172
- exception_instance.raygun_custom_data
173
- else
174
- {}
175
- end
176
-
177
- tags = env.delete(:tags) || []
178
-
179
- if rails_env
180
- tags << rails_env
181
- else
182
- tags << rack_env
183
- end
184
-
185
- combined_tags = []
186
-
187
- if Raygun.configuration.tags.is_a?(Proc)
188
- configuration_tags = Raygun.configuration.tags.call(exception_instance, env)
189
- else
190
- configuration_tags = Raygun.configuration.tags
191
- end
192
-
193
- combined_tags.concat(configuration_tags)
194
-
195
- Raygun.log('set tags')
196
-
197
- grouping_key = env.delete(:grouping_key)
198
- correlation_id = env.delete(:correlation_id)
199
-
200
- configuration_custom_data = Raygun.configuration.custom_data
201
- configured_custom_data = if configuration_custom_data.is_a?(Proc)
202
- configuration_custom_data.call(exception_instance, env)
203
- else
204
- configuration_custom_data
205
- end
206
-
207
- Raygun.log('set custom data')
208
-
209
- error_details = {
210
- machineName: hostname,
211
- version: version,
212
- client: client_details,
213
- error: error_details(exception_instance),
214
- userCustomData: exception_custom_data.merge(custom_data).merge(configured_custom_data),
215
- tags: combined_tags.concat(tags).compact.uniq,
216
- request: request_information(env),
217
- environment: {
218
- utcOffset: Time.now.utc_offset / 3600
219
- }
220
- }
221
- store = ::Raygun::Breadcrumbs::Store
222
- error_details[:breadcrumbs] = store.take_until_size(MAX_BREADCRUMBS_SIZE).map(&:build_payload) if store.any?
223
-
224
- Raygun.log('set details and breadcrumbs')
225
-
226
- error_details.merge!(groupingKey: grouping_key) if grouping_key
227
- error_details.merge!(correlationId: correlation_id) if correlation_id
228
-
229
- user_details = if affected_user_present?(env)
230
- user_information(env)
231
- elsif user != nil
232
- AffectedUser.information_hash(user)
233
- end
234
- error_details.merge!(user: user_details) unless user_details == nil
235
-
236
- Raygun.log('set user details')
237
-
238
- if Raygun.configuration.filter_payload_with_whitelist
239
- Raygun.log('filtering payload with whitelist')
240
- error_details = filter_payload_with_whitelist(error_details)
241
- end
242
-
243
- {
244
- occurredOn: Time.now.utc.iso8601,
245
- details: error_details
246
- }
247
- end
248
-
249
- def create_entry(payload_hash)
250
- Raygun.log('sending payload to api')
251
-
252
- self.class.post(
253
- "/entries",
254
- verify_peer: true,
255
- verify: true,
256
- headers: @headers,
257
- body: JSON.generate(payload_hash),
258
- )
259
- end
260
-
261
- def filter_params_with_blacklist(params_hash = {}, extra_filter_keys = nil)
262
- filter_parameters = Raygun.configuration.filter_parameters
263
-
264
- if filter_parameters.is_a? Proc
265
- filter_parameters.call(params_hash)
266
- else
267
- filter_keys = (Array(extra_filter_keys) + filter_parameters).map(&:to_s)
268
-
269
- filter_params_with_array(params_hash, filter_keys)
270
- end
271
- end
272
-
273
- def filter_payload_with_whitelist(payload_hash)
274
- shape = Raygun.configuration.whitelist_payload_shape
275
-
276
- if shape.is_a? Proc
277
- shape.call(payload_hash)
278
- else
279
- # Always keep the client hash, so force it to true here
280
- Services::ApplyWhitelistFilterToPayload.new.call(shape.merge(client: true), payload_hash)
281
- end
282
- end
283
-
284
- def filter_params_with_array(params_hash, filter_keys)
285
- # Recursive filtering of (nested) hashes
286
- (params_hash || {}).inject({}) do |result, (k, v)|
287
- result[k] = case v
288
- when Hash
289
- filter_params_with_array(v, filter_keys)
290
- else
291
- filter_keys.any? { |fk| /#{fk}/i === k.to_s } ? "[FILTERED]" : v
292
- end
293
- result
294
- end
295
- end
296
-
297
- def ip_address_from(env_hash)
298
- ENV_IP_ADDRESS_KEYS.each do |key_to_try|
299
- return env_hash[key_to_try] unless env_hash[key_to_try].nil? || env_hash[key_to_try] == ""
300
- end
301
- "(Not Available)"
302
- end
303
-
304
- def print_api_key_warning
305
- $stderr.puts(NO_API_KEY_MESSAGE)
306
- end
307
- end
308
- end
1
+ module Raygun
2
+ # client for the Raygun REST APIv1
3
+ # as per https://raygun.com/documentation/product-guides/crash-reporting/api/
4
+ class Client
5
+
6
+ ENV_IP_ADDRESS_KEYS = %w(action_dispatch.remote_ip raygun.remote_ip REMOTE_ADDR)
7
+ NO_API_KEY_MESSAGE = "[RAYGUN] Just a note, you've got no API Key configured, which means we can't report exceptions. Specify your Raygun API key using Raygun#setup (find yours at https://app.raygun.com)"
8
+ MAX_BREADCRUMBS_SIZE = 100_000
9
+
10
+ include HTTParty
11
+
12
+ def initialize
13
+ @api_key = require_api_key
14
+ @headers = {
15
+ "X-ApiKey" => @api_key
16
+ }
17
+
18
+ enable_http_proxy if Raygun.configuration.proxy_settings[:address]
19
+ self.class.base_uri Raygun.configuration.api_url
20
+ self.class.default_timeout(Raygun.configuration.error_report_send_timeout)
21
+ end
22
+
23
+ def require_api_key
24
+ Raygun.configuration.api_key || print_api_key_warning
25
+ end
26
+
27
+ def track_exception(exception_instance, env = {}, user = nil)
28
+ create_entry(build_payload_hash(exception_instance, env, user))
29
+ end
30
+
31
+ private
32
+
33
+ def enable_http_proxy
34
+ self.class.http_proxy(Raygun.configuration.proxy_settings[:address],
35
+ Raygun.configuration.proxy_settings[:port] || "80",
36
+ Raygun.configuration.proxy_settings[:username],
37
+ Raygun.configuration.proxy_settings[:password])
38
+ end
39
+
40
+ def client_details
41
+ {
42
+ name: Raygun::CLIENT_NAME,
43
+ version: Raygun::VERSION,
44
+ clientUrl: Raygun::CLIENT_URL
45
+ }
46
+ end
47
+
48
+ def error_details(exception)
49
+ details = {
50
+ className: exception.class.to_s,
51
+ message: exception.message.to_s.encode('UTF-16', :undef => :replace, :invalid => :replace).encode('UTF-8'),
52
+ stackTrace: (exception.backtrace || []).map { |line| stack_trace_for(line) },
53
+ }
54
+
55
+ details.update(innerError: error_details(exception.cause)) if exception.respond_to?(:cause) && exception.cause
56
+
57
+ details
58
+ end
59
+
60
+ def stack_trace_for(line)
61
+ # see http://www.ruby-doc.org/core-2.0/Exception.html#method-i-backtrace
62
+ file_name, line_number, method = line.split(":")
63
+ {
64
+ lineNumber: line_number,
65
+ fileName: file_name,
66
+ methodName: method ? method.gsub(/^in `(.*?)'$/, "\\1") : "(none)"
67
+ }
68
+ end
69
+
70
+ def hostname
71
+ Socket.gethostname
72
+ end
73
+
74
+ def version
75
+ Raygun.configuration.version
76
+ end
77
+
78
+ def user_information(env)
79
+ env["raygun.affected_user"]
80
+ end
81
+
82
+ def affected_user_present?(env)
83
+ !!env["raygun.affected_user"]
84
+ end
85
+
86
+ def rack_env
87
+ ENV["RACK_ENV"]
88
+ end
89
+
90
+ def rails_env
91
+ ENV["RAILS_ENV"]
92
+ end
93
+
94
+ def request_information(env)
95
+ Raygun.log('retrieving request information')
96
+
97
+ return {} if env.nil? || env.empty?
98
+ {
99
+ hostName: env["SERVER_NAME"],
100
+ url: env["PATH_INFO"],
101
+ httpMethod: env["REQUEST_METHOD"],
102
+ iPAddress: "#{ip_address_from(env)}",
103
+ queryString: Rack::Utils.parse_nested_query(env["QUERY_STRING"]),
104
+ headers: headers(env),
105
+ form: form_params(env),
106
+ rawData: raw_data(env)
107
+ }
108
+ end
109
+
110
+ def headers(rack_env)
111
+ rack_env.select { |k, v| k.to_s.start_with?("HTTP_") }.inject({}) do |hsh, (k, v)|
112
+ hsh[normalize_raygun_header_key(k)] = v
113
+ hsh
114
+ end
115
+ end
116
+
117
+ def normalize_raygun_header_key(key)
118
+ key.sub(/^HTTP_/, '')
119
+ .sub(/_/, ' ')
120
+ .split.map(&:capitalize).join(' ')
121
+ .sub(/ /, '-')
122
+ end
123
+
124
+ def form_params(env)
125
+ Raygun.log('retrieving form params')
126
+
127
+ params = action_dispatch_params(env) || rack_params(env) || {}
128
+ filter_params_with_blacklist(params, env["action_dispatch.parameter_filter"])
129
+ end
130
+
131
+ def action_dispatch_params(env)
132
+ env["action_dispatch.request.parameters"]
133
+ end
134
+
135
+ def rack_params(env)
136
+ request = Rack::Request.new(env)
137
+ request.params if env["rack.input"]
138
+ end
139
+
140
+ def raw_data(rack_env)
141
+ Raygun.log('retrieving raw data')
142
+ request = Rack::Request.new(rack_env)
143
+
144
+ return unless Raygun.configuration.record_raw_data
145
+ return if request.get?
146
+ Raygun.log('passed raw_data checks')
147
+
148
+ input = rack_env['rack.input']
149
+
150
+ if input && !request.form_data?
151
+ input.rewind
152
+
153
+ body = input.read(4096) || ''
154
+ input.rewind
155
+
156
+ body
157
+ else
158
+ {}
159
+ end
160
+ end
161
+
162
+ def filter_custom_data(env)
163
+ params = env.delete(:custom_data) || {}
164
+ filter_params_with_blacklist(params, env["action_dispatch.parameter_filter"])
165
+ end
166
+
167
+ # see https://raygun.com/documentation/product-guides/crash-reporting/api/
168
+ def build_payload_hash(exception_instance, env = {}, user = nil)
169
+ Raygun.log('building payload hash')
170
+ custom_data = filter_custom_data(env) || {}
171
+ exception_custom_data = if exception_instance.respond_to?(:raygun_custom_data)
172
+ exception_instance.raygun_custom_data
173
+ else
174
+ {}
175
+ end
176
+
177
+ tags = env.delete(:tags) || []
178
+
179
+ if rails_env
180
+ tags << rails_env
181
+ else
182
+ tags << rack_env
183
+ end
184
+
185
+ combined_tags = []
186
+
187
+ if Raygun.configuration.tags.is_a?(Proc)
188
+ configuration_tags = Raygun.configuration.tags.call(exception_instance, env)
189
+ else
190
+ configuration_tags = Raygun.configuration.tags
191
+ end
192
+
193
+ combined_tags.concat(configuration_tags)
194
+
195
+ Raygun.log('set tags')
196
+
197
+ grouping_key = env.delete(:grouping_key)
198
+ correlation_id = env.delete(:correlation_id)
199
+
200
+ configuration_custom_data = Raygun.configuration.custom_data
201
+ configured_custom_data = if configuration_custom_data.is_a?(Proc)
202
+ configuration_custom_data.call(exception_instance, env)
203
+ else
204
+ configuration_custom_data
205
+ end
206
+
207
+ Raygun.log('set custom data')
208
+
209
+ error_details = {
210
+ machineName: hostname,
211
+ version: version,
212
+ client: client_details,
213
+ error: error_details(exception_instance),
214
+ userCustomData: exception_custom_data.merge(custom_data).merge(configured_custom_data),
215
+ tags: combined_tags.concat(tags).compact.uniq,
216
+ request: request_information(env),
217
+ environment: {
218
+ utcOffset: Time.now.utc_offset / 3600
219
+ }
220
+ }
221
+
222
+ # If we have breadcrumbs passed to us as context from another thread, then include them
223
+ # Otherwise, use the default store (which is thread-local)
224
+ ::Raygun::Breadcrumbs::Store.initialize(with: env.delete(:rg_breadcrumb_store)) if env.key?(:rg_breadcrumb_store)
225
+
226
+ store = ::Raygun::Breadcrumbs::Store
227
+ error_details[:breadcrumbs] = store.take_until_size(MAX_BREADCRUMBS_SIZE).map(&:build_payload) if store.any?
228
+
229
+ Raygun.log('set details and breadcrumbs')
230
+
231
+ error_details.merge!(groupingKey: grouping_key) if grouping_key
232
+ error_details.merge!(correlationId: correlation_id) if correlation_id
233
+
234
+ user_details = if affected_user_present?(env)
235
+ user_information(env)
236
+ elsif user != nil
237
+ AffectedUser.information_hash(user)
238
+ end
239
+ error_details.merge!(user: user_details) unless user_details == nil
240
+
241
+ Raygun.log('set user details')
242
+
243
+ if Raygun.configuration.filter_payload_with_whitelist
244
+ Raygun.log('filtering payload with whitelist')
245
+ error_details = filter_payload_with_whitelist(error_details)
246
+ end
247
+
248
+ {
249
+ occurredOn: Time.now.utc.iso8601,
250
+ details: error_details
251
+ }
252
+ end
253
+
254
+ def create_entry(payload_hash)
255
+ Raygun.log('sending payload to api')
256
+
257
+ self.class.post(
258
+ "/entries",
259
+ verify_peer: true,
260
+ verify: true,
261
+ headers: @headers,
262
+ body: JSON.generate(payload_hash),
263
+ )
264
+ end
265
+
266
+ def filter_params_with_blacklist(params_hash = {}, extra_filter_keys = nil)
267
+ filter_parameters = Raygun.configuration.filter_parameters
268
+
269
+ if filter_parameters.is_a? Proc
270
+ filter_parameters.call(params_hash)
271
+ else
272
+ filter_keys = (Array(extra_filter_keys) + filter_parameters).map(&:to_s)
273
+
274
+ filter_params_with_array(params_hash, filter_keys)
275
+ end
276
+ end
277
+
278
+ def filter_payload_with_whitelist(payload_hash)
279
+ shape = Raygun.configuration.whitelist_payload_shape
280
+
281
+ if shape.is_a? Proc
282
+ shape.call(payload_hash)
283
+ else
284
+ # Always keep the client hash, so force it to true here
285
+ Services::ApplyWhitelistFilterToPayload.new.call(shape.merge(client: true), payload_hash)
286
+ end
287
+ end
288
+
289
+ def filter_params_with_array(params_hash, filter_keys)
290
+ # Recursive filtering of (nested) hashes
291
+ (params_hash || {}).inject({}) do |result, (k, v)|
292
+ result[k] = case v
293
+ when Hash
294
+ filter_params_with_array(v, filter_keys)
295
+ else
296
+ filter_keys.any? { |fk| /#{fk}/i === k.to_s } ? "[FILTERED]" : v
297
+ end
298
+ result
299
+ end
300
+ end
301
+
302
+ def ip_address_from(env_hash)
303
+ ENV_IP_ADDRESS_KEYS.each do |key_to_try|
304
+ return env_hash[key_to_try] unless env_hash[key_to_try].nil? || env_hash[key_to_try] == ""
305
+ end
306
+ "(Not Available)"
307
+ end
308
+
309
+ def print_api_key_warning
310
+ $stderr.puts(NO_API_KEY_MESSAGE)
311
+ end
312
+ end
313
+ end