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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2342f445e6c89ba4ea74094dd39894d99ad6e546781405fe43a6ecba71396264
4
- data.tar.gz: d5d6edaa942f57a726f9336a06541dabc3eadae2731d01953443a88d84fc7c2e
3
+ metadata.gz: edc00d8d4dd22e076dd0c331bd65ee2a6caad48e28ee0f2a79253f94d6d5a1b3
4
+ data.tar.gz: a8d0a71ada4d0eae355f853f685ea4548124e5090bcac361bb4363ef69b8faaa
5
5
  SHA512:
6
- metadata.gz: 9ac2e881d1687dc3756904840f21f98cc62dc497cac31804fcfeac8e4e01c780b5370497ed52da2d1ec22ca14a68ee3be4dc163c5d48cd47c38b775ef0df7b1c
7
- data.tar.gz: 5725ea9137d79a83ea8d1df1ae9b458fe0f94479d5e7c9643ac15368ef853f75fac38cce3b7e8543fd4d03df884fa3999019d08902ba437a196f6b5b3c78dd06
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
@@ -18,3 +18,5 @@ gem "rubocop-rspec"
18
18
 
19
19
  # TODO: appraisals
20
20
  gem "rails", "6.0"
21
+
22
+ gem 'redis', '~>4.8'
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- deprecation_collector (0.0.4)
5
- redis (>= 2.0)
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.7.1)
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
  ```
@@ -27,5 +27,5 @@ Gem::Specification.new do |spec|
27
27
  end
28
28
  spec.require_paths = ["lib"]
29
29
 
30
- spec.add_dependency "redis", ">= 2.0" # TODO: check exact minimum version
30
+ spec.add_dependency "redis", ">= 3.0"
31
31
  end
@@ -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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class DeprecationCollector
4
- VERSION = "0.0.4"
4
+ VERSION = "0.0.6"
5
5
  end
@@ -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
- attr_writer :redis
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
- @redis.hget("deprecations:data", digest)
195
- @redis.hget("deprecations:counter", digest)
196
- @redis.hget("deprecations:notes", digest)
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
- @redis.hdel("deprecations:data", *remove_digests)
206
- @redis.hdel("deprecations:notes", *remove_digests)
207
- @redis.hdel("deprecations:counter", *remove_digests) if @count
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 defined?(Rails) && Rails.env.development? && !deprecation.ignored?
239
-
240
- $stderr.puts(deprecation.message) # rubocop:disable Style/StderrPuts
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
- @redis.hincrby("deprecations:counter", digest, deprecation.occurences)
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
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-08-29 00:00:00.000000000 Z
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: '2.0'
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: '2.0'
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.1.6
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