oopsie_exceptions 1.1.0 → 1.1.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.
- checksums.yaml +4 -4
- data/README.md +10 -0
- data/lib/oopsie_exceptions/context.rb +52 -21
- data/lib/oopsie_exceptions/version.rb +1 -1
- metadata +17 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: eeb40f85518ab7f9d4d43e33bb9605206de73f6e3d8fc24979039c39c2c11c02
|
|
4
|
+
data.tar.gz: e075b4c269916b53dfecd103d7a10ec9ca0b6ce99de3b82c37b391fc386d56cf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 71d6c2ce97bae33d43f3d0ad1fee09ede56ca47576c11303a98e663e2046f6719fbd309d1429f6ce375956cff33fefa404a61ddbacf51c82df377b5296929820
|
|
7
|
+
data.tar.gz: 064032a2ec6f0d414bcb24935932a2775a8dbe691ff0b6a1252681bf798b68e347f9e5de8d14fa897d29bca8d22caca262751723343730c62c98eb6c99e15d5d
|
data/README.md
CHANGED
|
@@ -90,6 +90,8 @@ end
|
|
|
90
90
|
|
|
91
91
|
Each captured exception is enriched with request URL/method/IP/params/headers, the current user (via `context_builder` or `set_context`), server hostname/PID/Ruby version, and a UTC timestamp.
|
|
92
92
|
|
|
93
|
+
Request context capture is best-effort. If Rack rejects a malformed or truncated request body while OopsieExceptions is collecting params, the exception report is still allowed to continue with `request.params` omitted. Payloads include omission metadata such as `params_omitted` / `params_error_class` or `body_omitted` / `body_error_class` when request enrichment fails.
|
|
94
|
+
|
|
93
95
|
## Adding context per-request
|
|
94
96
|
|
|
95
97
|
If you don't want to use `context_builder`, you can set context from a controller:
|
|
@@ -189,6 +191,14 @@ Return `nil` to drop the notification entirely.
|
|
|
189
191
|
|
|
190
192
|
## Upgrading from earlier versions
|
|
191
193
|
|
|
194
|
+
### Malformed request body handling
|
|
195
|
+
|
|
196
|
+
Apps that added a local guard around OopsieExceptions request context collection for malformed multipart or truncated request bodies can remove that workaround after upgrading to a gem release that includes best-effort request params/body capture. Until the fixed gem version is deployed in the app, keep the app-local guard in place.
|
|
197
|
+
|
|
198
|
+
This gem change only prevents OopsieExceptions from turning context enrichment into a new request failure. Production exception groups for the affected app should still be resolved from that app's deploy verification, not from the gem release alone.
|
|
199
|
+
|
|
200
|
+
### Legacy delivery job cleanup
|
|
201
|
+
|
|
192
202
|
If you're coming from an older version of the gem that generated `app/jobs/oopsie_exceptions/delivery_job.rb` in your app, **delete that file**. The gem now ships its own `OopsieExceptions::WebhookJob` and the host-app file is obsolete.
|
|
193
203
|
|
|
194
204
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "rack"
|
|
3
|
+
require "rack/request"
|
|
4
4
|
|
|
5
5
|
module OopsieExceptions
|
|
6
6
|
module Context
|
|
@@ -27,38 +27,63 @@ module OopsieExceptions
|
|
|
27
27
|
request = Rack::Request.new(env)
|
|
28
28
|
config = OopsieExceptions.configuration
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
params: sanitize_params(request.params, config),
|
|
39
|
-
headers: extract_headers(env, config)
|
|
40
|
-
}
|
|
30
|
+
request_context = {
|
|
31
|
+
url: request.url,
|
|
32
|
+
method: request.request_method,
|
|
33
|
+
ip: request.ip,
|
|
34
|
+
user_agent: env["HTTP_USER_AGENT"],
|
|
35
|
+
referer: env["HTTP_REFERER"],
|
|
36
|
+
request_id: env["action_dispatch.request_id"] || env["HTTP_X_REQUEST_ID"],
|
|
37
|
+
headers: extract_headers(env, config)
|
|
41
38
|
}
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
request_context.merge!(request_params_context(request, config))
|
|
41
|
+
request_context.merge!(request_body_context(request, config))
|
|
42
|
+
|
|
43
|
+
ctx = {
|
|
44
|
+
request: request_context
|
|
45
|
+
}
|
|
48
46
|
|
|
49
47
|
ctx
|
|
50
48
|
end
|
|
51
49
|
|
|
52
50
|
private
|
|
53
51
|
|
|
52
|
+
def request_params_context(request, config)
|
|
53
|
+
{ params: sanitize_params(request.params, config) }
|
|
54
|
+
rescue StandardError => error
|
|
55
|
+
rewind_body(request.body)
|
|
56
|
+
{
|
|
57
|
+
params: {},
|
|
58
|
+
params_omitted: true,
|
|
59
|
+
params_error_class: error.class.name
|
|
60
|
+
}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def request_body_context(request, config)
|
|
64
|
+
return {} unless config.capture_request_body
|
|
65
|
+
return {} unless request.content_type&.include?("application/json")
|
|
66
|
+
|
|
67
|
+
body_io = request.body
|
|
68
|
+
body = body_io.read
|
|
69
|
+
return {} if body.nil? || body.empty?
|
|
70
|
+
|
|
71
|
+
{ body: body[0, 10_000] }
|
|
72
|
+
rescue StandardError => error
|
|
73
|
+
{
|
|
74
|
+
body_omitted: true,
|
|
75
|
+
body_error_class: error.class.name
|
|
76
|
+
}
|
|
77
|
+
ensure
|
|
78
|
+
rewind_body(body_io)
|
|
79
|
+
end
|
|
80
|
+
|
|
54
81
|
def sanitize_params(params, config)
|
|
55
82
|
filtered = params.reject { |k, _| k == "controller" || k == "action" }
|
|
56
83
|
filter_keys = config.filter_parameters
|
|
57
84
|
filtered.each_with_object({}) do |(k, v), hash|
|
|
58
|
-
hash[k] = filter_keys.any? { |f| k.to_s.include?(f) } ? "[FILTERED]" : v
|
|
85
|
+
hash[k] = filter_keys.any? { |f| k.to_s.include?(f.to_s) } ? "[FILTERED]" : v
|
|
59
86
|
end
|
|
60
|
-
rescue
|
|
61
|
-
{}
|
|
62
87
|
end
|
|
63
88
|
|
|
64
89
|
def extract_headers(env, config)
|
|
@@ -66,11 +91,17 @@ module OopsieExceptions
|
|
|
66
91
|
env.each do |key, value|
|
|
67
92
|
next unless key.start_with?("HTTP_")
|
|
68
93
|
header_name = key.sub("HTTP_", "").split("_").map(&:capitalize).join("-")
|
|
69
|
-
next if config.filter_headers.any? { |h| h.casecmp(header_name) == 0 }
|
|
94
|
+
next if config.filter_headers.any? { |h| h.to_s.casecmp(header_name) == 0 }
|
|
70
95
|
headers[header_name] = value
|
|
71
96
|
end
|
|
72
97
|
headers
|
|
73
98
|
end
|
|
99
|
+
|
|
100
|
+
def rewind_body(body_io)
|
|
101
|
+
body_io.rewind if body_io&.respond_to?(:rewind)
|
|
102
|
+
rescue StandardError
|
|
103
|
+
nil
|
|
104
|
+
end
|
|
74
105
|
end
|
|
75
106
|
end
|
|
76
107
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: oopsie_exceptions
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Troy
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rack
|
|
@@ -24,11 +23,24 @@ dependencies:
|
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
25
|
version: '2.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: minitest
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '5.0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '5.0'
|
|
27
40
|
description: Captures unhandled exceptions from web requests and background jobs,
|
|
28
41
|
enriches them with request/user/server context, and delivers structured JSON payloads
|
|
29
42
|
to configurable webhook endpoints. Works with any Rack-based framework; optional
|
|
30
43
|
Rails integration included.
|
|
31
|
-
email:
|
|
32
44
|
executables: []
|
|
33
45
|
extensions: []
|
|
34
46
|
extra_rdoc_files: []
|
|
@@ -55,7 +67,6 @@ metadata:
|
|
|
55
67
|
source_code_uri: https://github.com/theinventor/oopsie_exceptions
|
|
56
68
|
changelog_uri: https://github.com/theinventor/oopsie_exceptions/releases
|
|
57
69
|
rubygems_mfa_required: 'true'
|
|
58
|
-
post_install_message:
|
|
59
70
|
rdoc_options: []
|
|
60
71
|
require_paths:
|
|
61
72
|
- lib
|
|
@@ -70,8 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
70
81
|
- !ruby/object:Gem::Version
|
|
71
82
|
version: '0'
|
|
72
83
|
requirements: []
|
|
73
|
-
rubygems_version: 3.
|
|
74
|
-
signing_key:
|
|
84
|
+
rubygems_version: 3.6.7
|
|
75
85
|
specification_version: 4
|
|
76
86
|
summary: Lightweight exception capture and webhook delivery for Ruby (framework-agnostic)
|
|
77
87
|
test_files: []
|