safely_block 0.1.0 → 0.1.1

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
  SHA1:
3
- metadata.gz: 65bad436ec7ddcd49ef1836e3ec0f077b8754290
4
- data.tar.gz: fcafabce7a11b00143410a3083f78cbdee24bab3
3
+ metadata.gz: 9ba20f765b3e7d5a3a42de0c5376d06f2fa1a123
4
+ data.tar.gz: 100cf5b7ab1a8fba676b64e7914908d7d23f8276
5
5
  SHA512:
6
- metadata.gz: 180b1e137dcf01415624ea95333f2e571cd96edcaedb628ed99d83cb32d787ba470f8afc8f4084352cce7f5b162719bee5435e8742a431391dd0b5c95a0a4ff3
7
- data.tar.gz: 381c7aa036d20fd55577d67425e2f4a264af515231bb65c25d124b8bf68c0eb3f789cfe4338f4c859d8ce69d8ccaaf931e7317c20287982c4068655992bb72bd
6
+ metadata.gz: c781fdff6e44069440281ba046b853e97a187c0ef59110231c4571113abd6451f15ecbb94484b7c53afcd0c2d07e24f8ddd28a3cd1ed843611dfcb2d97b73ee2
7
+ data.tar.gz: 1d261002fdf45d8fe088a75203ce55e61467aefb41547abbbad2ae617384f3f9bb3579b3ea961e24369daa21666dcd91803fde2eb8c9accd9a41521f1625d765
@@ -1,3 +1,8 @@
1
+ ## 0.1.1
2
+
3
+ - Added `Safely.safely` to not pollute when included in gems
4
+ - Added `throttle` option
5
+
1
6
  ## 0.1.0
2
7
 
3
8
  - Added `tag` option and tag exception message by default
data/README.md CHANGED
@@ -1,30 +1,28 @@
1
1
  # Safely
2
2
 
3
- Unexpected data can cause errors in production - don’t let it bring down the system
4
-
5
3
  ```ruby
6
4
  safely do
7
5
  # keep going if this code fails
8
6
  end
9
7
  ```
10
8
 
11
- Exceptions are rescued and reported to your favorite reporting service.
9
+ Exceptions are rescued and automatically reported to your favorite reporting service.
12
10
 
13
- In development and test environments, exceptions are raised so you can fix them. :smirk:
11
+ In development and test environments, exceptions are raised so you can fix them.
14
12
 
15
- ## Examples
13
+ ## Use It Everywhere
16
14
 
17
- Great for analytics
15
+ “Oh no, analytics brought down search”
18
16
 
19
17
  ```ruby
20
- safely { track_event("Search") }
18
+ safely { track_search(params) }
21
19
  ```
22
20
 
23
- and background jobs
21
+ “Recommendations stopped updating because of one bad user”
24
22
 
25
23
  ```ruby
26
- User.find_each do |user|
27
- safely { cache_recommendations(user) }
24
+ users.each do |user|
25
+ safely { update_recommendations(user) }
28
26
  end
29
27
  ```
30
28
 
@@ -32,18 +30,10 @@ Also aliased as `yolo`.
32
30
 
33
31
  ## Features
34
32
 
35
- Throttle reporting with:
36
-
37
- ```ruby
38
- safely sample: 1000 do
39
- # reports ~ 1/1000 errors
40
- end
41
- ```
42
-
43
33
  Specify a default value to return on exceptions
44
34
 
45
35
  ```ruby
46
- score = safely(default: 30) { calculate_score }
36
+ show_banner = safely(default: true) { show_banner_logic }
47
37
  ```
48
38
 
49
39
  Raise specific exceptions
@@ -70,6 +60,16 @@ Silence exceptions
70
60
  safely(silence: ActiveRecord::RecordNotUnique) { code }
