activeerror 1.1.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf8f5a1ee01022330a7ab7fd51b9d49e5bd39a1fa3ac4430c90e1321b7d4d2a1
4
- data.tar.gz: f36c4e1b8052c14316e14075c9de5624ac3a09ee0816164f3d5e064f0bf6f55b
3
+ metadata.gz: f62d898e9e3ecefbee847720c5b0c494a175946ea248f380762ff9ff413a6e8e
4
+ data.tar.gz: ad82c8c07a1c2815c7a0ad58628a476f7e2d754682d8a09c45ce6e62cd930947
5
5
  SHA512:
6
- metadata.gz: 81a4a5f81fd404d6d154ad6a65d27dc2f5690113d0b2f4b284d1a878295734526d9be88ae2cf0fd71c8c7d46b358b4e9aaf382abcb9578f16990ea2a6d46fe0d
7
- data.tar.gz: ee9c6c4bca50c0dd8220b12c112bdfcc20d88b646cbc1c15cca1425d46c5a9768d9f1c9fc963c9febf8352f90936f0e16b4c868fbd6a565979b96c3c2c66f685
6
+ metadata.gz: fbbc8303ef12d3fc39d88d8320fb3b181eb08bd40cf8ebdd0da969bdd1f0f3e30f49d449838593656b319bbe07ed4b7630cec2adbadf58f36ed64043a078383f
7
+ data.tar.gz: 115594a0e228fc55d627c85ef2a0a081d6855e194f15a0741fbc5a54add7b2bd43cc9761ed5b6ed658243bef513d9eb8b3ce17bf7c9f18ff743dc7af5d1032eb
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2019 Nick Pezza
3
+ Copyright (c) 2020 Nick Pezza
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # ActiveError
2
2
 
3
3
  One of the fundemental tools needed to take your Rails app to production is a
4
- way to track errors that are triggered. Unfortunately, theres no free, easy,
5
- open source way to track them for small or medium apps. Honeybadger, Sentry,
4
+ way to track errors that are triggered. Unfortunately, there aren't many free,
5
+ easy, open source ways to track them for small or medium apps. Honeybadger, Sentry,
6
6
  and AppSignal are great, but they are are closed source. With Sentry
7
7
  looking at using your data as training
