coaster 1.3.9 → 1.3.10
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 +132 -3
- data/lib/coaster/core_ext/month.rb +4 -4
- data/lib/coaster/core_ext/object_translation.rb +3 -3
- data/lib/coaster/core_ext/standard_error/sentry.rb +2 -0
- data/lib/coaster/core_ext/standard_error.rb +115 -37
- data/lib/coaster/rails_ext/backtrace_cleaner.rb +26 -0
- data/lib/coaster/rails_ext.rb +1 -0
- data/lib/coaster/version.rb +1 -1
- data/lib/coaster.rb +2 -2
- data/test/test_backtrace.rb +182 -0
- data/test/test_month.rb +14 -0
- data/test/test_standard_error.rb +76 -27
- metadata +9 -4
- data/lib/coaster/backtrace_cleaner.rb +0 -78
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5b2e4ea7b170f104949852f0413f81dac320102b8045377554d8fcc8034004fd
|
|
4
|
+
data.tar.gz: d20610716bddf3fada3e41f6b9762738ce0eaa3aca7072e5b612d93539d10d0c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bf519218cfcabfbe77f9cc8f6f56aafa6810048e443098fa725b0039684806413da62130545265969d43bea81f185811362c35dc1330bac688497fbd5af99287
|
|
7
|
+
data.tar.gz: 283eb1f6a28247e902bdc986f244b249ceace63fb661c89700e0fe914b598da2acca9147334988de6d472c9327549e256ad4c34f611974dd5977e94053aedd3e
|
data/README.md
CHANGED
|
@@ -79,10 +79,139 @@ Hash로 전달되는 특수한 attribute가 있다.
|
|
|
79
79
|
|
|
80
80
|
|
|
81
81
|
그 외에 error instance variable로 등록되는 attribute가 있다.
|
|
82
|
-
1. tags: [ActiveSupport::TaggedLogging
|
|
82
|
+
1. tags: [ActiveSupport::TaggedLogging](http://api.rubyonrails.org/classes/ActiveSupport/TaggedLogging.html)에 사용된다.
|
|
83
83
|
1. level: debug, info 등등의 로깅 레벨
|
|
84
84
|
1. tkey: Object Translation 에서 사용된다. 기본값은 '.self'와 동일하다.
|
|
85
85
|
|
|
86
|
-
## StandardError
|
|
86
|
+
## StandardError#logging
|
|
87
|
+
|
|
88
|
+
`StandardError#logging`으로 로깅한다.
|
|
89
|
+
logger는 `Coaster.logger=`를 사용하며 설정이 안돼있을 경우 `Rails.logger`를 사용한다.
|
|
90
|
+
cleaner(`AcitveSupport::BacktraceCleaner`)는 `StandardError.cleaner=`, `StandardError.cause_cleaner=`를 사용하며
|
|
91
|
+
기본값은 없으며 cleaner가 없을 경우 backtrace를 출력하지 않는다.
|
|
92
|
+
|
|
93
|
+
1. options
|
|
94
|
+
1. `:logger` => 기본 logger를 대체할 logger
|
|
95
|
+
1. `:cleaner` => 해당 에러를 로깅할때 사용할 cleaner
|
|
96
|
+
1. before_logging_blocks, after_loggin_blocks
|
|
97
|
+
1. `logging` 전후 처리를 추가할 수 있으며 추가된 block은 error instance 내에서 실행된다.
|
|
98
|
+
1. ```
|
|
99
|
+
StandardError.before_logging(:cloudwatch) do
|
|
100
|
+
ReportCloudWatch.send(self) # self가 에러 자신
|
|
101
|
+
end
|
|
102
|
+
```
|
|
103
|
+
1. log 내용은 `StandardError#to_detail`을 사용
|
|
104
|
+
1. Sentry
|
|
105
|
+
아래와 같이 require를 하면 logging 하기 전 sentry에 보낸다.
|
|
106
|
+
```
|
|
107
|
+
require 'coaster/core_ext/standard_error/sentry'
|
|
108
|
+
```
|
|
109
|
+
([raven.rb](lib/coaster/core_ext/standard_error/raven.rb)는 legacy, 옛날 sentry gem 이름)
|
|
110
|
+
|
|
111
|
+
## StandardError#to_detail
|
|
112
|
+
`logging` 메서드에서 출력한 메시지를 만든다.
|
|
113
|
+
|
|
114
|
+
1. error class, status, message, instance_variables(, backtrace) 순서대로 출력하며
|
|
115
|
+
cause가 존재할 경우 CAUSE이후 tab indent를 하여 출력한다. cause는 최대 3 depth까지 출력한다.
|
|
116
|
+
1. instance_variable
|
|
117
|
+
1. `StandardError.detail_vars` Array에서 있는 값의 출력은 `StandardError.detail_value_proc`으로 출력한다.
|
|
118
|
+
1. `detail_vars` 기본값은 `%i[@attributes @tkey @fingerprint @tags @level]`
|
|
119
|
+
1. `detail_value_proc` 기본값은 `Proc.new{|val| val.inspect}`
|
|
120
|
+
1. 나머지는 `StandardError.detail_value_simpe`로 처리하며 class name만 사용한다.
|
|
121
|
+
|
|
122
|
+
## coaster/rails_ext/backtrace_cleaner
|
|
123
|
+
|
|
124
|
+
[`AcitveSupport::BacktraceCleaner`](https://github.com/rails/rails/blob/main/activesupport/lib/active_support/backtrace_cleaner.rb)에서
|
|
125
|
+
앞쪽은 `silence!`에서 제외하는(즉 모든 backtrace가 포함되는) 로직이 추가된다.
|
|
126
|
+
앞쪽에서 얼마나 포함할지는 `cleaner.minimum_first=`로 설정하며 기본값은 10이다.
|
|
127
|
+
minimum_first 이후 silence된 backtrace사이에 `BacktraceCleaner.minimum_first ... and next silenced backtraces`라인이 끼워진다.
|
|
128
|
+
|
|
129
|
+
## StandardError logging example with backtrace cleaner
|
|
87
130
|
|
|
88
|
-
|
|
131
|
+
```
|
|
132
|
+
[Dynamoid::Errors::RecordNotUnique] status:999999
|
|
133
|
+
MESSAGE: Attempted to write record #<DynamoUserIdentificationLog:0x00005592491a7378> when its key already exists
|
|
134
|
+
@attributes: {}
|
|
135
|
+
@fingerprint: [:default, :class]
|
|
136
|
+
@inner_exception: Attempted to write record #<DynamoUserIdentificationLog:0x00005592491a7378> when its key already exists
|
|
137
|
+
@level: "error"
|
|
138
|
+
@original_exception: Dynamoid::Errors::ConditionalCheckFailedException
|
|
139
|
+
@raven: {}
|
|
140
|
+
@tags: {}
|
|
141
|
+
@tkey: nil
|
|
142
|
+
BACKTRACE:
|
|
143
|
+
dynamoid (3.7.1) lib/dynamoid/persistence/save.rb:30:in `rescue in call'
|
|
144
|
+
dynamoid (3.7.1) lib/dynamoid/persistence/save.rb:15:in `call'
|
|
145
|
+
dynamoid (3.7.1) lib/dynamoid/persistence/save.rb:8:in `call'
|
|
146
|
+
dynamoid (3.7.1) lib/dynamoid/persistence.rb:485:in `block (2 levels) in save'
|
|
147
|
+
activesupport (6.1.4.4) lib/active_support/callbacks.rb:106:in `run_callbacks'
|
|
148
|
+
dynamoid (3.7.1) lib/dynamoid/persistence.rb:484:in `block in save'
|
|
149
|
+
activesupport (6.1.4.4) lib/active_support/callbacks.rb:106:in `run_callbacks'
|
|
150
|
+
dynamoid (3.7.1) lib/dynamoid/persistence.rb:483:in `save'
|
|
151
|
+
dynamoid (3.7.1) lib/dynamoid/dirty.rb:50:in `save'
|
|
152
|
+
dynamoid (3.7.1) lib/dynamoid/validations.rb:19:in `save'
|
|
153
|
+
BacktraceCleaner.minimum_first ... and next silenced backtraces
|
|
154
|
+
exmaple_app/app/models/dynamo_user_identification_log.rb:39:in `record!'
|
|
155
|
+
exmaple_app/app/models/sample_model.rb:156:in `record_authentication_log'
|
|
156
|
+
vendor/bundle/ruby/2.7.0/bin/rspec:25:in `load'
|
|
157
|
+
vendor/bundle/ruby/2.7.0/bin/rspec:25:in `<top (required)>'
|
|
158
|
+
/home/circleci/.rubygems/bin/bundle:25:in `load'
|
|
159
|
+
/home/circleci/.rubygems/bin/bundle:25:in `<main>'
|
|
160
|
+
CAUSE: [Dynamoid::Errors::ConditionalCheckFailedException] status:999999
|
|
161
|
+
MESSAGE: The conditional request failed
|
|
162
|
+
@attributes: {}
|
|
163
|
+
@fingerprint: [:default, :class]
|
|
164
|
+
@inner_exception: Aws::DynamoDB::Errors::ConditionalCheckFailedException
|
|
165
|
+
@level: "error"
|
|
166
|
+
@raven: {}
|
|
167
|
+
@tags: {}
|
|
168
|
+
@tkey: nil
|
|
169
|
+
BACKTRACE:
|
|
170
|
+
dynamoid (3.7.1) lib/dynamoid/adapter_plugin/aws_sdk_v3.rb:471:in `rescue in put_item'
|
|
171
|
+
dynamoid (3.7.1) lib/dynamoid/adapter_plugin/aws_sdk_v3.rb:462:in `put_item'
|
|
172
|
+
dynamoid (3.7.1) lib/dynamoid/adapter.rb:153:in `block (3 levels) in <class:Adapter>'
|
|
173
|
+
dynamoid (3.7.1) lib/dynamoid/adapter.rb:56:in `benchmark'
|
|
174
|
+
dynamoid (3.7.1) lib/dynamoid/adapter.rb:153:in `block (2 levels) in <class:Adapter>'
|
|
175
|
+
dynamoid (3.7.1) lib/dynamoid/adapter.rb:71:in `write'
|
|
176
|
+
dynamoid (3.7.1) lib/dynamoid/persistence/save.rb:24:in `call'
|
|
177
|
+
dynamoid (3.7.1) lib/dynamoid/persistence/save.rb:8:in `call'
|
|
178
|
+
dynamoid (3.7.1) lib/dynamoid/persistence.rb:485:in `block (2 levels) in save'
|
|
179
|
+
activesupport (6.1.4.4) lib/active_support/callbacks.rb:106:in `run_callbacks'
|
|
180
|
+
BacktraceCleaner.minimum_first ... and next silenced backtraces
|
|
181
|
+
exmaple_app/app/models/dynamo_user_identification_log.rb:39:in `record!'
|
|
182
|
+
exmaple_app/app/models/sample_model.rb:156:in `record_authentication_log'
|
|
183
|
+
vendor/bundle/ruby/2.7.0/bin/rspec:25:in `load'
|
|
184
|
+
vendor/bundle/ruby/2.7.0/bin/rspec:25:in `<top (required)>'
|
|
185
|
+
/home/circleci/.rubygems/bin/bundle:25:in `load'
|
|
186
|
+
/home/circleci/.rubygems/bin/bundle:25:in `<main>'
|
|
187
|
+
CAUSE: [Aws::DynamoDB::Errors::ConditionalCheckFailedException] status:999999
|
|
188
|
+
MESSAGE: The conditional request failed
|
|
189
|
+
@attributes: {}
|
|
190
|
+
@code: ConditionalCheckFailedException
|
|
191
|
+
@context: Seahorse::Client::RequestContext
|
|
192
|
+
@data: Aws::DynamoDB::Types::ConditionalCheckFailedException
|
|
193
|
+
@fingerprint: [:default, :class]
|
|
194
|
+
@level: "error"
|
|
195
|
+
@message: The conditional request failed
|
|
196
|
+
@raven: {}
|
|
197
|
+
@tags: {}
|
|
198
|
+
@tkey: nil
|
|
199
|
+
BACKTRACE:
|
|
200
|
+
aws-sdk-core (3.130.0) lib/seahorse/client/plugins/raise_response_errors.rb:17:in `call'
|
|
201
|
+
aws-sdk-dynamodb (1.69.0) lib/aws-sdk-dynamodb/plugins/simple_attributes.rb:119:in `call'
|
|
202
|
+
aws-sdk-core (3.130.0) lib/aws-sdk-core/plugins/jsonvalue_converter.rb:22:in `call'
|
|
203
|
+
aws-sdk-core (3.130.0) lib/aws-sdk-core/plugins/idempotency_token.rb:19:in `call'
|
|
204
|
+
aws-sdk-core (3.130.0) lib/aws-sdk-core/plugins/param_converter.rb:26:in `call'
|
|
205
|
+
aws-sdk-core (3.130.0) lib/seahorse/client/plugins/request_callback.rb:71:in `call'
|
|
206
|
+
aws-sdk-core (3.130.0) lib/aws-sdk-core/plugins/response_paging.rb:12:in `call'
|
|
207
|
+
aws-sdk-core (3.130.0) lib/seahorse/client/plugins/response_target.rb:24:in `call'
|
|
208
|
+
aws-sdk-core (3.130.0) lib/seahorse/client/request.rb:72:in `send_request'
|
|
209
|
+
aws-sdk-dynamodb (1.69.0) lib/aws-sdk-dynamodb/client.rb:4147:in `put_item'
|
|
210
|
+
BacktraceCleaner.minimum_first ... and next silenced backtraces
|
|
211
|
+
example_app/app/models/dynamo_user_identification_log.rb:39:in `record!'
|
|
212
|
+
example_app/app/models/sample_model.rb:156:in `record_authentication_log'
|
|
213
|
+
vendor/bundle/ruby/2.7.0/bin/rspec:25:in `load'
|
|
214
|
+
vendor/bundle/ruby/2.7.0/bin/rspec:25:in `<top (required)>'
|
|
215
|
+
/home/circleci/.rubygems/bin/bundle:25:in `load'
|
|
216
|
+
/home/circleci/.rubygems/bin/bundle:25:in `<main>'
|
|
217
|
+
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'attr_extras' # gem
|
|
2
2
|
|
|
3
3
|
class Month
|
|
4
|
-
vattr_initialize :
|
|
4
|
+
vattr_initialize :_year, :_month
|
|
5
5
|
|
|
6
6
|
class << self
|
|
7
7
|
def from(object)
|
|
@@ -19,7 +19,7 @@ class Month
|
|
|
19
19
|
date = Date.parse(str)
|
|
20
20
|
from(date)
|
|
21
21
|
rescue ArgumentError => e
|
|
22
|
-
if str.instance_variable_get(:@_gsub_)
|
|
22
|
+
if str.instance_variable_defined?(:@_gsub_) && str.instance_variable_get(:@_gsub_)
|
|
23
23
|
raise e, str: str.instance_variable_get(:@_gsub_)
|
|
24
24
|
elsif e.message != 'invalid date'
|
|
25
25
|
raise e, str: str
|
|
@@ -41,11 +41,11 @@ class Month
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def year
|
|
44
|
-
Integer(@
|
|
44
|
+
Integer(@_year)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def month
|
|
48
|
-
Integer(@
|
|
48
|
+
Integer(@_month)
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def first_date
|
|
@@ -14,14 +14,14 @@ class Object
|
|
|
14
14
|
if key.start_with?('.')
|
|
15
15
|
subkey = key
|
|
16
16
|
else
|
|
17
|
-
return I18n.t(key, *args, options)
|
|
17
|
+
return I18n.t(key, *args, **options)
|
|
18
18
|
end
|
|
19
19
|
elsif key.is_a?(Symbol)
|
|
20
20
|
subkey = ".#{key.to_s}"
|
|
21
21
|
elsif key.nil?
|
|
22
22
|
# do nothing
|
|
23
23
|
else
|
|
24
|
-
return I18n.t(key, *args, options)
|
|
24
|
+
return I18n.t(key, *args, **options)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
key_class = options.delete(:class) || self
|
|
@@ -35,7 +35,7 @@ class Object
|
|
|
35
35
|
options[:tkey] ||= key
|
|
36
36
|
options.merge!(throw: true)
|
|
37
37
|
result = catch(:exception) do
|
|
38
|
-
I18n.t(key, *args, options)
|
|
38
|
+
I18n.t(key, *args, **options)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
if result.is_a?(I18n::MissingTranslation)
|
|
@@ -31,6 +31,8 @@ class StandardError
|
|
|
31
31
|
|
|
32
32
|
nt[:tags] ||= (tags && tags.merge(nt[:tags] || {})) || {}
|
|
33
33
|
nt[:tags] = nt[:tags].merge(environment: Rails.env) if defined?(Rails)
|
|
34
|
+
nt[:tags][:digest_message] = digest_message if digest_message.present?
|
|
35
|
+
nt[:tags][:digest_backtrace] = digest_backtrace if digest_backtrace.present?
|
|
34
36
|
nt[:level] ||= self.level
|
|
35
37
|
nt[:extra] = attributes.merge(nt[:extra])
|
|
36
38
|
nt
|
|
@@ -1,17 +1,33 @@
|
|
|
1
|
+
require 'digest'
|
|
1
2
|
require 'coaster/core_ext/object_translation'
|
|
3
|
+
require 'coaster/rails_ext/backtrace_cleaner'
|
|
2
4
|
require 'pp'
|
|
3
5
|
|
|
4
6
|
class StandardError
|
|
5
7
|
cattr_accessor :cleaner, :cause_cleaner
|
|
6
|
-
|
|
8
|
+
|
|
9
|
+
DEFAULT_INSPECTION_VARS = %i[@attributes @tkey @fingerprint @tags @level]
|
|
10
|
+
DEFAULT_INSPECTION_VALUE_PROC = Proc.new{|val| val.inspect}
|
|
7
11
|
|
|
8
12
|
class << self
|
|
13
|
+
attr_writer :inspection_value_proc
|
|
14
|
+
|
|
9
15
|
def status; 999999 end # Unknown
|
|
10
16
|
alias_method :code, :status
|
|
11
17
|
def http_status; 500 end
|
|
12
18
|
def report?; true end
|
|
13
19
|
def intentional?; false end
|
|
14
20
|
def title; _translate('.title') end
|
|
21
|
+
def inspection_vars; @inspection_vars ||= DEFAULT_INSPECTION_VARS.dup end
|
|
22
|
+
def inspection_value_proc; @inspection_value_proc ||= superclass.respond_to?(:inspection_value_proc) ? superclass.inspection_value_proc : DEFAULT_INSPECTION_VALUE_PROC end
|
|
23
|
+
def inspection_value_simple(val)
|
|
24
|
+
case val
|
|
25
|
+
when Array then val.map{|v| inspection_value_simple(v)}
|
|
26
|
+
when Hash then Hash[val.map{|k,v| [k, inspection_value_simple(v)]}]
|
|
27
|
+
when String, Numeric, TrueClass, FalseClass then val
|
|
28
|
+
else val.class.name
|
|
29
|
+
end
|
|
30
|
+
end
|
|
15
31
|
|
|
16
32
|
def before_logging(name, &block)
|
|
17
33
|
@before_logging_blocks ||= {}
|
|
@@ -71,7 +87,7 @@ class StandardError
|
|
|
71
87
|
@attributes[:description] = _translate
|
|
72
88
|
end
|
|
73
89
|
msg = "#{_translate} (#{msg || self.class.name})"
|
|
74
|
-
msg = "#{msg} {#{cause.message}}" if cause
|
|
90
|
+
msg = "#{msg} cause{#{cause.message}}" if cause
|
|
75
91
|
when String then
|
|
76
92
|
msg = message
|
|
77
93
|
when FalseClass, NilClass then
|
|
@@ -87,6 +103,15 @@ class StandardError
|
|
|
87
103
|
end
|
|
88
104
|
|
|
89
105
|
def safe_message; message || '' end
|
|
106
|
+
def digest_message
|
|
107
|
+
m = message.to_s.dup
|
|
108
|
+
mat = m.match(/#<.*0x(?<object_id>\S+)>/)
|
|
109
|
+
m = message.gsub(/#{mat[:object_id]}/, 'XXXXXXX') if mat
|
|
110
|
+
m = "#{self.class.name} #{m}"
|
|
111
|
+
@digest_message ||= Digest::MD5.hexdigest(m)[0...6]
|
|
112
|
+
end
|
|
113
|
+
def digest_backtrace; @digest_backtrace ||= backtrace ? Digest::MD5.hexdigest(cleaned_backtrace.join("\n"))[0...8] : nil end
|
|
114
|
+
def user_digests; @user_digests ||= "#{[digest_message, digest_backtrace].compact.join(' ')}" end
|
|
90
115
|
def status; self.class.status end
|
|
91
116
|
def before_logging_blocks; self.class.before_logging_blocks end
|
|
92
117
|
def after_logging_blocks; self.class.after_logging_blocks end
|
|
@@ -107,6 +132,7 @@ class StandardError
|
|
|
107
132
|
def code; attributes[:code] || status end
|
|
108
133
|
def code=(value); attributes[:code] = value end
|
|
109
134
|
def title; attributes[:title] || self.class.title end
|
|
135
|
+
def detail; attributes[:detail] end
|
|
110
136
|
def it_might_happen?; attributes[:it] == :might_happen end
|
|
111
137
|
def it_should_not_happen?; attributes[:it] == :should_not_happen end
|
|
112
138
|
def report?
|
|
@@ -139,8 +165,9 @@ class StandardError
|
|
|
139
165
|
# user friendly message, for overid
|
|
140
166
|
def user_message
|
|
141
167
|
return _translate if description.present? || tkey.present?
|
|
142
|
-
|
|
143
|
-
|
|
168
|
+
"#{_translate} (#{user_digests})"
|
|
169
|
+
rescue => e
|
|
170
|
+
"#{message} (user_message_error - #{e.class.name} #{e.message})"
|
|
144
171
|
end
|
|
145
172
|
|
|
146
173
|
# another user friendly messages
|
|
@@ -150,52 +177,102 @@ class StandardError
|
|
|
150
177
|
attributes[:descriptions]
|
|
151
178
|
end
|
|
152
179
|
|
|
153
|
-
def to_hash
|
|
154
|
-
|
|
180
|
+
def to_hash(_h: {}.with_indifferent_access, _depth: 0)
|
|
181
|
+
_h.merge!(attributes)
|
|
182
|
+
_h.merge!(
|
|
155
183
|
type: self.class.name, status: status,
|
|
156
184
|
http_status: http_status, message: message
|
|
157
185
|
)
|
|
158
|
-
if cause
|
|
186
|
+
if _depth < 4 && cause
|
|
159
187
|
if cause.respond_to?(:to_hash)
|
|
160
|
-
|
|
188
|
+
_h[:cause] = cause.to_hash(_depth: _depth + 1)
|
|
161
189
|
else
|
|
162
|
-
|
|
190
|
+
_h[:cause_object] = cause
|
|
163
191
|
end
|
|
164
192
|
end
|
|
165
|
-
|
|
193
|
+
_h
|
|
166
194
|
end
|
|
167
195
|
|
|
168
196
|
def to_json
|
|
169
197
|
Oj.dump(to_hash.with_indifferent_access, mode: :compat)
|
|
170
198
|
end
|
|
171
199
|
|
|
172
|
-
def
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
200
|
+
def inspection_vars
|
|
201
|
+
(self.class.inspection_vars + (attributes[:inspection_vars] || [])).map(&:to_sym).compact.uniq
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def inspection_value_proc
|
|
205
|
+
attributes[:inspection_value_proc] || self.class.inspection_value_proc
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def to_inspection_hash(options: {}, _h: {}.with_indifferent_access, _depth: 0)
|
|
209
|
+
_h.merge!(
|
|
210
|
+
type: self.class.name, status: status,
|
|
211
|
+
http_status: http_status, message: message,
|
|
212
|
+
instance_variables: {}.with_indifferent_access
|
|
213
|
+
)
|
|
214
|
+
instance_variables.sort.each do |var|
|
|
215
|
+
if inspection_vars.include?(var)
|
|
216
|
+
val = instance_variable_get(var)
|
|
217
|
+
val = inspection_value_proc.call(val) rescue val.to_s
|
|
218
|
+
_h[:instance_variables][var] = val
|
|
219
|
+
elsif var.to_s.start_with?('@__')
|
|
179
220
|
next
|
|
180
221
|
else
|
|
181
222
|
val = instance_variable_get(var)
|
|
182
|
-
|
|
183
|
-
lg += "\n\t#{var}: #{val}"
|
|
223
|
+
_h[:instance_variables][var] = self.class.inspection_value_simple(val)
|
|
184
224
|
end
|
|
185
225
|
end
|
|
186
|
-
if
|
|
187
|
-
if
|
|
188
|
-
|
|
189
|
-
|
|
226
|
+
if backtrace.present?
|
|
227
|
+
if respond_to?(:cleaned_backtrace)
|
|
228
|
+
if (bt = cleaned_backtrace(options))
|
|
229
|
+
_h[:backtrace] = bt
|
|
230
|
+
else
|
|
231
|
+
_h[:backtrace] = backtrace[0...ActiveSupport::BacktraceCleaner.minimum_first]
|
|
232
|
+
end
|
|
190
233
|
else
|
|
191
|
-
|
|
234
|
+
_h[:backtrace] = backtrace[0...ActiveSupport::BacktraceCleaner.minimum_first]
|
|
192
235
|
end
|
|
193
|
-
|
|
194
|
-
|
|
236
|
+
end
|
|
237
|
+
if cause
|
|
238
|
+
if _depth < 4
|
|
239
|
+
if cause.respond_to?(:to_inspection_hash)
|
|
240
|
+
_h[:cause] = cause.to_inspection_hash(options: options, _depth: _depth + 1)
|
|
241
|
+
else
|
|
242
|
+
cause_h = {
|
|
243
|
+
type: self.class.name, status: status,
|
|
244
|
+
http_status: http_status, message: message,
|
|
245
|
+
}
|
|
246
|
+
cause_h.merge!(backtrace: cause.backtrace[0...ActiveSupport::BacktraceCleaner.minimum_first])
|
|
247
|
+
_h[:cause] = cause_h
|
|
248
|
+
end
|
|
249
|
+
else
|
|
250
|
+
_h[:cause] = 'and more causes...'
|
|
195
251
|
end
|
|
196
252
|
end
|
|
253
|
+
_h
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def to_inspection_s(options: {}, _dh: nil)
|
|
257
|
+
dh = _dh || to_inspection_hash(options: options, _h: {}.with_indifferent_access, _depth: 0)
|
|
258
|
+
lg = "[#{dh[:type]}] status:#{dh[:status]}"
|
|
259
|
+
lg += "\n MESSAGE: #{dh[:message]&.gsub(/\n/, "\n ")}"
|
|
260
|
+
dh[:instance_variables].each do |var, val|
|
|
261
|
+
lg += "\n #{var}: #{val}"
|
|
262
|
+
end
|
|
263
|
+
if (bt = dh[:backtrace] || [])
|
|
264
|
+
lg += "\n BACKTRACE:\n "
|
|
265
|
+
lg += bt.join("\n ")
|
|
266
|
+
end
|
|
267
|
+
if dh[:cause].is_a?(Hash)
|
|
268
|
+
lg += "\n CAUSE: "
|
|
269
|
+
lg += to_inspection_s(options: options, _dh: dh[:cause]).strip.gsub(/\n/, "\n ")
|
|
270
|
+
elsif dh[:cause].is_a?(String)
|
|
271
|
+
lg += dh[:cause]
|
|
272
|
+
end
|
|
197
273
|
lg << "\n"
|
|
198
274
|
end
|
|
275
|
+
alias_method :to_detail, :to_inspection_s
|
|
199
276
|
|
|
200
277
|
def rails_tag
|
|
201
278
|
(fingerprint || Coaster.default_fingerprint).flatten.map do |fp|
|
|
@@ -209,8 +286,17 @@ class StandardError
|
|
|
209
286
|
end.compact
|
|
210
287
|
end
|
|
211
288
|
|
|
289
|
+
def cleaned_backtrace(options = {})
|
|
290
|
+
return unless backtrace
|
|
291
|
+
cl = options[:cleaner] || cleaner
|
|
292
|
+
return backtrace unless cl
|
|
293
|
+
bt = cl.clean(backtrace)
|
|
294
|
+
bt = bt[0..2] if intentional?
|
|
295
|
+
bt
|
|
296
|
+
end
|
|
297
|
+
|
|
212
298
|
def logging(options = {})
|
|
213
|
-
before_logging_blocks.values.each { |blk| instance_exec
|
|
299
|
+
before_logging_blocks.values.each { |blk| instance_exec(&blk) }
|
|
214
300
|
|
|
215
301
|
if !report? || intentional?
|
|
216
302
|
if defined?(Rails)
|
|
@@ -223,15 +309,7 @@ class StandardError
|
|
|
223
309
|
logger = options[:logger] || Coaster.logger
|
|
224
310
|
return unless logger
|
|
225
311
|
|
|
226
|
-
|
|
227
|
-
msg = to_detail
|
|
228
|
-
|
|
229
|
-
if cl && backtrace
|
|
230
|
-
bt = cl.clean(backtrace)
|
|
231
|
-
bt = bt[0..2] if intentional?
|
|
232
|
-
msg += "\tBACKTRACE:\n\t"
|
|
233
|
-
msg += bt.join("\n\t")
|
|
234
|
-
end
|
|
312
|
+
msg = to_inspection_s(options: options)
|
|
235
313
|
|
|
236
314
|
if level && logger.respond_to?(level)
|
|
237
315
|
logger.send(level, msg)
|
|
@@ -240,6 +318,6 @@ class StandardError
|
|
|
240
318
|
end
|
|
241
319
|
msg
|
|
242
320
|
ensure
|
|
243
|
-
after_logging_blocks.values.each { |blk| instance_exec
|
|
321
|
+
after_logging_blocks.values.each { |blk| instance_exec(&blk) }
|
|
244
322
|
end
|
|
245
323
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'active_support/backtrace_cleaner'
|
|
2
|
+
|
|
3
|
+
class ActiveSupport::BacktraceCleaner
|
|
4
|
+
attr_writer :minimum_first
|
|
5
|
+
|
|
6
|
+
def minimum_first
|
|
7
|
+
@minimum_first ||= 10
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
alias_method :original_silence, :silence
|
|
12
|
+
def silence(backtrace)
|
|
13
|
+
@silencers.each do |s|
|
|
14
|
+
ix = 0
|
|
15
|
+
backtrace = backtrace.reject do |line|
|
|
16
|
+
ix += 1
|
|
17
|
+
next if ix <= minimum_first
|
|
18
|
+
s.call(line)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
backtrace = backtrace.to_a
|
|
23
|
+
backtrace.insert(minimum_first, 'BacktraceCleaner.minimum_first ... and next silenced backtraces')
|
|
24
|
+
backtrace
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'coaster/rails_ext/backtrace_cleaner'
|
data/lib/coaster/version.rb
CHANGED
data/lib/coaster.rb
CHANGED
|
@@ -22,7 +22,7 @@ module Coaster
|
|
|
22
22
|
def logger
|
|
23
23
|
return @@logger if defined?(@@logger) && @@logger
|
|
24
24
|
return Rails.logger if defined?(Rails)
|
|
25
|
-
|
|
25
|
+
@@logger = Logger.new(STDOUT)
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
@@ -32,4 +32,4 @@ module Coaster
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
require 'coaster/core_ext'
|
|
35
|
-
require 'coaster/
|
|
35
|
+
require 'coaster/rails_ext'
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'minitest/autorun'
|
|
3
|
+
|
|
4
|
+
module Coaster
|
|
5
|
+
class TestBacktrace < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
@backtrace = <<~EOS.chomp.split("\n")
|
|
8
|
+
/home/circleci/project/app/controllers/application_controller.rb:174:in `block (2 levels) in block_fun'
|
|
9
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.4.4/lib/action_controller/metal/mime_responds.rb:214:in `respond_to'
|
|
10
|
+
/home/circleci/project/app/controllers/application_controller.rb:170:in `block_fun'
|
|
11
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/callbacks.rb:427:in `block in make_lambda'
|
|
12
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/callbacks.rb:198:in `block (2 levels) in halting'
|
|
13
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.4.4/lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in <module:Callbacks>'
|
|
14
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/callbacks.rb:199:in `block in halting'
|
|
15
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/callbacks.rb:512:in `block in invoke_before'
|
|
16
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/callbacks.rb:512:in `each'
|
|
17
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/callbacks.rb:512:in `invoke_before'
|
|
18
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/callbacks.rb:115:in `block in run_callbacks'
|
|
19
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/bundler/gems/vanity-ce67b2c66864/lib/vanity/frameworks/rails.rb:141:in `vanity_context_filter'
|
|
20
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
|
|
21
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actiontext-6.1.4.4/lib/action_text/rendering.rb:20:in `with_renderer'
|
|
22
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actiontext-6.1.4.4/lib/action_text/engine.rb:59:in `block (4 levels) in <class:Engine>'
|
|
23
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/callbacks.rb:126:in `instance_exec'
|
|
24
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
|
|
25
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/react-rails-2.6.1/lib/react/rails/controller_lifecycle.rb:31:in `use_react_component_helper'
|
|
26
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
|
|
27
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/callbacks.rb:137:in `run_callbacks'
|
|
28
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.4.4/lib/abstract_controller/callbacks.rb:41:in `process_action'
|
|
29
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.4.4/lib/action_controller/metal/rescue.rb:22:in `process_action'
|
|
30
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.4.4/lib/action_controller/metal/instrumentation.rb:34:in `block in process_action'
|
|
31
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/notifications.rb:203:in `block in instrument'
|
|
32
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
|
|
33
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4.4/lib/active_support/notifications.rb:203:in `instrument'
|
|
34
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.4.4/lib/action_controller/metal/instrumentation.rb:33:in `process_action'
|
|
35
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.4.4/lib/action_controller/metal/params_wrapper.rb:249:in `process_action'
|
|
36
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/searchkick-4.5.2/lib/searchkick/logging.rb:212:in `process_action'
|
|
37
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.4/lib/active_record/railties/controller_runtime.rb:27:in `process_action'
|
|
38
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.4.4/lib/abstract_controller/base.rb:165:in `process'
|
|
39
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionview-6.1.4.4/lib/action_view/rendering.rb:39:in `process'
|
|
40
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.4.4/lib/action_controller/metal.rb:190:in `dispatch'
|
|
41
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.4.4/lib/action_controller/test_case.rb:580:in `process_controller_response'
|
|
42
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.4.4/lib/action_controller/test_case.rb:499:in `process'
|
|
43
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.4.4/lib/action_controller/test_case.rb:398:in `get'
|
|
44
|
+
/home/circleci/project/spec/controllers/api/funfun_controller_spec.rb:77:in `block (5 levels) in <top (required)>'
|
|
45
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:262:in `instance_exec'
|
|
46
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:262:in `block in run'
|
|
47
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:508:in `block in with_around_and_singleton_context_hooks'
|
|
48
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:465:in `block in with_around_example_hooks'
|
|
49
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:486:in `block in run'
|
|
50
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:626:in `block in run_around_example_hooks_for'
|
|
51
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:350:in `call'
|
|
52
|
+
/home/circleci/project/spec/controllers/api/funfun_controller_spec.rb:6:in `block (3 levels) in <top (required)>'
|
|
53
|
+
/home/circleci/project/vendor/gems/funny_gem/lib/funny_gem/locale.rb:272:in `around'
|
|
54
|
+
/home/circleci/project/spec/controllers/api/funfun_controller_spec.rb:5:in `block (2 levels) in <top (required)>'
|
|
55
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
|
|
56
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
|
|
57
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:390:in `execute_with'
|
|
58
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
|
|
59
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:350:in `call'
|
|
60
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-rails-4.0.2/lib/rspec/rails/example/controller_example_group.rb:191:in `block (2 levels) in <module:ControllerExampleGroup>'
|
|
61
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
|
|
62
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
|
|
63
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:390:in `execute_with'
|
|
64
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
|
|
65
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:350:in `call'
|
|
66
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-rails-4.0.2/lib/rspec/rails/adapters.rb:75:in `block (2 levels) in <module:MinitestLifecycleAdapter>'
|
|
67
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
|
|
68
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
|
|
69
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:390:in `execute_with'
|
|
70
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
|
|
71
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:350:in `call'
|
|
72
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/webmock-3.14.0/lib/webmock/rspec.rb:37:in `block (2 levels) in <top (required)>'
|
|
73
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
|
|
74
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:455:in `instance_exec'
|
|
75
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:390:in `execute_with'
|
|
76
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:628:in `block (2 levels) in run_around_example_hooks_for'
|
|
77
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:350:in `call'
|
|
78
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:629:in `run_around_example_hooks_for'
|
|
79
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/hooks.rb:486:in `run'
|
|
80
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:465:in `with_around_example_hooks'
|
|
81
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:508:in `with_around_and_singleton_context_hooks'
|
|
82
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example.rb:259:in `run'
|
|
83
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:644:in `block in run_examples'
|
|
84
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:640:in `map'
|
|
85
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:640:in `run_examples'
|
|
86
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:606:in `run'
|
|
87
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `block in run'
|
|
88
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `map'
|
|
89
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `run'
|
|
90
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `block in run'
|
|
91
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `map'
|
|
92
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `run'
|
|
93
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `block in run'
|
|
94
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `map'
|
|
95
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/example_group.rb:607:in `run'
|
|
96
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:121:in `block (3 levels) in run_specs'
|
|
97
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:121:in `map'
|
|
98
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:121:in `block (2 levels) in run_specs'
|
|
99
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/configuration.rb:2067:in `with_suite_hooks'
|
|
100
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:116:in `block in run_specs'
|
|
101
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/reporter.rb:74:in `report'
|
|
102
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:115:in `run_specs'
|
|
103
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:89:in `run'
|
|
104
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:71:in `run'
|
|
105
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:45:in `invoke'
|
|
106
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/gems/rspec-core-3.10.1/exe/rspec:4:in `<top (required)>'
|
|
107
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/bin/rspec:25:in `load'
|
|
108
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/bin/rspec:25:in `<top (required)>'
|
|
109
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/cli/exec.rb:58:in `load'
|
|
110
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/cli/exec.rb:58:in `kernel_load'
|
|
111
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/cli/exec.rb:23:in `run'
|
|
112
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/cli.rb:478:in `exec'
|
|
113
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
|
|
114
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
|
|
115
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
|
|
116
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/cli.rb:31:in `dispatch'
|
|
117
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
|
|
118
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/cli.rb:25:in `start'
|
|
119
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/exe/bundle:49:in `block in <top (required)>'
|
|
120
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/friendly_errors.rb:103:in `with_friendly_errors'
|
|
121
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/exe/bundle:37:in `<top (required)>'
|
|
122
|
+
/home/circleci/.rubygems/bin/bundle:25:in `load'
|
|
123
|
+
/home/circleci/.rubygems/bin/bundle:25:in `<main>'
|
|
124
|
+
EOS
|
|
125
|
+
|
|
126
|
+
@expected_bt = <<~EOS.chomp.split("\n")
|
|
127
|
+
/home/circleci/project/app/controllers/application_controller.rb:174:in `block (2 levels) in block_fun'
|
|
128
|
+
actionpack (6.1.4.4) lib/action_controller/metal/mime_responds.rb:214:in `respond_to'
|
|
129
|
+
/home/circleci/project/app/controllers/application_controller.rb:170:in `block_fun'
|
|
130
|
+
activesupport (6.1.4.4) lib/active_support/callbacks.rb:427:in `block in make_lambda'
|
|
131
|
+
activesupport (6.1.4.4) lib/active_support/callbacks.rb:198:in `block (2 levels) in halting'
|
|
132
|
+
actionpack (6.1.4.4) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in <module:Callbacks>'
|
|
133
|
+
activesupport (6.1.4.4) lib/active_support/callbacks.rb:199:in `block in halting'
|
|
134
|
+
activesupport (6.1.4.4) lib/active_support/callbacks.rb:512:in `block in invoke_before'
|
|
135
|
+
activesupport (6.1.4.4) lib/active_support/callbacks.rb:512:in `each'
|
|
136
|
+
activesupport (6.1.4.4) lib/active_support/callbacks.rb:512:in `invoke_before'
|
|
137
|
+
BacktraceCleaner.minimum_first ... and next silenced backtraces
|
|
138
|
+
/home/circleci/project/spec/controllers/api/funfun_controller_spec.rb:77:in `block (5 levels) in <top (required)>'
|
|
139
|
+
/home/circleci/project/spec/controllers/api/funfun_controller_spec.rb:6:in `block (3 levels) in <top (required)>'
|
|
140
|
+
/home/circleci/project/vendor/gems/funny_gem/lib/funny_gem/locale.rb:272:in `around'
|
|
141
|
+
/home/circleci/project/spec/controllers/api/funfun_controller_spec.rb:5:in `block (2 levels) in <top (required)>'
|
|
142
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/bin/rspec:25:in `load'
|
|
143
|
+
/home/circleci/project/vendor/bundle/ruby/2.7.0/bin/rspec:25:in `<top (required)>'
|
|
144
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/cli/exec.rb:58:in `load'
|
|
145
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/cli/exec.rb:58:in `kernel_load'
|
|
146
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/cli/exec.rb:23:in `run'
|
|
147
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/cli.rb:478:in `exec'
|
|
148
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
|
|
149
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
|
|
150
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
|
|
151
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/cli.rb:31:in `dispatch'
|
|
152
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
|
|
153
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/cli.rb:25:in `start'
|
|
154
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/exe/bundle:49:in `block in <top (required)>'
|
|
155
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/lib/bundler/friendly_errors.rb:103:in `with_friendly_errors'
|
|
156
|
+
/home/circleci/.rubygems/gems/bundler-2.2.30/exe/bundle:37:in `<top (required)>'
|
|
157
|
+
/home/circleci/.rubygems/bin/bundle:25:in `load'
|
|
158
|
+
/home/circleci/.rubygems/bin/bundle:25:in `<main>'
|
|
159
|
+
EOS
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def test_backtrace
|
|
163
|
+
Gem.stub :path, ['/home/circleci/project/vendor/bundle/ruby/2.7.0'] do
|
|
164
|
+
Gem.stub :default_path, [] do
|
|
165
|
+
cleaner = ActiveSupport::BacktraceCleaner.new
|
|
166
|
+
bt = cleaner.clean(@backtrace)
|
|
167
|
+
assert_equal bt, @expected_bt
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def test_backtrace_with_enumerator
|
|
173
|
+
Gem.stub :path, ['/home/circleci/project/vendor/bundle/ruby/2.7.0'] do
|
|
174
|
+
Gem.stub :default_path, [] do
|
|
175
|
+
cleaner = ActiveSupport::BacktraceCleaner.new
|
|
176
|
+
bt = cleaner.clean(@backtrace.lazy)
|
|
177
|
+
assert_equal bt, @expected_bt
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
data/test/test_month.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'minitest/autorun'
|
|
3
|
+
|
|
4
|
+
module Coaster
|
|
5
|
+
class TestMonth < Minitest::Test
|
|
6
|
+
def test_month
|
|
7
|
+
m = Month.parse('202001')
|
|
8
|
+
assert_equal m.year, 2020
|
|
9
|
+
assert_equal m.last_date, Date.parse('20200131')
|
|
10
|
+
assert_equal m.end_of_month, Date.parse('20200131').end_of_day
|
|
11
|
+
assert_equal m.to_time_range, Date.parse('20200101').beginning_of_day...Date.parse('20200201').beginning_of_day
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/test/test_standard_error.rb
CHANGED
|
@@ -2,10 +2,13 @@ require 'test_helper'
|
|
|
2
2
|
require 'minitest/autorun'
|
|
3
3
|
require 'coaster/core_ext/standard_error/raven'
|
|
4
4
|
|
|
5
|
-
StandardError.
|
|
5
|
+
StandardError.inspection_value_proc = Proc.new do |val|
|
|
6
6
|
PP.pp(val, ''.dup, 79)[0...-1]
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
+
StandardError.cleaner = ActiveSupport::BacktraceCleaner.new
|
|
10
|
+
StandardError.cause_cleaner = StandardError.cleaner
|
|
11
|
+
|
|
9
12
|
module Coaster
|
|
10
13
|
class TestStandardError < Minitest::Test
|
|
11
14
|
class SampleError < StandardError
|
|
@@ -31,7 +34,7 @@ module Coaster
|
|
|
31
34
|
assert_nil e.description
|
|
32
35
|
assert_nil e.desc
|
|
33
36
|
assert_equal 'standard error translation', e._translate
|
|
34
|
-
assert_equal 'standard error translation (
|
|
37
|
+
assert_equal 'standard error translation (363fdc)', e.user_message
|
|
35
38
|
assert_equal 'standard error title', e.title
|
|
36
39
|
e = StandardError.new(m: 'developer message', desc: 'user message')
|
|
37
40
|
assert_equal "user message (developer message)", e.to_s
|
|
@@ -50,7 +53,7 @@ module Coaster
|
|
|
50
53
|
assert_nil e.description
|
|
51
54
|
assert_nil e.desc
|
|
52
55
|
assert_equal 'standard error translation', e._translate
|
|
53
|
-
assert_equal 'standard error translation (
|
|
56
|
+
assert_equal 'standard error translation (e39e84)', e.user_message
|
|
54
57
|
assert_equal 'standard error title', e.title
|
|
55
58
|
e = UntitledError.new(m: 'developer message', desc: 'user message')
|
|
56
59
|
assert_equal "user message (developer message)", e.to_s
|
|
@@ -77,7 +80,7 @@ module Coaster
|
|
|
77
80
|
assert_nil e.description
|
|
78
81
|
assert_nil e.desc
|
|
79
82
|
assert_equal 'Test sample error', e._translate
|
|
80
|
-
assert_equal 'Test sample error (
|
|
83
|
+
assert_equal 'Test sample error (e28ede)', e.user_message
|
|
81
84
|
assert_equal 'Test this title', e.title
|
|
82
85
|
e = SampleError.new(beet: 'apple')
|
|
83
86
|
assert_equal "Test sample error (Coaster::TestStandardError::SampleError)", e.to_s
|
|
@@ -85,7 +88,7 @@ module Coaster
|
|
|
85
88
|
assert_nil e.description
|
|
86
89
|
assert_nil e.desc
|
|
87
90
|
assert_equal 'Test sample error', e._translate
|
|
88
|
-
assert_equal 'Test sample error (
|
|
91
|
+
assert_equal 'Test sample error (cbe233)', e.user_message
|
|
89
92
|
assert_equal 'Test this title', e.title
|
|
90
93
|
e = SampleError.new('developer message')
|
|
91
94
|
assert_equal "developer message", e.to_s
|
|
@@ -93,7 +96,7 @@ module Coaster
|
|
|
93
96
|
assert_nil e.description
|
|
94
97
|
assert_nil e.desc
|
|
95
98
|
assert_equal 'Test sample error', e._translate
|
|
96
|
-
assert_equal 'Test sample error (
|
|
99
|
+
assert_equal 'Test sample error (43161e)', e.user_message
|
|
97
100
|
assert_equal 'Test this title', e.title
|
|
98
101
|
e = SampleError.new(desc: 'user message')
|
|
99
102
|
assert_equal "user message (Coaster::TestStandardError::SampleError)", e.to_s
|
|
@@ -159,7 +162,7 @@ module Coaster
|
|
|
159
162
|
assert_equal 'Coaster::TestStandardError::ExampleError', e.to_hash['type']
|
|
160
163
|
assert_equal 20, e.to_hash['status']
|
|
161
164
|
assert_equal 500, e.to_hash['http_status']
|
|
162
|
-
assert_equal "Test example error (Coaster::TestStandardError::ExampleError) {Test sample error (Coaster::TestStandardError::SampleError)}", e.to_hash['message']
|
|
165
|
+
assert_equal "Test example error (Coaster::TestStandardError::ExampleError) cause{Test sample error (Coaster::TestStandardError::SampleError)}", e.to_hash['message']
|
|
163
166
|
assert_equal 'rams', e.to_hash['cause']['frog']
|
|
164
167
|
assert_equal 'Coaster::TestStandardError::SampleError', e.to_hash['cause']['type']
|
|
165
168
|
assert_equal 10, e.to_hash['cause']['status']
|
|
@@ -174,7 +177,7 @@ module Coaster
|
|
|
174
177
|
raise ExampleError, {m: 'abc', wat: 'cha'}
|
|
175
178
|
end
|
|
176
179
|
rescue => e
|
|
177
|
-
assert_equal 'Test example error (abc) {Test sample error (Coaster::TestStandardError::SampleError)}', e.message
|
|
180
|
+
assert_equal 'Test example error (abc) cause{Test sample error (Coaster::TestStandardError::SampleError)}', e.message
|
|
178
181
|
assert_equal 'rams', e.cause.attr['frog']
|
|
179
182
|
assert_equal 'rams', e.attr['frog']
|
|
180
183
|
assert_equal 'cha', e.attr['wat']
|
|
@@ -184,28 +187,73 @@ module Coaster
|
|
|
184
187
|
begin
|
|
185
188
|
raise SampleError, {frog: 'rams'}
|
|
186
189
|
rescue => e
|
|
187
|
-
|
|
190
|
+
err = ExampleError.new(wat: 'cha')
|
|
191
|
+
err.instance_variable_set(:@ins_var, [SampleError.new, {h: 1}])
|
|
192
|
+
err.instance_variable_set(:@ins_varr, {dd: true})
|
|
193
|
+
raise err
|
|
188
194
|
end
|
|
189
195
|
rescue => e
|
|
190
|
-
detail =
|
|
196
|
+
detail = e.to_inspection_s
|
|
197
|
+
detail_front = <<-LOG
|
|
191
198
|
[Coaster::TestStandardError::ExampleError] status:20
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
199
|
+
MESSAGE: Test example error (Coaster::TestStandardError::ExampleError) cause{Test sample error (Coaster::TestStandardError::SampleError)}
|
|
200
|
+
@attributes: {\"frog\"=>\"rams\", \"wat\"=>\"cha\"}
|
|
201
|
+
@coaster: true
|
|
202
|
+
@fingerprint: []
|
|
203
|
+
@ins_var: [\"Coaster::TestStandardError::SampleError\", {\"h\"=>1}]
|
|
204
|
+
@ins_varr: {\"dd\"=>true}
|
|
205
|
+
@level: \"error\"
|
|
206
|
+
@raven: {}
|
|
207
|
+
@tags: {}
|
|
208
|
+
@tkey: nil
|
|
209
|
+
BACKTRACE:
|
|
210
|
+
#{__FILE__}:193:in `rescue in test_to_detail'
|
|
211
|
+
#{__FILE__}:187:in `test_to_detail'
|
|
212
|
+
LOG
|
|
213
|
+
detail_cause_front = <<-LOG
|
|
214
|
+
CAUSE: [Coaster::TestStandardError::SampleError] status:10
|
|
215
|
+
MESSAGE: Test sample error (Coaster::TestStandardError::SampleError)
|
|
216
|
+
@attributes: {"frog"=>"rams"}
|
|
217
|
+
@coaster: true
|
|
218
|
+
@fingerprint: []
|
|
219
|
+
@level: "error"
|
|
220
|
+
@raven: {}
|
|
221
|
+
@tags: {}
|
|
222
|
+
@tkey: nil
|
|
223
|
+
BACKTRACE:
|
|
224
|
+
#{__FILE__}:188:in `test_to_detail'
|
|
207
225
|
LOG
|
|
208
|
-
|
|
226
|
+
assert detail.start_with?(detail_front)
|
|
227
|
+
cause_ix = (detail =~ /CAUSE/)
|
|
228
|
+
cause = detail[cause_ix..-1]
|
|
229
|
+
assert cause.start_with?(detail_cause_front)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def test_to_detail_with_depth
|
|
233
|
+
begin
|
|
234
|
+
begin
|
|
235
|
+
begin
|
|
236
|
+
begin
|
|
237
|
+
begin
|
|
238
|
+
raise SampleError
|
|
239
|
+
rescue => e
|
|
240
|
+
raise SampleError
|
|
241
|
+
end
|
|
242
|
+
rescue => e
|
|
243
|
+
raise SampleError
|
|
244
|
+
end
|
|
245
|
+
rescue => e
|
|
246
|
+
raise SampleError
|
|
247
|
+
end
|
|
248
|
+
rescue => e
|
|
249
|
+
raise SampleError
|
|
250
|
+
end
|
|
251
|
+
rescue => e
|
|
252
|
+
raise SampleError
|
|
253
|
+
end
|
|
254
|
+
rescue => e
|
|
255
|
+
detail = e.to_inspection_s
|
|
256
|
+
assert detail =~ /and more causes/
|
|
209
257
|
end
|
|
210
258
|
|
|
211
259
|
def test_translation
|
|
@@ -263,7 +311,8 @@ LOG
|
|
|
263
311
|
assert_equal 'NameError', e.to_hash['type']
|
|
264
312
|
assert_equal 999999, e.to_hash['status']
|
|
265
313
|
assert_equal 500, e.to_hash['http_status']
|
|
266
|
-
|
|
314
|
+
assert_equal 'standard error translation (a962bd 80dfafa3)', e.user_message
|
|
315
|
+
assert_match(/undefined local variable or method `aa'/, e.to_hash['message'])
|
|
267
316
|
end
|
|
268
317
|
|
|
269
318
|
def test_descriptions
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: coaster
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.3.
|
|
4
|
+
version: 1.3.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- buzz jung
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-
|
|
11
|
+
date: 2022-06-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: i18n
|
|
@@ -146,7 +146,6 @@ files:
|
|
|
146
146
|
- README.md
|
|
147
147
|
- Rakefile
|
|
148
148
|
- lib/coaster.rb
|
|
149
|
-
- lib/coaster/backtrace_cleaner.rb
|
|
150
149
|
- lib/coaster/core_ext.rb
|
|
151
150
|
- lib/coaster/core_ext/array.rb
|
|
152
151
|
- lib/coaster/core_ext/date.rb
|
|
@@ -156,10 +155,14 @@ files:
|
|
|
156
155
|
- lib/coaster/core_ext/standard_error.rb
|
|
157
156
|
- lib/coaster/core_ext/standard_error/raven.rb
|
|
158
157
|
- lib/coaster/core_ext/standard_error/sentry.rb
|
|
158
|
+
- lib/coaster/rails_ext.rb
|
|
159
|
+
- lib/coaster/rails_ext/backtrace_cleaner.rb
|
|
159
160
|
- lib/coaster/serialized_properties.rb
|
|
160
161
|
- lib/coaster/version.rb
|
|
161
162
|
- test/locales/en.yml
|
|
163
|
+
- test/test_backtrace.rb
|
|
162
164
|
- test/test_helper.rb
|
|
165
|
+
- test/test_month.rb
|
|
163
166
|
- test/test_object_translation.rb
|
|
164
167
|
- test/test_standard_error.rb
|
|
165
168
|
homepage: http://github.com/frograms/coaster
|
|
@@ -181,12 +184,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
181
184
|
- !ruby/object:Gem::Version
|
|
182
185
|
version: '0'
|
|
183
186
|
requirements: []
|
|
184
|
-
rubygems_version: 3.
|
|
187
|
+
rubygems_version: 3.3.7
|
|
185
188
|
signing_key:
|
|
186
189
|
specification_version: 4
|
|
187
190
|
summary: A little convenient feature for standard library
|
|
188
191
|
test_files:
|
|
189
192
|
- test/locales/en.yml
|
|
193
|
+
- test/test_backtrace.rb
|
|
190
194
|
- test/test_helper.rb
|
|
195
|
+
- test/test_month.rb
|
|
191
196
|
- test/test_object_translation.rb
|
|
192
197
|
- test/test_standard_error.rb
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
class Coaster::BacktraceCleaner
|
|
2
|
-
attr_accessor :least
|
|
3
|
-
|
|
4
|
-
def initialize
|
|
5
|
-
@filters, @silencers = [], []
|
|
6
|
-
@least = 10
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
# Returns the backtrace after all filters and silencers have been run
|
|
10
|
-
# against it. Filters run first, then silencers.
|
|
11
|
-
def clean(backtrace, kind = :silent)
|
|
12
|
-
filtered = filter_backtrace(backtrace)
|
|
13
|
-
|
|
14
|
-
case kind
|
|
15
|
-
when :silent
|
|
16
|
-
silence(filtered)
|
|
17
|
-
when :noise
|
|
18
|
-
noise(filtered)
|
|
19
|
-
else
|
|
20
|
-
filtered
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
alias :filter :clean
|
|
24
|
-
|
|
25
|
-
# Adds a filter from the block provided. Each line in the backtrace will be
|
|
26
|
-
# mapped against this filter.
|
|
27
|
-
#
|
|
28
|
-
# # Will turn "/my/rails/root/app/models/person.rb" into "/app/models/person.rb"
|
|
29
|
-
# backtrace_cleaner.add_filter { |line| line.gsub(Rails.root, '') }
|
|
30
|
-
def add_filter(&block)
|
|
31
|
-
@filters << block
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# Adds a silencer from the block provided. If the silencer returns +true+
|
|
35
|
-
# for a given line, it will be excluded from the clean backtrace.
|
|
36
|
-
#
|
|
37
|
-
# # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb"
|
|
38
|
-
# backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ }
|
|
39
|
-
def add_silencer(&block)
|
|
40
|
-
@silencers << block
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Removes all silencers, but leaves in the filters. Useful if your
|
|
44
|
-
# context of debugging suddenly expands as you suspect a bug in one of
|
|
45
|
-
# the libraries you use.
|
|
46
|
-
def remove_silencers!
|
|
47
|
-
@silencers = []
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Removes all filters, but leaves in the silencers. Useful if you suddenly
|
|
51
|
-
# need to see entire filepaths in the backtrace that you had already
|
|
52
|
-
# filtered out.
|
|
53
|
-
def remove_filters!
|
|
54
|
-
@filters = []
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
private
|
|
58
|
-
def filter_backtrace(backtrace)
|
|
59
|
-
@filters.each do |f|
|
|
60
|
-
backtrace = backtrace.map { |line| f.call(line) }
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
backtrace
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def silence(backtrace)
|
|
67
|
-
least_bt = backtrace.shift(least)
|
|
68
|
-
@silencers.each do |s|
|
|
69
|
-
backtrace = backtrace.reject { |line| s.call(line) }
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
least_bt + backtrace
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def noise(backtrace)
|
|
76
|
-
backtrace - silence(backtrace)
|
|
77
|
-
end
|
|
78
|
-
end
|