71
61
  ```
72
62
 
63
+ Throttle reporting with:
64
+
65
+ ```ruby
66
+ safely throttle: {limit: 10, period: 1.minute} do
67
+ # reports only first 10 exceptions each minute
68
+ end
69
+ ```
70
+
71
+ **Note:** The throttle limit is approximate and per process.
72
+
73
73
  ## Reporting
74
74
 
75
75
  Reports exceptions to a variety of services out of the box thanks to [Errbase](https://github.com/ankane/errbase).
@@ -96,6 +96,12 @@ By default, exception messages are prefixed with `[safely]`. This makes it easie
96
96
  Safely.tag = false
97
97
  ```
98
98
 
99
+ To report exceptions manually:
100
+
101
+ ```ruby
102
+ Safely.report_exception(e)
103
+ ```
104
+
99
105
  ## Installation
100
106
 
101
107
  Add this line to your application’s Gemfile:
@@ -0,0 +1,57 @@
1
+ require "safely/version"
2
+ require "errbase"
3
+ require "digest"
4
+
5
+ module Safely
6
+ class << self
7
+ attr_accessor :raise_envs, :tag, :report_exception_method, :throttle_counter
8
+ attr_writer :env
9
+
10
+ def report_exception(e)
11
+ report_exception_method.call(e)
12
+ end
13
+
14
+ def env
15
+ @env ||= ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
16
+ end
17
+
18
+ def throttled?(e, options)
19
+ return false unless options
20
+ key = "#{options[:key] || Digest::MD5.hexdigest([e.class.name, e.message, e.backtrace.join("\n")].join("/"))}/#{(Time.now.to_i / options[:period]) * options[:period]}"
21
+ throttle_counter.clear if throttle_counter.size > 1000 # prevent from growing indefinitely
22
+ (throttle_counter[key] += 1) > options[:limit]
23
+ end
24
+ end
25
+
26
+ DEFAULT_EXCEPTION_METHOD = proc do |e|
27
+ e = e.dup # leave original exception unmodified
28
+ e.message.prepend("[safely] ") if e.message && Safely.tag
29
+ Errbase.report(e)
30
+ end
31
+
32
+ self.tag = true
33
+ self.report_exception_method = DEFAULT_EXCEPTION_METHOD
34
+ self.raise_envs = %w(development test)
35
+ # not thread-safe, but we don't need to be exact
36
+ self.throttle_counter = Hash.new(0)
37
+
38
+ module Methods
39
+ def safely(options = {})
40
+ yield
41
+ rescue *Array(options[:only] || StandardError) => e
42
+ raise e if Array(options[:except]).any? { |c| e.is_a?(c) }
43
+ raise e if Safely.raise_envs.include?(Safely.env)
44
+ sample = options[:sample]
45
+ if sample ? rand < 1.0 / sample : true
46
+ begin
47
+ Safely.report_exception(e) unless Array(options[:silence]).any? { |c| e.is_a?(c) } || Safely.throttled?(e, options[:throttle])
48
+ rescue => e2
49
+ $stderr.puts "FAIL-SAFE #{e2.class.name}: #{e2.message}"
50
+ end
51
+ end
52
+ options[:default]
53
+ end
54
+ alias_method :yolo, :safely
55
+ end
56
+ extend Methods
57
+ end
@@ -0,0 +1,3 @@
1
+ module Safely
2
+ VERSION = "0.1.1"
3
+ end
@@ -1,45 +1,3 @@
1
- require "errbase"
2
-
3
- module Safely
4
- VERSION = "0.1.0"
5
-
6
- class << self
7
- attr_accessor :env, :raise_envs, :tag, :report_exception_method
8
-
9
- def report_exception(e)
10
- report_exception_method.call(e)
11
- end
12
- end
13
-
14
- DEFAULT_EXCEPTION_METHOD = proc do |e|
15
- e = e.dup # leave original exception unmodified
16
- e.message.prepend("[safely] ") if e.message && Safely.tag
17
- Errbase.report(e)
18
- end
19
-
20
- self.env = ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"
21
- self.tag = true
22
- self.report_exception_method = DEFAULT_EXCEPTION_METHOD
23
- self.raise_envs = %w(development test)
24
-
25
- module Methods
26
- def safely(options = {})
27
- yield
28
- rescue *Array(options[:only] || StandardError) => e
29
- raise e if Array(options[:except]).any? { |c| e.is_a?(c) }
30
- raise e if Safely.raise_envs.include?(Safely.env)
31
- sample = options[:sample]
32
- if sample ? rand < 1.0 / sample : true
33
- begin
34
- Safely.report_exception(e) unless Array(options[:silence]).any? { |c| e.is_a?(c) }
35
- rescue => e2
36
- $stderr.puts "FAIL-SAFE #{e2.class.name}: #{e2.message}"
37
- end
38
- end
39
- options[:default]
40
- end
41
- alias_method :yolo, :safely
42
- end
43
- end
1
+ require "safely/core"
44
2
 
