deprecation_collector 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +9 -3
- data/README.md +6 -0
- data/deprecation_collector.gemspec +1 -1
- data/lib/deprecation_collector/deprecation.rb +4 -2
- data/lib/deprecation_collector/version.rb +1 -1
- data/lib/deprecation_collector.rb +36 -18
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: edc00d8d4dd22e076dd0c331bd65ee2a6caad48e28ee0f2a79253f94d6d5a1b3
|
4
|
+
data.tar.gz: a8d0a71ada4d0eae355f853f685ea4548124e5090bcac361bb4363ef69b8faaa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7f467b251d4e04f9d23f5524f1c0e36d6ab363090664178ef82d78d261e118d7f30511f6711ebde8205cde3fe46e871f870752c8be867f4f0bd743344589e5b
|
7
|
+
data.tar.gz: 2c3b8f59fc2adb43a04a39f3fb39f02bcd752ebbc9d7a1974a77a8441dfeb1daaf65ec87704d7159a1b31a443c20df5a202ff1872e08a28e709baccd84657998
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 0.0.6
|
2
|
+
- added custom context saving ability
|
3
|
+
|
4
|
+
== 0.0.5
|
5
|
+
- options `print_to_stderr`, `print_recurring`
|
6
|
+
- fix redis deprecated `pipelined` block arity (support for redis 5)
|
7
|
+
|
1
8
|
== 0.0.4
|
2
9
|
- added first_timestamp to deprecations (unix timestamp of first occurrence, not accurate because a worker with later timestamp may dump its deprecations earlier)
|
3
10
|
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
deprecation_collector (0.0.
|
5
|
-
redis (>=
|
4
|
+
deprecation_collector (0.0.6)
|
5
|
+
redis (>= 3.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
@@ -84,8 +84,12 @@ GEM
|
|
84
84
|
nokogiri (~> 1)
|
85
85
|
rake
|
86
86
|
mini_mime (1.1.2)
|
87
|
+
mini_portile2 (2.8.0)
|
87
88
|
minitest (5.15.0)
|
88
89
|
nio4r (2.5.8)
|
90
|
+
nokogiri (1.13.6)
|
91
|
+
mini_portile2 (~> 2.8.0)
|
92
|
+
racc (~> 1.4)
|
89
93
|
nokogiri (1.13.6-x86_64-darwin)
|
90
94
|
racc (~> 1.4)
|
91
95
|
parallel (1.22.1)
|
@@ -123,7 +127,7 @@ GEM
|
|
123
127
|
thor (>= 0.20.3, < 2.0)
|
124
128
|
rainbow (3.1.1)
|
125
129
|
rake (13.0.6)
|
126
|
-
redis (4.
|
130
|
+
redis (4.8.0)
|
127
131
|
regexp_parser (2.5.0)
|
128
132
|
rexml (3.2.5)
|
129
133
|
rspec (3.11.0)
|
@@ -181,12 +185,14 @@ GEM
|
|
181
185
|
zeitwerk (2.5.4)
|
182
186
|
|
183
187
|
PLATFORMS
|
188
|
+
ruby
|
184
189
|
x86_64-darwin-21
|
185
190
|
|
186
191
|
DEPENDENCIES
|
187
192
|
deprecation_collector!
|
188
193
|
rails (= 6.0)
|
189
194
|
rake (~> 13.0)
|
195
|
+
redis (~> 4.8)
|
190
196
|
rspec (~> 3.0)
|
191
197
|
rubocop (~> 1.21)
|
192
198
|
rubocop-performance
|
data/README.md
CHANGED
@@ -28,9 +28,15 @@ Add an initializer with configuration, like
|
|
28
28
|
instance.raise_on_deprecation = false
|
29
29
|
instance.write_interval = (::Rails.env.production? && 15.minutes) || 1.minute
|
30
30
|
instance.exclude_realms = %i[kernel] if Rails.env.production?
|
31
|
+
instance.print_to_stderr = true if Rails.env.development?
|
32
|
+
instance.print_recurring = false
|
31
33
|
instance.ignored_messages = [
|
32
34
|
"Ignoring db/schema_cache.yml because it has expired"
|
33
35
|
]
|
36
|
+
instance.context_saver do
|
37
|
+
# this will only be called for new deprecations, return value must be json-compatible
|
38
|
+
{ some: "custom", context: "for example request.id" }
|
39
|
+
end
|
34
40
|
end
|
35
41
|
end
|
36
42
|
```
|
@@ -4,6 +4,7 @@ class DeprecationCollector
|
|
4
4
|
# :nodoc:
|
5
5
|
class Deprecation
|
6
6
|
attr_reader :message, :realm, :gem_traceline, :app_traceline, :occurences, :first_timestamp, :full_backtrace
|
7
|
+
attr_accessor :context
|
7
8
|
|
8
9
|
CLEANUP_REGEXES = {
|
9
10
|
# rails views generated methods names are unique per-worker
|
@@ -54,7 +55,7 @@ class DeprecationCollector
|
|
54
55
|
end
|
55
56
|
|
56
57
|
def digest_base
|
57
|
-
"1:#{RUBY_VERSION}:#{Rails.version}:#{message_for_digest}:#{gem_traceline}:#{app_traceline}"
|
58
|
+
"1:#{RUBY_VERSION}:#{defined?(Rails) && Rails.version}:#{message_for_digest}:#{gem_traceline}:#{app_traceline}"
|
58
59
|
end
|
59
60
|
|
60
61
|
def as_json(_options = {})
|
@@ -70,7 +71,8 @@ class DeprecationCollector
|
|
70
71
|
revision: DeprecationCollector.instance.app_revision,
|
71
72
|
count: @occurences, # output anyway for frequency estimation (during write_interval inside single process)
|
72
73
|
first_timestamp: first_timestamp, # this may not be accurate, a worker with later timestamp may dump earlier
|
73
|
-
digest_base: digest_base # for debug purposes
|
74
|
+
digest_base: digest_base, # for debug purposes
|
75
|
+
context: context
|
74
76
|
}.compact
|
75
77
|
end
|
76
78
|
|
@@ -54,8 +54,9 @@ class DeprecationCollector
|
|
54
54
|
attr_accessor :count, :raise_on_deprecation, :save_full_backtrace,
|
55
55
|
:exclude_realms,
|
56
56
|
:write_interval, :write_interval_jitter,
|
57
|
-
:app_revision, :app_root
|
58
|
-
|
57
|
+
:app_revision, :app_root,
|
58
|
+
:print_to_stderr, :print_recurring
|
59
|
+
attr_writer :redis, :context_saver
|
59
60
|
|
60
61
|
def initialize(mutex: nil)
|
61
62
|
# on cruby hash itself is threadsafe, but we need to prevent races
|
@@ -78,12 +79,19 @@ class DeprecationCollector
|
|
78
79
|
# NB: in production with hugreds of workers may easily overload redis with writes, so more delay needed:
|
79
80
|
@write_interval = 900 # 15.minutes
|
80
81
|
@write_interval_jitter = 60
|
82
|
+
@context_saver = nil
|
81
83
|
end
|
82
84
|
|
83
85
|
def ignored_messages=(val)
|
84
86
|
@ignore_message_regexp = (val && Regexp.union(val)) || nil
|
85
87
|
end
|
86
88
|
|
89
|
+
def context_saver(&block)
|
90
|
+
return @context_saver unless block_given?
|
91
|
+
|
92
|
+
@context_saver = block
|
93
|
+
end
|
94
|
+
|
87
95
|
def app_root_prefix
|
88
96
|
"#{app_root}/"
|
89
97
|
end
|
@@ -97,8 +105,8 @@ class DeprecationCollector
|
|
97
105
|
raise "Deprecation: #{message}" if @raise_on_deprecation
|
98
106
|
|
99
107
|
deprecation = Deprecation.new(message, realm, backtrace, cleanup_prefixes)
|
100
|
-
store_deprecation(deprecation)
|
101
|
-
log_deprecation_if_needed(deprecation)
|
108
|
+
fresh = store_deprecation(deprecation)
|
109
|
+
log_deprecation_if_needed(deprecation, fresh)
|
102
110
|
end
|
103
111
|
|
104
112
|
def unsent_data?
|
@@ -190,10 +198,10 @@ class DeprecationCollector
|
|
190
198
|
def read_one(digest)
|
191
199
|
decode_deprecation(
|
192
200
|
digest,
|
193
|
-
*@redis.pipelined do
|
194
|
-
|
195
|
-
|
196
|
-
|
201
|
+
*@redis.pipelined do |pipe|
|
202
|
+
pipe.hget("deprecations:data", digest)
|
203
|
+
pipe.hget("deprecations:counter", digest)
|
204
|
+
pipe.hget("deprecations:notes", digest)
|
197
205
|
end
|
198
206
|
)
|
199
207
|
end
|
@@ -201,10 +209,10 @@ class DeprecationCollector
|
|
201
209
|
def delete_deprecations(remove_digests)
|
202
210
|
return 0 unless remove_digests.any?
|
203
211
|
|
204
|
-
@redis.pipelined do
|
205
|
-
|
206
|
-
|
207
|
-
|
212
|
+
@redis.pipelined do |pipe|
|
213
|
+
pipe.hdel("deprecations:data", *remove_digests)
|
214
|
+
pipe.hdel("deprecations:notes", *remove_digests)
|
215
|
+
pipe.hdel("deprecations:counter", *remove_digests) if @count
|
208
216
|
end.first
|
209
217
|
end
|
210
218
|
|
@@ -226,18 +234,23 @@ class DeprecationCollector
|
|
226
234
|
|
227
235
|
def store_deprecation(deprecation)
|
228
236
|
return if deprecation.ignored?
|
237
|
+
fresh = !@deprecations.key?(deprecation.digest)
|
238
|
+
deprecation.context = context_saver.call if context_saver
|
229
239
|
|
230
240
|
@deprecations_mutex.synchronize do
|
231
241
|
(@deprecations[deprecation.digest] ||= deprecation).touch
|
232
242
|
end
|
233
243
|
|
234
244
|
write_to_redis if current_time - @last_write_time > (@write_interval + rand(@write_interval_jitter))
|
245
|
+
fresh
|
235
246
|
end
|
236
247
|
|
237
|
-
def log_deprecation_if_needed(deprecation)
|
238
|
-
return unless
|
239
|
-
|
240
|
-
|
248
|
+
def log_deprecation_if_needed(deprecation, fresh)
|
249
|
+
return unless print_to_stderr && !deprecation.ignored?
|
250
|
+
return unless fresh || print_recurring
|
251
|
+
msg = deprecation.message
|
252
|
+
msg = "DEPRECATION: #{msg}" unless msg.start_with?('DEPRECAT')
|
253
|
+
$stderr.puts(msg) # rubocop:disable Style/StderrPuts
|
241
254
|
end
|
242
255
|
|
243
256
|
def current_time
|
@@ -247,7 +260,12 @@ class DeprecationCollector
|
|
247
260
|
end
|
248
261
|
|
249
262
|
def decode_deprecation(digest, data, count, notes)
|
263
|
+
return nil unless data
|
250
264
|
data = JSON.parse(data, symbolize_names: true)
|
265
|
+
unless data.is_a?(Hash)
|
266
|
+
binding.irb
|
267
|
+
return nil
|
268
|
+
end
|
251
269
|
data[:digest] = digest
|
252
270
|
data[:notes] = JSON.parse(notes, symbolize_names: true) if notes
|
253
271
|
data[:count] = count.to_i if count
|
@@ -255,9 +273,9 @@ class DeprecationCollector
|
|
255
273
|
end
|
256
274
|
|
257
275
|
def write_count_to_redis(deprecations_to_flush)
|
258
|
-
@redis.pipelined do
|
276
|
+
@redis.pipelined do |pipe|
|
259
277
|
deprecations_to_flush.each_pair do |digest, deprecation|
|
260
|
-
|
278
|
+
pipe.hincrby("deprecations:counter", digest, deprecation.occurences)
|
261
279
|
end
|
262
280
|
end
|
263
281
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deprecation_collector
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vasily Fedoseyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '3.0'
|
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: '
|
26
|
+
version: '3.0'
|
27
27
|
description: Collects and aggregates warnings and deprecations. Optimized for production
|
28
28
|
environment.
|
29
29
|
email:
|
@@ -69,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
69
69
|
- !ruby/object:Gem::Version
|
70
70
|
version: '0'
|
71
71
|
requirements: []
|
72
|
-
rubygems_version: 3.
|
72
|
+
rubygems_version: 3.3.7
|
73
73
|
signing_key:
|
74
74
|
specification_version: 4
|
75
75
|
summary: Collector for ruby/rails deprecations and warnings, suitable for production
|