deprecation_collector 0.0.2 → 0.0.5

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: 02cc02dc5d90e6b304ac5dadfc7ee09c1ac684ced0d3e0657095a47ffdc88e82
4
- data.tar.gz: ce2b0e299aed5c65f302ffb4fb72d49e7ea1f44772a5b6d61eeae1807eecb1fd
3
+ metadata.gz: 6f45c8742c0a83f697b04d7a99af54749b354c25cfcffb78f152a680f8224584
4
+ data.tar.gz: ab25a06b38f3ebfe82a48136c8a58da8d61e4db93614af0c66e283771f0b61b7
5
5
  SHA512:
6
- metadata.gz: b468f3a95e56ced60c3de42996f1d6c4d9249588dfe972c321aaf3dcf80f81cf9048dc040b14c9a604f7c01d780385de2ec4e3ea1cb5dbda47ac541bd20d1a83
7
- data.tar.gz: a245eb05033c494e514ba10e0ba63888bffb5e7fb86365a9e09cc425674be7c01df17d7c4870af60011c5a26600f07825e3a74971b5b690859762880f35b33e9
6
+ metadata.gz: d395dc4cedb786ab398911e5de19568f44317040352f1b85a6fc45a45fce465d6c82b8092c2f74e0a6b1d18e4dedfbc3284d59767dad2f3a2202143acd969b81
7
+ data.tar.gz: 0f9a6cd6f02b9b674710db839fcce21f69a2af31a41cc552ad3266b7cd1c3eaa21dac1ac7f94f0208833536e29c20d70e0261e6b087bc548597035c45bc47799
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
- == unreleased
1
+ == 0.0.5 (unreleased)
2
+ - options `print_to_stderr`, `print_recurring`
3
+ - fix redis deprecated `pipelined` block arity (support for redis 5)
2
4
 
5
+ == 0.0.4
6
+ - added first_timestamp to deprecations (unix timestamp of first occurrence, not accurate because a worker with later timestamp may dump its deprecations earlier)
7
+
8
+ == 0.0.3
9
+ - Fixed selective deprecation cleanup (`DeprecationCollector.instance.cleanup { |d| d[:message].include?('foo') }`)
3
10
 
4
11
  == 0.0.2