8
8
  data([link](https://blog.sentry.io/ai-privacy-and-terms-of-service-updates/?original_referrer=https%3A%2F%2Fsentry.io%2F))
9
9
  there should be an easy open source alternative where you control the data.
10
+ With Rails 8's ethos of No PAAS, there should be a way for new apps to start out
11
+ with a basic error reporter and not be forced to pay a third party for one.
10
12
 
11
13
  ActiveError hooks into the [error reporting
12
14
  api](https://guides.rubyonrails.org/error_reporting.html) baked directly into
@@ -16,8 +18,8 @@ with is the one baked into Rails that we use everyday in development. So with
16
18
  ActiveError, when an error gets raised it's captured and stored in the
17
19
  database (we attempt to group the same error together as Instances to reduce
18
20
  noise) and then we recreate the error and display it using the built in debug
19
- view from Rails. Once you've resolved the error you can click "Resolve" which
20
- will destroy the record.
21
+ view from Rails (with a few font and styling tweaks). Once you've resolved the
22
+ error you can click "Resolve" which will destroy the record.
21
23
 
22
24
  ![screenshot 1](https://github.com/npezza93/activeerror/blob/main/.github/screenshot1.png)
23
25
  ![screenshot 2](https://github.com/npezza93/activeerror/blob/main/.github/screenshot2.png)
@@ -39,22 +41,21 @@ Or install it yourself as:
39
41
  $ gem install activeerror
40
42
  ```
41
43
 
42
- And then install migrations:
44
+ Run the installer and migrate:
43
45
  ```bash
44
- bin/rails generate active_error:install
45
- bin/rails rails db:migrate
46
+ bin/rails active_error:install
47
+ bin/rails db:migrate
46
48
  ```
47
49
 
48
- This also mounts a route in your routes file to view the errors at `/errors`.
49
-
50
+ This will mount a route in your routes file to view the errors at `/errors`.
50
51
 
51
52
  ##### Config
52
53
 
53
- You can supply the string version of an error class to `ignored` to ignore
54
- classes of errors.
54
+ You can supply a list of the string version of an error class to `ignored` to
55
+ ignore classes of errors.
55
56
 
56
57
  ```ruby
57
- ActiveError.ignored = ["NoMethodError"]
58
+ config.active_error.ignored = ["NoMethodError"]
58
59
  ```
59
60
 
60
61
  ## Development
data/Rakefile CHANGED
@@ -1,20 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- begin
4
- require "bundler/setup"
5
- rescue LoadError
6
- puts "You must `gem install bundler` and `bundle install` to run rake tasks"
7
- end
8
-
9
- require "rdoc/task"
10
-
11
- RDoc::Task.new(:rdoc) do |rdoc|
12
- rdoc.rdoc_dir = "rdoc"
13
- rdoc.title = "ActiveError"
14
- rdoc.options << "--line-numbers"
15
- rdoc.rdoc_files.include("README.md")
16
- rdoc.rdoc_files.include("lib/**/*.rb")
17
- end
3
+ require "bundler/setup"
18
4
 
19
5
  APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
20
6
  load "rails/tasks/engine.rake"
@@ -23,12 +9,8 @@ load "rails/tasks/statistics.rake"
23
9
 
24
10
  require "bundler/gem_tasks"
25
11
 
26
- require "rake/testtask"
27
-
28
- Rake::TestTask.new(:test) do |t|
29
- t.libs << "test"
30
- t.pattern = "test/**/*_test.rb"
31
- t.verbose = false
12
+ task test: :environment do
13
+ sh("bin/rails test")
32
14
  end
33
15
 
34
16
  task default: :test
@@ -0,0 +1,175 @@
1
+ @font-face {
2
+ font-family: 'Calibre';
3
+ font-style: normal;
4
+ font-weight: 400;
5
+ src: url('./calibre-regular.woff2') format('woff2');
6
+ font-display: swap;
7
+ }
8
+
9
+ @font-face {
10
+ font-family: 'Calibre';
11
+ font-style: italic;
12
+ font-weight: 400;
13
+ src: url('./calibre-regular-italic.woff2') format('woff2');
14
+ font-display: swap;
15
+ }
16
+
17
+ @font-face {
18
+ font-family: 'Calibre';
19
+ font-style: normal;
20
+ font-weight: 600;
21
+ src: url('./calibre-semibold.woff2') format('woff2');
22
+ font-display: swap;
23
+ }
24
+
25
+ @font-face {
26
+ font-family: 'Calibre';
27
+ font-style: italic;
28
+ font-weight: 600;
29
+ src: url('./calibre-semibold-italic.woff2') format('woff2');
30
+ font-display: swap;
31
+ }
32
+
33
+ @font-face {
34
+ font-family: 'Calibre';
35
+ font-style: normal;
36
+ font-weight: 700;
37
+ src: url('./calibre-bold.woff2') format('woff2');
38
+ font-display: swap;
39
+ }
40
+
41
+ .active_error {
42
+ body {
43
+ background-color: #fff;
44
+ color: #333;
45
+ margin: 0px;
46
+ }
47
+
48
+ body, p, ol, ul, td, input {
49
+ font-family: helvetica, verdana, arial, sans-serif;
50
+ font-size: 15px;
51
+ line-height: 18px;
52
+ font-family: 'Calibre';
53
+ }
54
+
55
+ header {
56
+ color: #D30001;
57
+ background: rgb(238, 231, 233);
58
+ padding: 7.5px 22.5px;
59
+ display: flex;
60
+ flex-direction: row;
61
+ justify-content: space-between;
62
+ align-items: center;
63
+ }
64
+
65
+ h1 {
66
+ flex: 1;
67
+ overflow-wrap: break-word;
68
+ margin: 0.2em 0;
69
+ line-height: 1.1em;
70
+ font-size: 30px;
71
+ }
72
+
73
+ #notice {
74
+ font-family: 'Calibre';
75
+ color: #000;
76
+ margin: 0px;
77
+ font-size: 20px;
78
+ }
79
+
80
+ table {
81
+ margin: 0;
82
+ border-collapse: collapse;
83
+ word-wrap:break-word;
84
+ table-layout: auto;
85
+ width: 100%;
86
+ }
87
+
88
+ .tr {
89
+ border-bottom: 3px solid rgba(38,27,35,0.1);
90
+ display: grid;
91
+ grid-template-columns: 10px 70px 1fr 215px 150px 180px;
92
+ align-items: center;
93
+
94
+ .all-cols {
95
+ grid-column: span 6 / span 6;
96
+ margin-bottom: 10px;
97
+
98
+ &> div {
99
+ display: grid;
100
+ grid-template-columns: 1fr 215px 300px;
101
+ margin-left: 110px;
102
+ flex-direction: row;
103
+
104
+ &> div {
105
+ padding-right: 5px;
106
+ }
107
+ div {
108
+ margin: 3px 0px;
109
+
110
+ a {
111
+ word-break: break-all;
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ a {
118
+ color: #261B23;
119
+ &:hover {
120
+ color: #D30001;
121
+ }
122
+ }
123
+
124
+ .td {
125
+ font-family: 'Calibre';
126
+ font-size: 20px;
127
+
128
+ &.chevron {
129
+ padding: 0px;
130
+ padding-left: 3px;
131
+ cursor: pointer;
132
+ font-size: 14px;
133
+ &.rotate {
134
+ transform: rotate(90deg);
135
+ }
136
+ }
137
+
138
+ &.location {
139
+ display: flex;
140
+ flex-direction: column;
141
+
142
+ span {
143
+ font-size: 16px;
144
+ margin-top: 10px;
145
+ }
146
+ }
147
+ }
148
+ }
149
+
150
+ .tr:nth-child(even) {
151
+ background: rgb(238, 231, 233);
152
+ }
153
+
154
+ .tr .td {
155
+ padding: 10px 30px;
156
+ }
157
+
158
+ .button-as-link {
159
+ border: none;
160
+ text-decoration: none;
161
+ cursor: pointer;
162
+ background: none;
163
+ font-size: 20px;
164
+ margin: 0;
165
+ padding: 7px 25px;
166
+ line-height: 18px;
167
+ color: #fff;
168
+ border-radius: 9999px;
169
+ background-color: #D30001;
170
+ }
171
+ }
172
+
173
+ .hidden {
174
+ display: none;
175
+ }
@@ -5,10 +5,14 @@ module ActiveError
5
5
  before_action :set_fault, only: %i(show destroy)
6
6
 
7
7
  def index
8
- @faults = Fault.top_level
8
+ @faults = Fault.top_level.includes(:instances)
9
9
  end
10
10
 
11
11
  def show
12
+ instance = @fault.instances.last ||
13
+ @fault.instances.new(headers: {}, parameters: {})
14
+
15
+ render html: Renderer.new(instance:).body
12
16
  end
13
17
 
14
18
  def destroy
@@ -2,12 +2,14 @@
2
2
 
3
3
  module ActiveError
4
4
  class Fault < ApplicationRecord
5
+ self.filter_attributes = [:backtrace]
6
+
5
7
  has_one :parent_cause, class_name: "ActiveError::Fault",
6
8
  foreign_key: :cause_id, inverse_of: :cause,
7
9
  dependent: :restrict_with_error
8
10
  belongs_to :cause, optional: true, class_name: "ActiveError::Fault",
9
11
  dependent: :destroy
10
- has_many :instances, dependent: :destroy
12
+ has_many :instances, dependent: :delete_all
11
13
 
12
14
  store :options, accessors: [:template], coder: YAML,
13
15
  yaml: { unsafe_load: true }
@@ -39,12 +41,16 @@ module ActiveError
39
41
  super(Marshal.dump(new_template))
40
42
  end
41
43
 
44
+ def location
45
+ Rails.backtrace_cleaner.clean(backtrace).first
46
+ end
47
+
42
48
  private
43
49
 
44
50
  def controller_display
45
51
  return unless controller?
46
52
 
47
- " in #{controller.camelize}Controller"
53
+ " in #{controller.camelize}"
48
54
  end
49
55
 
50
56
  def action_display
@@ -3,16 +3,39 @@
3
3
  <p id="notice"><%= notice %><p>
4
4
  </header>
5
5
 
6
- <table>
7
- <tbody>
8
- <% @faults.each do |fault| %>
9
- <tr>
10
- <td>#<%= fault.id %></td>
11
- <td><%= link_to fault.title, fault %></td>
12
- <td class="w-15"><%= time_ago_in_words(fault.created_at).capitalize %> ago</td>
13
- <td class="w-15"><%= fault.occurrences %></td>
14
- <td class="w-5"><%= button_to 'Resolve', fault, method: :delete, form: { onSubmit: "return confirm('Are you sure?')" }, class: "button-as-link" %></td>
15
- </tr>
16
- <% end %>
17
- </tbody>
18
- </table>
6
+ <div class="table">
7
+ <% @faults.each do |fault| %>
8
+ <div class="tr">
9
+ <div class="td chevron">▶</div>
10
+ <div class="td">#<%= fault.id %></div>
11
+ <div class="td location">
12
+ <%= link_to fault.title, fault_path(fault) %>
13
+
14
+ <% if fault.location.present? %>
15
+ <span><%= fault.location %></span>
16
+ <% end %>
17
+ </div>
18
+ <div class="td"><%= time_ago_in_words(fault.created_at).capitalize %> ago</div>
19
+ <div class="td"><%= fault.occurrences %></div>
20
+ <div class="td"><%= button_to 'Resolve', fault, method: :delete, form: { onSubmit: "return confirm('Are you sure?')" }, class: "button-as-link" %></div>
21
+ <div class="all-cols hidden">
22
+ <% fault.instances.each do |instance| %>
23
+ <div>
24
+ <div><%= link_to instance.url, fault_instance_path(fault, instance) %></div>
25
+ <div><%= time_ago_in_words(instance.created_at).capitalize %> ago</div>
26
+ <div><%= instance.user_agent_display %></div>
27
+ </div>
28
+ <% end %>
29
+ </div>
30
+ </div>
31
+ <% end %>
32
+ </div>
33
+
34
+ <script>
35
+ document.querySelectorAll(".chevron").forEach((el) => {
36
+ el.addEventListener("click", (event) => {
37
+ event.target.parentElement.querySelector(".all-cols").classList.toggle("hidden")
38
+ event.target.classList.toggle("rotate")
39
+ })
40
+ })
41
+ </script>
@@ -5,96 +5,7 @@
5
5
  <%= csrf_meta_tags %>
6
6
  <%= csp_meta_tag %>
7
7
 
8
- <style>
9
- .active_error body {
10
- background-color: #FAFAFA;
11
- color: #333;
12
- color-scheme: light dark;
13
- supported-color-schemes: light dark;
14
- margin: 0px;
15
- }
16
-
17
- @media (prefers-color-scheme: dark) {
18
- .active_error body {
19
- background-color: #222;
20
- color: #ECECEC;
21
- }
22
- }
23
-
24
- .active_error body, .active_error p, .active_error ol, .active_error ul, .active_error td {
25
- font-family: helvetica, verdana, arial, sans-serif;
26
- font-size: 13px;
27
- line-height: 18px;
28
- }
29
-
30
- .active_error .button-as-link {
31
- border: none;
32
- text-decoration: underline;
33
- cursor: pointer;
34
- background: none;
35
- font-size: 15px;
36
- margin: 0;
37
- padding: 0;
38
- line-height: 18px;
39
- }
40
-
41
- .active_error a, .active_error .button-as-link { color: #980905; }
42
- .active_error a:visited, .active_error .button-as-link:visited { color: #666; }
43
- .active_error a.trace-frames {
44
- color: #666;
45
- overflow-wrap: break-word;
46
- }
47
- .active_error a:hover, .active_error .button-as-link:hover, .active_error a.trace-frames.selected { color: #C00; }
48
- .active_error a.summary:hover { color: #FFF; }
49
-
50
- .active_error th {
51
- padding-bottom: 5px;
52
- }
53
-
54
- .active_error td {
55
- padding: 0 5px 7px;
56
- }
57
-
58
- .active_error #notice {
59
- color: green;
60
- margin: 0px;
61
- }
62
-
63
- .active_error header {
64
- color: #f0f0f0;
65
- background: #C00;
66
- padding: 0.5em 1.5em;
67
- display: flex;
68
- flex-direction: row;
69
- align-items: center;
70
- margin-bottom: 0.83em;
71
- }
72
-
73
- .active_error h1 {
74
- flex: 1;
75
- overflow-wrap: break-word;
76
- margin: 0.2em 0;
77
- line-height: 1.1em;
78
- font-size: 2em;
79
- }
80
-
81
- .active_error table {
82
- padding: 0 1.5em;
83
- width: 100%;
84
- }
85
-
86
- .active_error table tr td:first-of-type {
87
- padding-left: 0;
88
- }
89
-
90
- .active_error .w-5 {
91
- width: 5%;
92
- }
93
-
94
- .active_error .w-15 {
95
- width: 15%;
96
- }
97
- </style>
8
+ <%= stylesheet_link_tag "activeerror/application" %>
98
9
  </head>
99
10
  <body><%= yield %></body>
100
11
  </html>
@@ -0,0 +1,278 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta name="turbo-visit-control" content="reload">
7
+ <title>Action Controller: Exception caught</title>
8
+ <%= stylesheet_link_tag "activeerror/application" %>
9
+ <link rel="preconnect" href="https://fonts.googleapis.com">
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400&display=swap" rel="stylesheet">
12
+ <style>
13
+ body {
14
+ background-color: #FAFAFA;
15
+ color: #333;
16
+ color-scheme: light dark;
17
+ supported-color-schemes: light dark;
18
+ margin: 0px;
19
+ }
20
+
21
+ pre, code {
22
+ font-family: "JetBrains Mono", monospace;
23
+ font-optical-sizing: auto;
24
+ font-weight: 400;
25
+ font-style: normal;
26
+ }
27
+
28
+ body, p, ol, ul, td {
29
+ font-family: "Calibre", helvetica, verdana, arial, sans-serif;
30
+ font-size: 15px;
31
+ line-height: 18px;
32
+ }
33
+
34
+ pre {
35
+ font-size: 11px;
36
+ white-space: pre-wrap;
37
+ }
38
+
39
+ pre.box {
40
+ border: 1px solid #EEE;
41
+ padding: 10px;
42
+ margin: 0px;
43
+ width: 958px;
44
+ }
45
+
46
+ header {
47
+ color: #F0F0F0;
48
+ background: #C00;
49
+ padding: 0.5em 1.5em;
50
+ }
51
+
52
+ h1 {
53
+ overflow-wrap: break-word;
54
+ margin: 0.2em 0;
55
+ line-height: 1.1em;
56
+ font-size: 2em;
57
+ }
58
+
59
+ header {
60
+ color: #D30001;
61
+ background: rgb(238, 231, 233);
62
+ padding: 7.5px 22.5px;
63
+ display: flex;
64
+ flex-direction: row;
65
+ justify-content: space-between;
66
+ align-items: center;
67
+ }
68
+
69
+ h1 {
70
+ flex: 1;
71
+ overflow-wrap: break-word;
72
+ margin: 0.2em 0;
73
+ line-height: 1.1em;
74
+ font-size: 30px;
75
+ font-family: "Calibre";
76
+ }
77
+
78
+ h2 {
79
+ color: #C00;
80
+ line-height: 25px;
81
+ }
82
+
83
+ code.traces {
84
+ font-size: 11px;
85
+ }
86
+
87
+ .response-heading, .request-heading {
88
+ margin-top: 30px;
89
+ font-family: "Calibre";
90
+ font-size: 22px;
91
+ }
92
+
93
+ .exception-message {
94
+ padding: 8px 0;
95
+ }
96
+
97
+ .exception-message .message {
98
+ margin-bottom: 8px;
99
+ line-height: 25px;
100
+ font-size: 24px;
101
+ font-weight: 600;
102
+ color: #C00;
103
+ font-family: "Calibre";
104
+ }
105
+
106
+ .details {
107
+ border: 1px solid #D0D0D0;
108
+ border-radius: 4px;
109
+ margin: 1em 0px;
110
+ display: block;
111
+ max-width: 978px;
112
+ }
113
+
114
+ .summary {
115
+ padding: 8px 15px;
116
+ border-bottom: 1px solid #D0D0D0;
117
+ display: block;
118
+ }
119
+
120
+ a.summary {
121
+ color: #F0F0F0;
122
+ text-decoration: none;
123
+ background: #C52F24;
124
+ border-bottom: none;
125
+ }
126
+
127
+ .details pre {
128
+ margin: 5px;
129
+ border: none;
130
+ }
131
+
132
+ #container {
133
+ box-sizing: border-box;
134
+ width: 100%;
135
+ padding: 0 1.5em;
136
+ }
137
+
138
+ .source * {
139
+ margin: 0px;
140
+ padding: 0px;
141
+ }
142
+
143
+ .source {
144
+ border: 1px solid #D9D9D9;
145
+ background: #ECECEC;
146
+ max-width: 978px;
147
+ }
148
+
149
+ .source pre {
150
+ padding: 10px 0px;
151
+ border: none;
152
+ }
153
+
154
+ .source .data {
155
+ font-size: 80%;
156
+ overflow: auto;
157
+ background-color: #FFF;
158
+ }
159
+
160
+ .info {
161
+ padding: 0.5em;
162
+ }
163
+
164
+ .source .data .line_numbers {
165
+ background-color: #ECECEC;
166
+ color: #555;
167
+ padding: 1em .5em;
168
+ border-right: 1px solid #DDD;
169
+ text-align: right;
170
+ }
171
+
172
+ .line {
173
+ padding-left: 10px;
174
+ white-space: pre;
175
+ }
176
+
177
+ .line:hover {
178
+ background-color: #F6F6F6;
179
+ }
180
+
181
+ .line.active {
182
+ background-color: #FCC;
183
+ }
184
+
185
+ .error_highlight {
186
+ display: inline-block;
187
+ background-color: #FF9;
188
+ text-decoration: #F00 wavy underline;
189
+ }
190
+
191
+ .error_highlight_tip {
192
+ color: #666;
193
+ padding: 2px 2px;
194
+ font-size: 10px;
195
+ }
196
+
197
+ .button_to {
198
+ display: inline-block;
199
+ margin-top: 0.75em;
200
+ margin-bottom: 0.75em;
201
+ }
202
+
203
+ .hidden {
204
+ display: none;
205
+ }
206
+
207
+ .correction {
208
+ list-style-type: none;
209
+ }
210
+
211
+ input[type="submit"] {
212
+ color: white;
213
+ background-color: #C00;
214
+ border: none;
215
+ border-radius: 12px;
216
+ box-shadow: 0 3px #F99;
217
+ font-size: 13px;
218
+ font-weight: bold;
219
+ margin: 0;
220
+ padding: 10px 18px;
221
+ cursor: pointer;
222
+ -webkit-appearance: none;
223
+ }
224
+ input[type="submit"]:focus,
225
+ input[type="submit"]:hover {
226
+ opacity: 0.8;
227
+ }
228
+ input[type="submit"]:active {
229
+ box-shadow: 0 2px #F99;
230
+ transform: translateY(1px)
231
+ }
232
+
233
+ a { color: #980905; }
234
+ a:visited { color: #666; }
235
+ a.trace-frames {
236
+ color: #666;
237
+ overflow-wrap: break-word;
238
+ }
239
+ a:hover, a.trace-frames.selected { color: #C00; }
240
+ a.summary:hover { color: #FFF; }
241
+
242
+ h2.response-heading {
243
+ display: none;
244
+ &+p {
245
+ display: none;
246
+ &+pre {
247
+ display: none;
248
+ }
249
+ }
250
+ }
251
+ <%= yield :style %>
252
+ </style>
253
+
254
+ <script>
255
+ var toggle = function(id) {
256
+ document.getElementById(id).classList.toggle('hidden');
257
+ return false;
258
+ }
259
+ var show = function(id) {
260
+ document.getElementById(id).style.display = 'block';
261
+ }
262
+ var hide = function(id) {
263
+ document.getElementById(id).style.display = 'none';
264
+ }
265
+ var toggleSessionDump = function() {
266
+ return toggle('session_dump');
267
+ }
268
+ var toggleEnvDump = function() {
269
+ return toggle('env_dump');
270
+ }
271
+ </script>
272
+ </head>
273
+ <body>
274
+
275
+ <%= yield %>
276
+
277
+ </body>
278
+ </html>
data/config/routes.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  ActiveError::Engine.routes.draw do
4
- resources :faults, only: %i(index show destroy) do
4
+ resources :faults, only: %i(show index destroy) do
5
5
  scope module: :faults do
6
6
  resources :instances, only: :show
7
7
  end
@@ -4,14 +4,14 @@ class CreateActiveErrorFaults < ActiveRecord::Migration[7.1]
4
4
  def change # rubocop:disable Metrics/AbcSize
5
5
  create_table :active_error_faults do |t|
6
6
  t.belongs_to :cause
7
- t.binary :backtrace, lmit: 512.megabytes
8
- t.binary :backtrace_locations, lmit: 512.megabytes
7
+ t.binary :backtrace, limit: 512.megabytes
8
+ t.binary :backtrace_locations, limit: 512.megabytes
9
9
  t.string :klass
10
10
  t.text :message
11
11
  t.string :controller
12
12
  t.string :action
13
13
  t.integer :instances_count
14
- t.text :blamed_files, lmit: 512.megabytes
14
+ t.text :blamed_files, limit: 512.megabytes
15
15
  t.text :options
16
16
  t.index %i(klass backtrace message)
17
17
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveError
4
- BacktraceLocation = Struct.new(:absolute_path, :base_label, :to_s, :label, # rubocop:disable Lint/StructNewOverride
4
+ BacktraceLocation = Struct.new(:absolute_path, :base_label, :to_s, :label,
5
5
  :lineno, :path) do
6
6
  def inspect = to_s
7
7
 
@@ -42,7 +42,8 @@ module ActiveError
42
42
  end
43
43
 
44
44
  def template?
45
- exception.class.is_a?(ActionView::Template::Error)
45
+ exception.is_a?(ActionView::Template::Error) ||
46
+ exception.class.is_a?(ActionView::Template::Error)
46
47
  end
47
48
 
48
49
  def template
@@ -7,9 +7,19 @@ module ActiveError
7
7
  class Engine < ::Rails::Engine
8
8
  isolate_namespace ActiveError
9
9
 
10
- initializer "active_error.middleware" do |app|
11
- app.config.middleware.use ActiveError::Middleware
10
+ config.active_error = ActiveSupport::OrderedOptions.new
12
11
 
12
+ initializer "active_error.error_reporter" do |_app|
13
+ Rails.error.subscribe(::ActiveError::ErrorSubscriber.new)
14
+ end
15
+
16
+ initializer "active_error.config" do
17
+ config.active_error.each do |name, value|
18
+ ActiveError.public_send(:"#{name}=", value)
19
+ end
20
+ end
21
+
22
+ initializer "active_error.context" do
13
23
  ActionController::Base.before_action do
14
24
  Rails.error.set_context(active_error_request: request)
15
25
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveError
4
+ class ErrorSubscriber
5
+ def report(exception, context:, handled:, **_opts)
6
+ return if !ActiveError.enabled? || handled ||
7
+ ActiveError.ignored_classes.include?(exception.class.to_s)
8
+
9
+ Captor.new(exception:, request: context[:active_error_request]).capture
10
+ end
11
+ end
12
+ end
@@ -8,7 +8,11 @@ module ActiveError
8
8
  end
9
9
 
10
10
  def body
11
- @body ||= template.render(template: file, layout: "rescues/layout")
11
+ @body ||= begin
12
+ set_lookup_context
13
+
14
+ template.render(template: file, layout: "active_error/rescue")
15
+ end
12
16
  end
13
17
 
14
18
  private
@@ -16,27 +20,39 @@ module ActiveError
16
20
  attr_reader :exception, :instance
17
21
 
18
22
  delegate :trace_to_show, :source_to_show_id, :source_extracts,
19
- :traces, to: :wrapper
20
-
21
- def backtrace_cleaner
22
- Rails.backtrace_cleaner
23
- end
23
+ :traces, to: :exception_wrapper
24
24
 
25
- def wrapper
26
- @wrapper ||=
27
- ActionDispatch::ExceptionWrapper.new(backtrace_cleaner, exception)
25
+ def exception_wrapper
26
+ @exception_wrapper ||=
27
+ ActionDispatch::ExceptionWrapper.new(Rails.backtrace_cleaner, exception)
28
28
  end
29
29
 
30
30
  def file
31
- "rescues/#{wrapper.rescue_template}"
31
+ "rescues/#{exception_wrapper.rescue_template}"
32
32
  end
33
33
 
34
34
  def template
35
- ActionDispatch::DebugView.new(
36
- request: instance.request, exception_wrapper: wrapper,
37
- exception: wrapper.exception, traces:,
38
- show_source_idx: source_to_show_id, trace_to_show:, source_extracts:
39
- )
35
+ @template ||=
36
+ ActionDispatch::DebugView.
37
+ new(request: instance.request, exception_wrapper:, traces:,
38
+ exception: exception_wrapper.exception, trace_to_show:,
39
+ source_extracts:, show_source_idx: source_to_show_id,)
40
+ end
41
+
42
+ def set_lookup_context
43
+ template.define_singleton_method :lookup_context= do |new_context|
44
+ @lookup_context = new_context
45
+ @view_renderer = ActionView::Renderer.new @lookup_context
46
+ end
47
+
48
+ template.lookup_context = new_lookup_context
49
+ end
50
+
51
+ def new_lookup_context
52
+ ActionView::LookupContext.new([
53
+ *ActionDispatch::DebugView::RESCUES_TEMPLATE_PATHS.dup,
54
+ ActiveError::Engine.root.join("app/views/layouts").to_s
55
+ ])
40
56
  end
41
57
  end
42
58
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveError
4
- VERSION = "1.1.1"
4
+ VERSION = "2.0.0"
5
5
  end
data/lib/active_error.rb CHANGED
@@ -1,15 +1,45 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_error/error_subscriber"
3
4
  require "active_error/exception_mock/default"
4
5
  require "active_error/exception_mock/template_error"
5
6
  require "active_error/exception_mock"
6
7
  require "active_error/captor"
7
- require "active_error/middleware"
8
8
  require "active_error/renderer"
9
9
  require "active_error/engine"
10
- require "active_error/railtie"
11
10
  require "active_error/version"
12
11
 
13
12
  module ActiveError
14
- mattr_accessor :ignored
13
+ mattr_accessor :ignored, :enabled
14
+
15
+ IGNORE_DEFAULT = [
16
+ "AbstractController::ActionNotFound",
17
+ "ActionController::BadRequest",
18
+ "ActionController::InvalidAuthenticityToken",
19
+ "ActionController::InvalidCrossOriginRequest",
20
+ "ActionController::MethodNotAllowed",
21
+ "ActionController::NotImplemented",
22
+ "ActionController::ParameterMissing",
23
+ "ActionController::RoutingError",
24
+ "ActionController::UnknownAction",
25
+ "ActionController::UnknownFormat",
26
+ "ActionDispatch::Http::MimeNegotiation::InvalidType",
27
+ "ActionController::UnknownHttpMethod",
28
+ "ActionDispatch::Http::Parameters::ParseError",
29
+ "ActiveRecord::RecordNotFound"
30
+ ].freeze
31
+
32
+ class << self
33
+ def ignored_classes
34
+ ignored.to_a + IGNORE_DEFAULT
35
+ end
36
+
37
+ def enabled?
38
+ if enabled.nil?
39
+ !Rails.env.local?
40
+ else
41
+ enabled.present?
42
+ end
43
+ end
44
+ end
15
45
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc "Copy over the migrations and mount route for ActiveError"
4
+ namespace :active_error do
5
+ task install: :environment do
6
+ Rails::Command.invoke :generate, ["active_error:install"]
7
+ end
8
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeerror
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Pezza
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-09 00:00:00.000000000 Z
11
+ date: 2024-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '7.1'
19
+ version: '7.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '7.1'
26
+ version: '7.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: useragent
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -48,6 +48,12 @@ files:
48
48
  - LICENSE.md
49
49
  - README.md
50
50
  - Rakefile
51
+ - app/assets/stylesheets/activeerror/application.css
52
+ - app/assets/stylesheets/activeerror/calibre-bold.woff2
53
+ - app/assets/stylesheets/activeerror/calibre-regular-italic.woff2
54
+ - app/assets/stylesheets/activeerror/calibre-regular.woff2
55
+ - app/assets/stylesheets/activeerror/calibre-semibold-italic.woff2
56
+ - app/assets/stylesheets/activeerror/calibre-semibold.woff2
51
57
  - app/controllers/active_error/application_controller.rb
52
58
  - app/controllers/active_error/faults/instances_controller.rb
53
59
  - app/controllers/active_error/faults_controller.rb
@@ -55,23 +61,23 @@ files:
55
61
  - app/models/active_error/fault.rb
56
62
  - app/models/active_error/instance.rb
57
63
  - app/views/active_error/faults/index.html.erb
58
- - app/views/active_error/faults/show.html.erb
59
64
  - app/views/layouts/active_error/application.html.erb
65
+ - app/views/layouts/active_error/rescue.html.erb
60
66
  - config/routes.rb
61
67
  - db/migrate/20200727220359_create_active_error_faults.rb
62
68
  - db/migrate/20200727225318_create_active_error_instances.rb
63
69
  - lib/active_error.rb
64
70
  - lib/active_error/captor.rb
65
71
  - lib/active_error/engine.rb
72
+ - lib/active_error/error_subscriber.rb
66
73
  - lib/active_error/exception_mock.rb
67
74
  - lib/active_error/exception_mock/default.rb
68
75
  - lib/active_error/exception_mock/template_error.rb
69
- - lib/active_error/middleware.rb
70
- - lib/active_error/railtie.rb
71
76
  - lib/active_error/renderer.rb
72
77
  - lib/active_error/version.rb
73
78
  - lib/activeerror.rb
74
79
  - lib/generators/active_error/install/install_generator.rb
80
+ - lib/tasks/active_error_tasks.rake
75
81
  homepage: https://github.com/npezza93/activeerror
76
82
  licenses:
77
83
  - MIT
@@ -85,14 +91,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
85
91
  requirements:
86
92
  - - ">="
87
93
  - !ruby/object:Gem::Version
88
- version: 3.1.0
94
+ version: 3.2.0
89
95
  required_rubygems_version: !ruby/object:Gem::Requirement
90
96
  requirements:
91
97
  - - ">="
92
98
  - !ruby/object:Gem::Version
93
99
  version: '0'
94
100
  requirements: []
95
- rubygems_version: 3.5.3
101
+ rubygems_version: 3.5.18
96
102
  signing_key:
97
103
  specification_version: 4
98
104
  summary: Rails exception logger
@@ -1,17 +0,0 @@
1
- <header>
2
- <h1>Instances of <%= @fault.title %> (Fault #<%= @fault.id %>)</h1>
3
- <p id="notice"><%= notice %><p>
4
- </header>
5
-
6
- <table>
7
- <tbody>
8
- <% @fault.instances.each do |instance| %>
9
- <tr>
10
- <td>#<%= instance.id %></td>
11
- <td><%= link_to instance.url, fault_instance_path(@fault, instance) %></td>
12
- <td class="w-15"><%= instance.user_agent_display %></td>
13
- <td class="w-15"><%= time_ago_in_words(instance.created_at).capitalize %> ago</td>
14
- </tr>
15
- <% end %>
16
- </tbody>
17
- </table>
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActiveError
4
- class Middleware
5
- def initialize(app)
6
- @app = app
7
- end
8
-
9
- def call(env)
10
- @app.call(env)
11
- rescue StandardError => e
12
- unless Rails.application.config.reloading_enabled?
13
- Rails.error.report(e, handled: false,
14
- source: "application.action_dispatch")
15
- end
16
- raise
17
- end
18
- end
19
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActiveError
4
- class ErrorSubscriber
5
- def report(exception, context:, handled:, **_opts)
6
- return if Rails.env.development? || handled ||
7
- ActiveError.ignored.to_a.include?(exception.class.to_s)
8
-
9
- Captor.new(exception:, request: context[:active_error_request]).capture
10
- end
11
- end
12
-
13
- class Railtie < ::Rails::Railtie
14
- initializer "active_error.error_reporter" do |_app|
15
- Rails.error.subscribe(::ActiveError::ErrorSubscriber.new)
16
- end
17
- end
18
- end