45
3
  Object.send :include, Safely::Methods
@@ -1,16 +1,16 @@
1
1
  # coding: utf-8
2
2
  lib = File.expand_path("../lib", __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "safely_block"
4
+ require "safely/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "safely_block"
8
8
  spec.version = Safely::VERSION
9
9
  spec.authors = ["Andrew Kane"]
10
10
  spec.email = ["andrew@chartkick.com"]
11
- spec.summary = "Don’t let small errors bring down the system"
12
- spec.description = "Don’t let small errors bring down the system"
13
- spec.homepage = "https://github.com/ankane/safely_block"
11
+ spec.summary = "Awesome exception handling"
12
+ spec.description = "Awesome exception handling"
13
+ spec.homepage = "https://github.com/ankane/safely"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
@@ -82,4 +82,26 @@ class TestSafely < Minitest::Test
82
82
  end
83
83
  assert_equal "FAIL-SAFE RuntimeError: oops\n", err
84
84
  end
85
+
86
+ def test_throttle
87
+ count = 0
88
+ Safely.report_exception_method = proc { |e| count += 1 }
89
+ 5.times do |n|
90
+ safely throttle: {limit: 2, period: 3600} do
91
+ raise Safely::TestError
92
+ end
93
+ end
94
+ assert_equal 2, count
95
+ end
96
+
97
+ def test_throttle_key
98
+ count = 0
99
+ Safely.report_exception_method = proc { |e| count += 1 }
100
+ 5.times do |n|
101
+ safely throttle: {limit: 2, period: 3600, key: "boom#{n % 2}"} do
102
+ raise Safely::TestError
103
+ end
104
+ end
105
+ assert_equal 4, count
106
+ end
85
107
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safely_block
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-15 00:00:00.000000000 Z
11
+ date: 2016-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: errbase
@@ -66,7 +66,7 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '5'
69
- description: Don’t let small errors bring down the system
69
+ description: Awesome exception handling
70
70
  email:
71
71
  - andrew@chartkick.com
72
72
  executables: []
@@ -79,11 +79,13 @@ files:
79
79
  - LICENSE.txt
80
80
  - README.md
81
81
  - Rakefile
82
+ - lib/safely/core.rb
83
+ - lib/safely/version.rb
82
84
  - lib/safely_block.rb
83
85
  - safely_block.gemspec
84
86
  - test/safely_test.rb
85
87
  - test/test_helper.rb
86
- homepage: https://github.com/ankane/safely_block
88
+ homepage: https://github.com/ankane/safely
87
89
  licenses:
88
90
  - MIT
89
91
  metadata: {}
@@ -103,10 +105,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
105
  version: '0'
104
106
  requirements: []
105
107
  rubyforge_project:
106
- rubygems_version: 2.4.5
108
+ rubygems_version: 2.6.1
107
109
  signing_key:
108
110
  specification_version: 4
109
- summary: Don’t let small errors bring down the system
111
+ summary: Awesome exception handling
110
112
  test_files:
111
113
  - test/safely_test.rb
112
114
  - test/test_helper.rb