5
12
 
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.2)
5
- redis (>= 2.0)
4
+ deprecation_collector (0.0.5)
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.6.0)
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
@@ -2,6 +2,8 @@
2
2
  [![Gem Version](https://badge.fury.io/rb/deprecation_collector.svg)](https://badge.fury.io/rb/deprecation_collector)
3
3
 
4
4
  Collects ruby and rails deprecation warnings.
5
+ Designed to be suitable for use in production under load.
6
+
5
7
  (gem is a work-in-process, documentation will come later)
6
8
 
7
9
  ## Installation
@@ -17,15 +19,17 @@ bundle add deprecation_collector
17
19
  Add an initializer with configuration, like
18
20
 
19
21
  ```ruby
20
- DeprecationCollector.create_instance(redis: your_redis_connection)
21
22
  Rails.application.config.to_prepare do
22
23
  DeprecationCollector.install do |instance|
24
+ instance.redis = Redis.new # default is $redis
23
25
  instance.app_revision = ::GIT_REVISION
24
26
  instance.count = false
25
27
  instance.save_full_backtrace = true
26
28
  instance.raise_on_deprecation = false
27
29
  instance.write_interval = (::Rails.env.production? && 15.minutes) || 1.minute
28
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
29
33
  instance.ignored_messages = [
30
34
  "Ignoring db/schema_cache.yml because it has expired"
31
35
  ]
@@ -41,7 +45,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
41
45
 
42
46
  ## Contributing
43
47
 
44
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/deprecation_collector.
48
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Vasfed/deprecation_collector.
45
49
 
46
50
  ## License
47
51
 
@@ -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
@@ -3,7 +3,7 @@
3
3
  class DeprecationCollector
4
4
  # :nodoc:
5
5
  class Deprecation
6
- attr_reader :message, :realm, :gem_traceline, :app_traceline, :occurences, :full_backtrace
6
+ attr_reader :message, :realm, :gem_traceline, :app_traceline, :occurences, :first_timestamp, :full_backtrace
7
7
 
8
8
  CLEANUP_REGEXES = {
9
9
  # rails views generated methods names are unique per-worker
@@ -20,6 +20,7 @@ class DeprecationCollector
20
20
  @occurences = 0
21
21
  @gem_traceline = find_gem_traceline(backtrace)
22
22
  @app_traceline = find_app_traceline(backtrace)
23
+ @first_timestamp = Time.now.to_i
23
24
 
24
25
  cleanup_prefixes.each do |path|
25
26
  @gem_traceline.delete_prefix!(path)
@@ -53,7 +54,7 @@ class DeprecationCollector
53
54
  end
54
55
 
55
56
  def digest_base
56
- "1:#{RUBY_VERSION}:#{Rails.version}:#{message_for_digest}:#{gem_traceline}:#{app_traceline}"
57
+ "1:#{RUBY_VERSION}:#{defined?(Rails) && Rails.version}:#{message_for_digest}:#{gem_traceline}:#{app_traceline}"
57
58
  end
58
59
 
59
60
  def as_json(_options = {})
@@ -68,6 +69,7 @@ class DeprecationCollector
68
69
  hostname: Socket.gethostname,
69
70
  revision: DeprecationCollector.instance.app_revision,
70
71
  count: @occurences, # output anyway for frequency estimation (during write_interval inside single process)
72
+ first_timestamp: first_timestamp, # this may not be accurate, a worker with later timestamp may dump earlier
71
73
  digest_base: digest_base # for debug purposes
72
74
  }.compact
73
75
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class DeprecationCollector
4
- VERSION = "0.0.2"
4
+ VERSION = "0.0.5"
5
5
  end
@@ -5,6 +5,7 @@ require_relative "deprecation_collector/deprecation"
5
5
  require_relative "deprecation_collector/collectors"
6
6
  require "time"
7
7
  require "redis"
8
+ require "json"
8
9
 
9
10
  # singleton class for collector
10
11
  class DeprecationCollector
@@ -53,7 +54,8 @@ class DeprecationCollector
53
54
  attr_accessor :count, :raise_on_deprecation, :save_full_backtrace,
54
55
  :exclude_realms,
55
56
  :write_interval, :write_interval_jitter,
56
- :app_revision, :app_root
57
+ :app_revision, :app_root,
58
+ :print_to_stderr, :print_recurring
57
59
  attr_writer :redis
58
60
 
59
61
  def initialize(mutex: nil)
@@ -96,8 +98,8 @@ class DeprecationCollector
96
98
  raise "Deprecation: #{message}" if @raise_on_deprecation
97
99
 
98
100
  deprecation = Deprecation.new(message, realm, backtrace, cleanup_prefixes)
99
- store_deprecation(deprecation)
100
- log_deprecation_if_needed(deprecation)
101
+ fresh = store_deprecation(deprecation)
102
+ log_deprecation_if_needed(deprecation, fresh)
101
103
  end
102
104
 
103
105
  def unsent_data?
@@ -163,6 +165,10 @@ class DeprecationCollector
163
165
  @redis.set("deprecations:enabled", "false")
164
166
  end
165
167
 
168
+ def dump
169
+ read_each.to_a.to_json
170
+ end
171
+
166
172
  def read_each
167
173
  return to_enum(:read_each) unless block_given?
168
174
 
@@ -185,10 +191,10 @@ class DeprecationCollector
185
191
  def read_one(digest)
186
192
  decode_deprecation(
187
193
  digest,
188
- *@redis.pipelined do
189
- @redis.hget("deprecations:data", digest)
190
- @redis.hget("deprecations:counter", digest)
191
- @redis.hget("deprecations:notes", digest)
194
+ *@redis.pipelined do |pipe|
195
+ pipe.hget("deprecations:data", digest)
196
+ pipe.hget("deprecations:counter", digest)
197
+ pipe.hget("deprecations:notes", digest)
192
198
  end
193
199
  )
194
200
  end
@@ -196,10 +202,10 @@ class DeprecationCollector
196
202
  def delete_deprecations(remove_digests)
197
203
  return 0 unless remove_digests.any?
198
204
 
199
- @redis.pipelined do
200
- @redis.hdel("deprecations:data", *remove_digests)
201
- @redis.hdel("deprecations:notes", *remove_digests)
202
- @redis.hdel("deprecations:counter", *remove_digests) if @count
205
+ @redis.pipelined do |pipe|
206
+ pipe.hdel("deprecations:data", *remove_digests)
207
+ pipe.hdel("deprecations:notes", *remove_digests)
208
+ pipe.hdel("deprecations:counter", *remove_digests) if @count
203
209
  end.first
204
210
  end
205
211
 
@@ -210,7 +216,7 @@ class DeprecationCollector
210
216
  cursor, data_pairs = @redis.hscan("deprecations:data", cursor) # NB: some pages may be empty
211
217
  total += data_pairs.size
212
218
  removed += delete_deprecations(
213
- data_pairs.select { |_digest, data| !block_given? || yield(JSON.parse(data, symbolize_names: true)) }.keys
219
+ data_pairs.to_h.select { |_digest, data| !block_given? || yield(JSON.parse(data, symbolize_names: true)) }.keys
214
220
  )
215
221
  break if cursor == "0"
216
222
  end
@@ -221,18 +227,22 @@ class DeprecationCollector
221
227
 
222
228
  def store_deprecation(deprecation)
223
229
  return if deprecation.ignored?
230
+ fresh = !@deprecations.key?(deprecation.digest)
224
231
 
225
232
  @deprecations_mutex.synchronize do
226
233
  (@deprecations[deprecation.digest] ||= deprecation).touch
227
234
  end
228
235
 
229
236
  write_to_redis if current_time - @last_write_time > (@write_interval + rand(@write_interval_jitter))
237
+ fresh
230
238
  end
231
239
 
232
- def log_deprecation_if_needed(deprecation)
233
- return unless defined?(Rails) && Rails.env.development? && !deprecation.ignored?
234
-
235
- $stderr.puts(deprecation.message) # rubocop:disable Style/StderrPuts
240
+ def log_deprecation_if_needed(deprecation, fresh)
241
+ return unless print_to_stderr && !deprecation.ignored?
242
+ return unless fresh || print_recurring
243
+ msg = deprecation.message
244
+ msg = "DEPRECATION: #{msg}" unless msg.start_with?('DEPRECAT')
245
+ $stderr.puts(msg) # rubocop:disable Style/StderrPuts
236
246
  end
237
247
 
238
248
  def current_time
@@ -242,7 +252,12 @@ class DeprecationCollector
242
252
  end
243
253
 
244
254
  def decode_deprecation(digest, data, count, notes)
255
+ return nil unless data
245
256
  data = JSON.parse(data, symbolize_names: true)
257
+ unless data.is_a?(Hash)
258
+ binding.irb
259
+ return nil
260
+ end
246
261
  data[:digest] = digest
247
262
  data[:notes] = JSON.parse(notes, symbolize_names: true) if notes
248
263
  data[:count] = count.to_i if count
@@ -250,9 +265,9 @@ class DeprecationCollector
250
265
  end
251
266
 
252
267
  def write_count_to_redis(deprecations_to_flush)
253
- @redis.pipelined do
268
+ @redis.pipelined do |pipe|
254
269
  deprecations_to_flush.each_pair do |digest, deprecation|
255
- @redis.hincrby("deprecations:counter", digest, deprecation.occurences)
270
+ pipe.hincrby("deprecations:counter", digest, deprecation.occurences)
256
271
  end
257
272
  end
258
273
  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.2
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vasily Fedoseyev
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-02 00:00:00.000000000 Z
11
+ date: 2022-09-02 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:
@@ -54,7 +54,7 @@ metadata:
54
54
  homepage_uri: https://github.com/Vasfed/deprecation_collector
55
55
  source_code_uri: https://github.com/Vasfed/deprecation_collector
56
56
  changelog_uri: https://github.com/Vasfed/deprecation_collector/blob/main/CHANGELOG.md
57
- post_install_message:
57
+ post_install_message:
58
58
  rdoc_options: []
59
59
  require_paths:
60
60
  - lib
@@ -70,7 +70,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
70
70
  version: '0'
71
71
  requirements: []
72
72
  rubygems_version: 3.1.6
73
- signing_key:
73
+ signing_key:
74
74
  specification_version: 4
75
75
  summary: Collector for ruby/rails deprecations and warnings, suitable for production
76
76
  test_files: []