deprecation_collector 0.0.2 → 0.0.5

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: 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: []