temescal 0.1.1 → 0.1.2
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/README.md +2 -0
- data/lib/temescal.rb +1 -0
- data/lib/temescal/configuration.rb +11 -0
- data/lib/temescal/error.rb +68 -0
- data/lib/temescal/middleware.rb +11 -25
- data/lib/temescal/response.rb +5 -7
- data/lib/temescal/version.rb +1 -1
- data/spec/lib/temescal/error_spec.rb +79 -0
- data/spec/lib/temescal/middleware_spec.rb +26 -3
- data/spec/spec_helper.rb +13 -10
- metadata +13 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 703ee645d282ae0d060ee10a7c86f8e244abf307
|
4
|
+
data.tar.gz: 709b6344067afe53bd9bc0c0094c9931fb597d78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7adcffdc5f34d2e77da605d45ad237cdd7ee61ac5d8d382247b204223306ba8b461b2ccd0995ad1b3b06f485a81b870a6135303100e60f9d005965a25578b0e
|
7
|
+
data.tar.gz: 5d7e7cbc05af0e2f2b2c81c12a6839e1c375dc59ff77742b8cf949a42963bef0cbbf8b0840f246c6634ec3bf168991e804601331e4254a74df336c19ecaab4b0
|
data/README.md
CHANGED
@@ -49,5 +49,7 @@ Temescal provides several configuration options for you. You can set these optio
|
|
49
49
|
|
50
50
|
`default_message` to set an all-encompasing message to use in responses instead of the exception's message. Takes a string.
|
51
51
|
|
52
|
+
`ignored_errors` to set which exception types you'd like to not be reported to a monitor or logged. Specified errors will still have error responses built, but they won't trigger any sort of logging. It takes the class names of the exceptions you'd like ignored.
|
53
|
+
|
52
54
|
## License
|
53
55
|
Copyright 2013-2014 Todd Bealmear. See LICENSE for details.
|
data/lib/temescal.rb
CHANGED
@@ -4,6 +4,9 @@ module Temescal
|
|
4
4
|
# Public: Getter for monitors array.
|
5
5
|
attr_reader :monitors
|
6
6
|
|
7
|
+
# Public: Getter for ignored errors array.
|
8
|
+
attr_reader :ignored_errors
|
9
|
+
|
7
10
|
# Public: Setter for raise_errors option.
|
8
11
|
attr_writer :raise_errors
|
9
12
|
|
@@ -15,6 +18,7 @@ module Temescal
|
|
15
18
|
# Returns a new Configuration object.
|
16
19
|
def initialize
|
17
20
|
@monitors = []
|
21
|
+
@ignored_errors = []
|
18
22
|
end
|
19
23
|
|
20
24
|
# Public: Setter for monitors option.
|
@@ -42,6 +46,13 @@ module Temescal
|
|
42
46
|
@raise_errors == true || ENV["RACK_ENV"] == "test"
|
43
47
|
end
|
44
48
|
|
49
|
+
# Public: Setter for ignored_errors option.
|
50
|
+
#
|
51
|
+
# errors - Zero or more Exception classes.
|
52
|
+
def ignored_errors=(*errors)
|
53
|
+
@ignored_errors = errors.flatten
|
54
|
+
end
|
55
|
+
|
45
56
|
private
|
46
57
|
|
47
58
|
# Private: Converts a snake cased Symbol to a camel cased String.
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Temescal
|
2
|
+
class Error
|
3
|
+
NOT_FOUND_ERRORS = ["ActiveRecord::RecordNotFound", "Sinatra::NotFound"]
|
4
|
+
|
5
|
+
# Public: Instantiates a new Error.
|
6
|
+
#
|
7
|
+
# exception - The raw exception being rescued.
|
8
|
+
#
|
9
|
+
# Returns a new Error.
|
10
|
+
def initialize(exception)
|
11
|
+
@exception = exception
|
12
|
+
end
|
13
|
+
|
14
|
+
# Public: Determines whether to use a default message (as specified in the
|
15
|
+
# configuration) or the exception's message for the API response.
|
16
|
+
#
|
17
|
+
# Returns a String that's either the default message or the exception's
|
18
|
+
# message.
|
19
|
+
def message
|
20
|
+
configuration.default_message || @exception.message
|
21
|
+
end
|
22
|
+
|
23
|
+
# Public: Determines the proper error code for the exception.
|
24
|
+
#
|
25
|
+
# Returns a Fixnum based on the exception's type and http_status
|
26
|
+
# attribute (if applicable), will return a generic 500 for all others.
|
27
|
+
def status
|
28
|
+
return 404 if NOT_FOUND_ERRORS.include? @exception.class.to_s
|
29
|
+
@exception.respond_to?(:http_status) ? @exception.http_status : 500
|
30
|
+
end
|
31
|
+
|
32
|
+
# Public: Formats the exception for logging.
|
33
|
+
#
|
34
|
+
# Returns a String containing the relevant exception information to log
|
35
|
+
# via STDERR.
|
36
|
+
def formatted
|
37
|
+
message = "\n#{@exception.class}: #{@exception.message}\n "
|
38
|
+
message << @exception.backtrace.join("\n ")
|
39
|
+
message << "\n\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Public: Gets the exception's type.
|
43
|
+
#
|
44
|
+
# Returns a String representing the exception class name.
|
45
|
+
def type
|
46
|
+
@exception.class.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
# Public: Determines whether an exception should be silenced.
|
50
|
+
#
|
51
|
+
# Returns true if the error type is configured as an ignored error, false
|
52
|
+
# otherwise.
|
53
|
+
def ignore?
|
54
|
+
configuration.ignored_errors.each do |error|
|
55
|
+
return true if @exception.is_a? error
|
56
|
+
end
|
57
|
+
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# Private: Getter for Temescal configuration.
|
64
|
+
def configuration
|
65
|
+
$_temescal_configuration
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/temescal/middleware.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
module Temescal
|
2
2
|
class Middleware
|
3
|
-
NOT_FOUND_ERRORS = ["ActiveRecord::RecordNotFound", "Sinatra::NotFound"]
|
4
|
-
|
5
3
|
# Public: Initializes the middleware.
|
6
4
|
#
|
7
5
|
# app - The Rack application.
|
@@ -23,40 +21,28 @@ module Temescal
|
|
23
21
|
def call(env)
|
24
22
|
begin
|
25
23
|
@status, @headers, @response = @app.call(env)
|
26
|
-
rescue =>
|
24
|
+
rescue => exception
|
27
25
|
raise if configuration.raise_errors?
|
28
26
|
|
29
|
-
|
30
|
-
message = configuration.default_message || @error.message
|
27
|
+
error = Error.new(exception)
|
31
28
|
|
32
|
-
|
33
|
-
|
29
|
+
unless error.ignore?
|
30
|
+
$stderr.print error.formatted
|
31
|
+
configuration.monitors.each { |monitor| monitor.report(exception) }
|
32
|
+
end
|
34
33
|
|
35
|
-
@status =
|
36
|
-
@response = Response.build(
|
37
|
-
@headers = { "Content-Type"
|
34
|
+
@status = error.status
|
35
|
+
@response = Response.build(error)
|
36
|
+
@headers = { "Content-Type" => "application/json" }
|
38
37
|
end
|
39
38
|
[@status, @headers, @response]
|
40
39
|
end
|
41
40
|
|
42
41
|
private
|
43
42
|
|
44
|
-
# Private: Getter for
|
43
|
+
# Private: Getter for Temescal configuration.
|
45
44
|
def configuration
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
# Private: Formats the exception for logging.
|
50
|
-
def formatted_error
|
51
|
-
message = "\n#{@error.class}: #{@error.message}\n "
|
52
|
-
message << @error.backtrace.join("\n ")
|
53
|
-
message << "\n\n"
|
54
|
-
end
|
55
|
-
|
56
|
-
# Private: Returns the proper error code for the exception.
|
57
|
-
def set_status
|
58
|
-
return 404 if NOT_FOUND_ERRORS.include? @error.class.to_s
|
59
|
-
@error.respond_to?(:http_status) ? @error.http_status : 500
|
45
|
+
$_temescal_configuration ||= Configuration.new
|
60
46
|
end
|
61
47
|
end
|
62
48
|
end
|
data/lib/temescal/response.rb
CHANGED
@@ -5,18 +5,16 @@ module Temescal
|
|
5
5
|
|
6
6
|
# Public: Builds a response body for the Rack response.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
# exception - The caught exception.
|
10
|
-
# message - The error message.
|
8
|
+
# error - The Temescal::Error object representing the caught exception.
|
11
9
|
#
|
12
10
|
# Returns an Array containing a JSON string as the response body.
|
13
|
-
def self.build(
|
11
|
+
def self.build(error)
|
14
12
|
[
|
15
13
|
{
|
16
14
|
meta: {
|
17
|
-
status: status,
|
18
|
-
error:
|
19
|
-
message: message
|
15
|
+
status: error.status,
|
16
|
+
error: error.type,
|
17
|
+
message: error.message
|
20
18
|
}
|
21
19
|
}.to_json
|
22
20
|
]
|
data/lib/temescal/version.rb
CHANGED
@@ -0,0 +1,79 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Temescal::Error do
|
4
|
+
let(:exception) { StandardError.new("Foobar") }
|
5
|
+
let(:error) { Temescal::Error.new(exception) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
# This is admittedly a little hacky, but it's the best way to prevent
|
9
|
+
# previously memoized configurations from polluting these tests.
|
10
|
+
$_temescal_configuration = Temescal::Configuration.new
|
11
|
+
end
|
12
|
+
|
13
|
+
context "#message" do
|
14
|
+
it "should return the configured default message if it is set in the configuration" do
|
15
|
+
Temescal::Configuration.any_instance.stub(:default_message).and_return("Some other message.")
|
16
|
+
|
17
|
+
expect(error.message).to eq "Some other message."
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return the exception's message if the default message is not configured" do
|
21
|
+
expect(error.message).to eq "Foobar"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "#status" do
|
26
|
+
it "should return 404 if the exception is an ActiveRecord::RecordNotFound" do
|
27
|
+
exception = ActiveRecord::RecordNotFound.new
|
28
|
+
error = Temescal::Error.new(exception)
|
29
|
+
|
30
|
+
expect(error.status).to eq 404
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return 404 if the exception is a Sinatra::NotFound" do
|
34
|
+
exception = Sinatra::NotFound.new
|
35
|
+
error = Temescal::Error.new(exception)
|
36
|
+
|
37
|
+
expect(error.status).to eq 404
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return the exception's status code if assigned" do
|
41
|
+
exception.stub(:http_status).and_return(403)
|
42
|
+
|
43
|
+
expect(error.status).to eq 403
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return 500 for all other exceptions" do
|
47
|
+
expect(error.status).to eq 500
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "#formatted" do
|
52
|
+
it "should return a String formatted for log output" do
|
53
|
+
exception.stub(:backtrace).and_return(["Line 1", "Line 2"])
|
54
|
+
|
55
|
+
expect(error.formatted).to eq "\nStandardError: Foobar\n Line 1\n Line 2\n\n"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "#type" do
|
60
|
+
it "should return the exception's class name" do
|
61
|
+
expect(error.type).to eq "StandardError"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "#ignore?" do
|
66
|
+
before do
|
67
|
+
Temescal::Configuration.any_instance.stub(:ignored_errors).and_return([TypeError])
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should return true if the exception type is configured as an ignored error" do
|
71
|
+
error = Temescal::Error.new(TypeError.new)
|
72
|
+
expect(error.ignore?).to be_true
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should return false if the exception type is not an ignored error" do
|
76
|
+
expect(error.ignore?).to be_false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
require "active_record"
|
4
|
-
require "sinatra"
|
5
|
-
|
6
3
|
describe Temescal::Middleware do
|
4
|
+
before do
|
5
|
+
$_temescal_configuration = nil
|
6
|
+
end
|
7
|
+
|
7
8
|
context "Ok response" do
|
8
9
|
let(:app) { ->(env) { [200, env, "app" ] } }
|
9
10
|
|
@@ -33,6 +34,7 @@ describe Temescal::Middleware do
|
|
33
34
|
let(:middleware) do
|
34
35
|
Temescal::Middleware.new(app) do |config|
|
35
36
|
config.monitors = :new_relic
|
37
|
+
config.ignored_errors = TypeError
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
@@ -111,6 +113,27 @@ describe Temescal::Middleware do
|
|
111
113
|
expect(code).to eq 404
|
112
114
|
end
|
113
115
|
end
|
116
|
+
|
117
|
+
context "with ignore_errors set" do
|
118
|
+
let(:middleware) do
|
119
|
+
Temescal::Middleware.new(app) do |config|
|
120
|
+
config.ignored_errors = StandardError, TypeError
|
121
|
+
config.monitors = :new_relic
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should not log an ignored error type" do
|
126
|
+
expect($stderr).to_not receive(:print).with(an_instance_of String)
|
127
|
+
|
128
|
+
middleware.call env_for("http://foobar.com")
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should not report an ignored error type" do
|
132
|
+
expect(Temescal::Monitors::NewRelic).to_not receive(:report).with(an_instance_of StandardError)
|
133
|
+
|
134
|
+
middleware.call env_for("http://foobar.com")
|
135
|
+
end
|
136
|
+
end
|
114
137
|
end
|
115
138
|
|
116
139
|
context "Override middleware to raise exception" do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,20 +1,23 @@
|
|
1
|
-
if ENV[
|
2
|
-
require
|
1
|
+
if ENV["CI"]
|
2
|
+
require "coveralls"
|
3
3
|
Coveralls.wear!
|
4
4
|
else
|
5
|
-
require
|
6
|
-
require
|
5
|
+
require "awesome_print"
|
6
|
+
require "pry-debugger"
|
7
7
|
|
8
|
-
require
|
8
|
+
require "simplecov"
|
9
9
|
SimpleCov.start
|
10
10
|
end
|
11
11
|
|
12
|
-
require
|
12
|
+
require "rack"
|
13
13
|
|
14
|
-
require
|
15
|
-
require
|
14
|
+
require "airbrake"
|
15
|
+
require "newrelic_rpm"
|
16
16
|
|
17
|
-
require
|
17
|
+
require "active_record"
|
18
|
+
require "sinatra"
|
19
|
+
|
20
|
+
require "temescal"
|
18
21
|
|
19
22
|
RSpec.configure do |config|
|
20
23
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
@@ -25,5 +28,5 @@ RSpec.configure do |config|
|
|
25
28
|
# order dependency and want to debug it, you can fix the order by providing
|
26
29
|
# the seed, which is printed after each run.
|
27
30
|
# --seed 1234
|
28
|
-
config.order =
|
31
|
+
config.order = "random"
|
29
32
|
end
|
metadata
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: temescal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Todd Bealmear
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '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
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
description: Rack Middleware for gracefully handling exceptions for JSON APIs.
|
@@ -48,17 +48,19 @@ files:
|
|
48
48
|
- LICENSE
|
49
49
|
- README.md
|
50
50
|
- Rakefile
|
51
|
-
-
|
51
|
+
- temescal.gemspec
|
52
52
|
- lib/temescal/configuration.rb
|
53
|
+
- lib/temescal/error.rb
|
53
54
|
- lib/temescal/middleware.rb
|
54
55
|
- lib/temescal/monitors.rb
|
55
56
|
- lib/temescal/response.rb
|
56
57
|
- lib/temescal/version.rb
|
58
|
+
- lib/temescal.rb
|
57
59
|
- spec/lib/temescal/configuration_spec.rb
|
60
|
+
- spec/lib/temescal/error_spec.rb
|
58
61
|
- spec/lib/temescal/middleware_spec.rb
|
59
62
|
- spec/lib/temescal/monitors_spec.rb
|
60
63
|
- spec/spec_helper.rb
|
61
|
-
- temescal.gemspec
|
62
64
|
homepage: https://github.com/todd/temescal
|
63
65
|
licenses:
|
64
66
|
- MIT
|
@@ -69,17 +71,17 @@ require_paths:
|
|
69
71
|
- lib
|
70
72
|
required_ruby_version: !ruby/object:Gem::Requirement
|
71
73
|
requirements:
|
72
|
-
- -
|
74
|
+
- - '>='
|
73
75
|
- !ruby/object:Gem::Version
|
74
76
|
version: '0'
|
75
77
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
78
|
requirements:
|
77
|
-
- -
|
79
|
+
- - '>='
|
78
80
|
- !ruby/object:Gem::Version
|
79
81
|
version: '0'
|
80
82
|
requirements: []
|
81
83
|
rubyforge_project:
|
82
|
-
rubygems_version: 2.
|
84
|
+
rubygems_version: 2.0.3
|
83
85
|
signing_key:
|
84
86
|
specification_version: 4
|
85
87
|
summary: Rack Middleware for gracefully handling exceptions for JSON APIs.
|