appygram-rails 0.9.5 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/appygram-rails.gemspec +4 -3
- data/lib/appygram-rails.rb +2 -95
- data/lib/appygram-rails/catcher.rb +4 -27
- data/lib/appygram-rails/integration/rack_rails.rb +2 -2
- data/lib/appygram-rails/version.rb +2 -2
- metadata +21 -20
- data/lib/appygram-rails/alert_data.rb +0 -15
- data/lib/appygram-rails/application_environment.rb +0 -55
- data/lib/appygram-rails/config.rb +0 -63
- data/lib/appygram-rails/controller_exception_data.rb +0 -75
- data/lib/appygram-rails/exception_data.rb +0 -108
- data/lib/appygram-rails/integration/alerter.rb +0 -11
- data/lib/appygram-rails/integration/debug_exceptions.rb +0 -16
- data/lib/appygram-rails/integration/rack.rb +0 -28
- data/lib/appygram-rails/log_factory.rb +0 -39
- data/lib/appygram-rails/monkeypatches.rb +0 -10
- data/lib/appygram-rails/rack_exception_data.rb +0 -29
- data/lib/appygram-rails/remote.rb +0 -52
- data/lib/appygram-rails/startup.rb +0 -14
data/appygram-rails.gemspec
CHANGED
@@ -5,10 +5,10 @@ require 'appygram-rails/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
7
|
gem.name = %q{appygram-rails}
|
8
|
-
gem.version =
|
8
|
+
gem.version = AppygramRails::VERSION
|
9
9
|
gem.authors = ["rfc2616"]
|
10
10
|
gem.summary = %q{ appygram is a hosted service for sending messages from mobile/web apps }
|
11
|
-
gem.description = %q{appygram-rails sends exceptions
|
11
|
+
gem.description = %q{appygram-rails sends uncaught Rails exceptions as traces to the hosted messaging service at http://www.appygram.com}
|
12
12
|
gem.email = ['heittman.rob@gmail.com']
|
13
13
|
gem.homepage = 'http://www.appygram.com/'
|
14
14
|
|
@@ -17,5 +17,6 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
|
20
|
-
gem.add_runtime_dependency '
|
20
|
+
gem.add_runtime_dependency 'appygram', '~> 1.0', '>= 1.0.3'
|
21
|
+
gem.add_runtime_dependency 'rack'
|
21
22
|
end
|
data/lib/appygram-rails.rb
CHANGED
@@ -1,106 +1,13 @@
|
|
1
|
-
require 'appygram-rails/monkeypatches'
|
2
1
|
require 'appygram-rails/catcher'
|
3
|
-
require 'appygram-rails/startup'
|
4
|
-
require 'appygram-rails/log_factory'
|
5
|
-
require 'appygram-rails/config'
|
6
|
-
require 'appygram-rails/application_environment'
|
7
|
-
require 'appygram-rails/exception_data'
|
8
|
-
require 'appygram-rails/controller_exception_data'
|
9
|
-
require 'appygram-rails/rack_exception_data'
|
10
|
-
require 'appygram-rails/alert_data'
|
11
|
-
require 'appygram-rails/remote'
|
12
|
-
require 'appygram-rails/integration/rack'
|
13
2
|
require 'appygram-rails/integration/rack_rails'
|
14
|
-
require 'appygram-rails/integration/alerter'
|
15
3
|
require 'appygram-rails/version'
|
16
|
-
require 'appygram-rails/integration/debug_exceptions'
|
17
4
|
|
18
|
-
module
|
19
|
-
|
20
|
-
PROTOCOL_VERSION = 5
|
21
|
-
CLIENT_NAME = 'appygram-rails'
|
22
|
-
ENVIRONMENT_FILTER = []
|
23
|
-
|
24
|
-
@@limit = 25
|
25
|
-
|
26
|
-
def self.restrict_duplicates(hash)
|
27
|
-
return false unless @@limit > 0
|
28
|
-
|
29
|
-
@@throttle ||= Hash.new
|
30
|
-
@@last_used ||= Date.today
|
31
|
-
if Date.today.yday != @@last_used.yday
|
32
|
-
@@last_used = Date.today
|
33
|
-
@@throttle = Hash.new
|
34
|
-
end
|
35
|
-
if @@throttle[hash]
|
36
|
-
@@throttle[hash] = @@throttle[hash] + 1
|
37
|
-
else
|
38
|
-
@@throttle[hash] = 1
|
39
|
-
end
|
40
|
-
if @@throttle[hash] > @@limit
|
41
|
-
return true
|
42
|
-
end
|
43
|
-
return false
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.set_duplicate_limit(limit)
|
47
|
-
@@limit = limit
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.logger
|
51
|
-
::Appygram::LogFactory.logger
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.configure(api_key)
|
55
|
-
Appygram::Config.api_key = api_key
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.handle(exception, name=nil)
|
59
|
-
Appygram::Catcher.handle(exception, name)
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.rescue(name=nil, context=nil, &block)
|
63
|
-
begin
|
64
|
-
self.context(context) unless context.nil?
|
65
|
-
block.call
|
66
|
-
rescue Exception => e
|
67
|
-
Appygram::Catcher.handle(e,name)
|
68
|
-
ensure
|
69
|
-
self.clear!
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.rescue_and_reraise(name=nil, context=nil, &block)
|
74
|
-
begin
|
75
|
-
self.context(context) unless context.nil?
|
76
|
-
block.call
|
77
|
-
rescue Exception => e
|
78
|
-
Appygram::Catcher.handle(e,name)
|
79
|
-
raise(e)
|
80
|
-
ensure
|
81
|
-
self.clear!
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def self.clear!
|
86
|
-
Thread.current[:appygram_context] = nil
|
87
|
-
end
|
88
|
-
|
89
|
-
def self.context(hash = {})
|
90
|
-
Thread.current[:appygram_context] ||= {}
|
91
|
-
Thread.current[:appygram_context].merge!(hash)
|
92
|
-
self
|
93
|
-
end
|
5
|
+
module AppygramRails
|
94
6
|
|
95
7
|
class Railtie < Rails::Railtie
|
96
8
|
|
97
9
|
initializer "appygram.middleware" do |app|
|
98
|
-
|
99
|
-
if defined?(ActionDispatch::DebugExceptions)
|
100
|
-
ActionDispatch::DebugExceptions.send(:include,Appygram::DebugExceptions)
|
101
|
-
else
|
102
|
-
app.config.middleware.use "Rack::RailsAppygram"
|
103
|
-
end
|
10
|
+
app.config.middleware.use "Rack::RailsAppygram"
|
104
11
|
end
|
105
12
|
|
106
13
|
end
|
@@ -1,33 +1,10 @@
|
|
1
|
-
|
1
|
+
require 'appygram'
|
2
|
+
|
3
|
+
module AppygramRails
|
2
4
|
class Catcher
|
3
5
|
class << self
|
4
6
|
def handle_with_controller(exception, controller=nil, request=nil)
|
5
|
-
|
6
|
-
data = ControllerExceptionData.new(exception, controller, request)
|
7
|
-
Remote.error(data)
|
8
|
-
else
|
9
|
-
raise exception
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
# unspeced
|
14
|
-
def handle_with_rack(exception, environment, request)
|
15
|
-
if Config.should_send_to_api?
|
16
|
-
data = RackExceptionData.new(exception, environment, request)
|
17
|
-
Remote.error(data)
|
18
|
-
else
|
19
|
-
raise exception
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# unspeced
|
24
|
-
def handle(exception, name=nil)
|
25
|
-
if Config.should_send_to_api?
|
26
|
-
data = ExceptionData.new(exception, name)
|
27
|
-
Remote.error(data)
|
28
|
-
else
|
29
|
-
raise exception
|
30
|
-
end
|
7
|
+
Appygram.trace(exception)
|
31
8
|
end
|
32
9
|
end
|
33
10
|
end
|
@@ -12,12 +12,12 @@ module Rack
|
|
12
12
|
begin
|
13
13
|
body = @app.call(env)
|
14
14
|
rescue Exception => e
|
15
|
-
::
|
15
|
+
::AppygramRails::Catcher.handle_with_controller(e,env['action_controller.instance'], Rack::Request.new(env))
|
16
16
|
raise
|
17
17
|
end
|
18
18
|
|
19
19
|
if env['rack.exception']
|
20
|
-
::
|
20
|
+
::AppygramRails::Catcher.handle_with_controller(env['rack.exception'],env['action_controller.instance'], Rack::Request.new(env))
|
21
21
|
end
|
22
22
|
|
23
23
|
body
|
@@ -1,3 +1,3 @@
|
|
1
|
-
module
|
2
|
-
VERSION = '0.
|
1
|
+
module AppygramRails
|
2
|
+
VERSION = '1.0.1'
|
3
3
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appygram-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,25 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement: &
|
15
|
+
name: appygram
|
16
|
+
requirement: &20298560 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.0'
|
22
|
+
- - ! '>='
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.0.3
|
25
|
+
type: :runtime
|
26
|
+
prerelease: false
|
27
|
+
version_requirements: *20298560
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rack
|
30
|
+
requirement: &20297860 !ruby/object:Gem::Requirement
|
17
31
|
none: false
|
18
32
|
requirements:
|
19
33
|
- - ! '>='
|
@@ -21,9 +35,9 @@ dependencies:
|
|
21
35
|
version: '0'
|
22
36
|
type: :runtime
|
23
37
|
prerelease: false
|
24
|
-
version_requirements: *
|
25
|
-
description: appygram-rails sends exceptions
|
26
|
-
service at http://www.appygram.com
|
38
|
+
version_requirements: *20297860
|
39
|
+
description: appygram-rails sends uncaught Rails exceptions as traces to the hosted
|
40
|
+
messaging service at http://www.appygram.com
|
27
41
|
email:
|
28
42
|
- heittman.rob@gmail.com
|
29
43
|
executables: []
|
@@ -38,21 +52,8 @@ files:
|
|
38
52
|
- Rakefile
|
39
53
|
- appygram-rails.gemspec
|
40
54
|
- lib/appygram-rails.rb
|
41
|
-
- lib/appygram-rails/alert_data.rb
|
42
|
-
- lib/appygram-rails/application_environment.rb
|
43
55
|
- lib/appygram-rails/catcher.rb
|
44
|
-
- lib/appygram-rails/config.rb
|
45
|
-
- lib/appygram-rails/controller_exception_data.rb
|
46
|
-
- lib/appygram-rails/exception_data.rb
|
47
|
-
- lib/appygram-rails/integration/alerter.rb
|
48
|
-
- lib/appygram-rails/integration/debug_exceptions.rb
|
49
|
-
- lib/appygram-rails/integration/rack.rb
|
50
56
|
- lib/appygram-rails/integration/rack_rails.rb
|
51
|
-
- lib/appygram-rails/log_factory.rb
|
52
|
-
- lib/appygram-rails/monkeypatches.rb
|
53
|
-
- lib/appygram-rails/rack_exception_data.rb
|
54
|
-
- lib/appygram-rails/remote.rb
|
55
|
-
- lib/appygram-rails/startup.rb
|
56
57
|
- lib/appygram-rails/version.rb
|
57
58
|
homepage: http://www.appygram.com/
|
58
59
|
licenses: []
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module Appygram
|
2
|
-
class AlertData < ExceptionData
|
3
|
-
# Overwrite backtrace, since it is irrelevant
|
4
|
-
def extra_data
|
5
|
-
{
|
6
|
-
'exception' => {
|
7
|
-
'exception_class' => @exception.class.to_s,
|
8
|
-
'message' => @exception.message,
|
9
|
-
'backtrace' => "",
|
10
|
-
'occurred_at' => Time.now
|
11
|
-
}
|
12
|
-
}
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'digest/md5'
|
2
|
-
|
3
|
-
module Appygram
|
4
|
-
class ApplicationEnvironment
|
5
|
-
def self.to_hash(framework)
|
6
|
-
{
|
7
|
-
'client' => {
|
8
|
-
'name' => Appygram::CLIENT_NAME,
|
9
|
-
'version' => Appygram::VERSION,
|
10
|
-
'protocol_version' => Appygram::PROTOCOL_VERSION
|
11
|
-
},
|
12
|
-
'application_environment' => {
|
13
|
-
'host' => get_hostname,
|
14
|
-
'run_as_user' => get_username,
|
15
|
-
'application_root_directory' => (application_root.to_s.respond_to?(:force_encoding) ? application_root.to_s.force_encoding("UTF-8") : application_root),
|
16
|
-
'language' => 'ruby',
|
17
|
-
'language_version' => language_version_string,
|
18
|
-
'framework' => framework,
|
19
|
-
'libraries_loaded' => libraries_loaded
|
20
|
-
}
|
21
|
-
}
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.environment
|
25
|
-
Config.application_environment
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.application_root
|
29
|
-
Config.application_root
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.get_hostname
|
33
|
-
require 'socket' unless defined?(Socket)
|
34
|
-
Socket.gethostname
|
35
|
-
rescue
|
36
|
-
'UNKNOWN'
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.language_version_string
|
40
|
-
"#{RUBY_VERSION rescue '?.?.?'} p#{RUBY_PATCHLEVEL rescue '???'} #{RUBY_RELEASE_DATE rescue '????-??-??'} #{RUBY_PLATFORM rescue '????'}"
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.get_username
|
44
|
-
ENV['LOGNAME'] || ENV['USER'] || ENV['USERNAME'] || ENV['APACHE_RUN_USER'] || 'UNKNOWN'
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.libraries_loaded
|
48
|
-
begin
|
49
|
-
return Hash[*Gem.loaded_specs.map{|name, gem_specification| [name, gem_specification.version.to_s]}.flatten]
|
50
|
-
rescue
|
51
|
-
end
|
52
|
-
{}
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
|
-
module Appygram
|
4
|
-
class Config
|
5
|
-
class ConfigurationException < StandardError; end
|
6
|
-
|
7
|
-
class << self
|
8
|
-
DEFAULTS = {
|
9
|
-
:ssl => false,
|
10
|
-
:remote_host_http => 'api.appygram.com',
|
11
|
-
:http_open_timeout => 2,
|
12
|
-
:http_read_timeout => 4,
|
13
|
-
:disabled_by_default => %w(development test)
|
14
|
-
}
|
15
|
-
|
16
|
-
attr_accessor :api_key, :enabled
|
17
|
-
attr_accessor :http_proxy_host, :http_proxy_port, :http_proxy_username, :http_proxy_password
|
18
|
-
attr_writer :ssl
|
19
|
-
|
20
|
-
def api_key
|
21
|
-
return @api_key unless @api_key.nil?
|
22
|
-
@api_key ||= ENV['EXCEPTIONAL_API_KEY'] unless ENV['EXCEPTIONAL_API_KEY'].nil?
|
23
|
-
end
|
24
|
-
|
25
|
-
def application_environment
|
26
|
-
ENV['RACK_ENV'] || ENV['RAILS_ENV']|| 'development'
|
27
|
-
end
|
28
|
-
|
29
|
-
def should_send_to_api?
|
30
|
-
return @enabled unless @enabled.nil?
|
31
|
-
@enabled = !(DEFAULTS[:disabled_by_default].include?(application_environment))
|
32
|
-
end
|
33
|
-
|
34
|
-
def application_root
|
35
|
-
(defined?(Rails) && Rails.respond_to?(:root)) ? Rails.root : Dir.pwd
|
36
|
-
end
|
37
|
-
|
38
|
-
def ssl?
|
39
|
-
@ssl ||= DEFAULTS[:ssl]
|
40
|
-
end
|
41
|
-
|
42
|
-
def remote_host
|
43
|
-
@remote_host ||= DEFAULTS[:remote_host_http]
|
44
|
-
end
|
45
|
-
|
46
|
-
def remote_port
|
47
|
-
@remote_port ||= ssl? ? 443 : 80
|
48
|
-
end
|
49
|
-
|
50
|
-
def reset
|
51
|
-
@enabled = @ssl = @remote_host = @remote_port = @api_key = nil
|
52
|
-
end
|
53
|
-
|
54
|
-
def http_open_timeout
|
55
|
-
@http_open_timeout ||= DEFAULTS[:http_open_timeout]
|
56
|
-
end
|
57
|
-
|
58
|
-
def http_read_timeout
|
59
|
-
@http_read_timeout ||= DEFAULTS[:http_read_timeout]
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
require 'digest/md5'
|
2
|
-
|
3
|
-
module Appygram
|
4
|
-
class ControllerExceptionData < ExceptionData
|
5
|
-
def initialize(exception, controller=nil, request=nil)
|
6
|
-
super(exception)
|
7
|
-
@request = request
|
8
|
-
@controller = controller
|
9
|
-
end
|
10
|
-
|
11
|
-
def framework
|
12
|
-
"rails"
|
13
|
-
end
|
14
|
-
|
15
|
-
def extra_stuff
|
16
|
-
return {} if @request.nil?
|
17
|
-
e = {
|
18
|
-
'request' => {
|
19
|
-
'url' => (@request.respond_to?(:url) ? @request.url : "#{@request.protocol}#{@request.host}#{@request.request_uri}"),
|
20
|
-
'controller' => @controller.class.to_s,
|
21
|
-
'action' => (@request.respond_to?(:parameters) ? @request.parameters['action'] : @request.params['action']),
|
22
|
-
'parameters' => filter_parameters(@request.respond_to?(:parameters) ? @request.parameters : @request.params),
|
23
|
-
'request_method' => @request.request_method.to_s,
|
24
|
-
'remote_ip' => (@request.respond_to?(:remote_ip) ? @request.remote_ip : @request.ip),
|
25
|
-
'headers' => extract_http_headers(@request.env),
|
26
|
-
'session' => self.class.sanitize_session(@request)
|
27
|
-
}
|
28
|
-
}
|
29
|
-
if @controller.respond_to?(:current_user)
|
30
|
-
cu = @controller.current_user
|
31
|
-
if cu and cu.email
|
32
|
-
e['request']['current_user'] = {
|
33
|
-
'id' => cu.id,
|
34
|
-
'email'=> cu.email
|
35
|
-
}
|
36
|
-
end
|
37
|
-
end
|
38
|
-
return e
|
39
|
-
end
|
40
|
-
|
41
|
-
def filter_hash(keys_to_filter, hash)
|
42
|
-
keys_to_filter.map! {|x| x.to_s}
|
43
|
-
if keys_to_filter.is_a?(Array) && !keys_to_filter.empty?
|
44
|
-
hash.each do |key, value|
|
45
|
-
if key_match?(key, keys_to_filter)
|
46
|
-
hash[key] = "[FILTERED]"
|
47
|
-
elsif value.respond_to?(:to_hash)
|
48
|
-
filter_hash(keys_to_filter, hash[key])
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
hash
|
53
|
-
end
|
54
|
-
|
55
|
-
# Closer alignment to latest filtered_params:
|
56
|
-
# https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/parameter_filter.rb
|
57
|
-
# https://github.com/exceptional/exceptional/issues/20
|
58
|
-
def key_match?(key, keys_to_filter)
|
59
|
-
keys_to_filter.any? { |k|
|
60
|
-
regexp = k.is_a?(Regexp)? k : Regexp.new(k, true)
|
61
|
-
key =~ regexp
|
62
|
-
}
|
63
|
-
end
|
64
|
-
|
65
|
-
def filter_parameters(hash)
|
66
|
-
if @request.respond_to?(:env) && @request.env["action_dispatch.parameter_filter"]
|
67
|
-
filter_hash(@request.env["action_dispatch.parameter_filter"], hash)
|
68
|
-
elsif @controller.respond_to?(:filter_parameters)
|
69
|
-
@controller.send(:filter_parameters, hash)
|
70
|
-
else
|
71
|
-
hash
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
@@ -1,108 +0,0 @@
|
|
1
|
-
require 'digest/md5'
|
2
|
-
require 'time'
|
3
|
-
|
4
|
-
module Appygram
|
5
|
-
class ExceptionData
|
6
|
-
|
7
|
-
def initialize(exception, name=nil)
|
8
|
-
@exception = exception
|
9
|
-
@name = name
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_hash
|
13
|
-
hash = ::Appygram::ApplicationEnvironment.to_hash(framework)
|
14
|
-
hash.merge!({
|
15
|
-
'exception' => {
|
16
|
-
'exception_class' => @exception.class.to_s,
|
17
|
-
'message' => @exception.message,
|
18
|
-
'backtrace' => @exception.backtrace,
|
19
|
-
'occurred_at' => Time.now.utc.iso8601
|
20
|
-
}
|
21
|
-
})
|
22
|
-
hash.merge!(extra_stuff)
|
23
|
-
hash.merge!(context_stuff)
|
24
|
-
self.class.sanitize_hash(hash)
|
25
|
-
end
|
26
|
-
|
27
|
-
def extra_stuff
|
28
|
-
{ 'rescue_block' => { 'name' => @name} }
|
29
|
-
end
|
30
|
-
|
31
|
-
def context_stuff
|
32
|
-
context = Thread.current[:appygram_context]
|
33
|
-
(context.nil? || context.empty?) ? {} : {'context' => context}
|
34
|
-
end
|
35
|
-
|
36
|
-
def to_json
|
37
|
-
begin
|
38
|
-
to_hash.to_json
|
39
|
-
rescue NoMethodError
|
40
|
-
begin
|
41
|
-
require 'json'
|
42
|
-
return to_hash.to_json
|
43
|
-
rescue StandardError => e
|
44
|
-
Appygram.logger.error(e.message)
|
45
|
-
Appygram.logger.error(e.backtrace)
|
46
|
-
raise StandardError.new("You need a json gem/library installed to send errors to Appygram (Object.to_json not defined). \nInstall json_pure, yajl-ruby, json-jruby, or the c-based json gem")
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def framework
|
52
|
-
nil
|
53
|
-
end
|
54
|
-
|
55
|
-
def uniqueness_hash
|
56
|
-
return nil if (@exception.backtrace.nil? || @exception.backtrace.empty?)
|
57
|
-
Digest::MD5.hexdigest(@exception.backtrace.join)
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.sanitize_hash(hash)
|
61
|
-
|
62
|
-
case hash
|
63
|
-
when Hash
|
64
|
-
hash.inject({}) do |result, (key, value)|
|
65
|
-
result.update(key => sanitize_hash(value))
|
66
|
-
end
|
67
|
-
when Array
|
68
|
-
hash.collect{|value| sanitize_hash(value)}
|
69
|
-
when Fixnum, String, Bignum
|
70
|
-
hash
|
71
|
-
else
|
72
|
-
hash.to_s
|
73
|
-
end
|
74
|
-
rescue Exception => e
|
75
|
-
Appygram.logger.error(hash)
|
76
|
-
Appygram.logger.error(e.message)
|
77
|
-
Appygram.logger.error(e.backtrace)
|
78
|
-
{}
|
79
|
-
end
|
80
|
-
|
81
|
-
def extract_http_headers(env)
|
82
|
-
headers = {}
|
83
|
-
env.select{|k, v| k =~ /^HTTP_/}.each do |name, value|
|
84
|
-
proper_name = name.sub(/^HTTP_/, '').split('_').map{|upper_case| upper_case.capitalize}.join('-')
|
85
|
-
headers[proper_name] = value
|
86
|
-
end
|
87
|
-
unless headers['Cookie'].nil?
|
88
|
-
headers['Cookie'] = headers['Cookie'].sub(/_session=\S+/, '_session=[FILTERED]')
|
89
|
-
end
|
90
|
-
headers
|
91
|
-
end
|
92
|
-
|
93
|
-
def self.sanitize_session(request)
|
94
|
-
session_hash = {'session_id' => "", 'data' => {}}
|
95
|
-
|
96
|
-
if request.respond_to?(:session)
|
97
|
-
session = request.session
|
98
|
-
session_hash['session_id'] = request.session_options ? request.session_options[:id] : nil
|
99
|
-
session_hash['session_id'] ||= session.respond_to?(:session_id) ? session.session_id : session.instance_variable_get("@session_id")
|
100
|
-
session_hash['data'] = session.respond_to?(:to_hash) ? session.to_hash : session.instance_variable_get("@data") || {}
|
101
|
-
session_hash['session_id'] ||= session_hash['data'][:session_id]
|
102
|
-
session_hash['data'].delete(:session_id)
|
103
|
-
end
|
104
|
-
|
105
|
-
self.sanitize_hash(session_hash)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module Appygram
|
2
|
-
module DebugExceptions
|
3
|
-
|
4
|
-
def self.included(base)
|
5
|
-
base.send(:alias_method_chain,:render_exception,:appygram)
|
6
|
-
end
|
7
|
-
|
8
|
-
def render_exception_with_appygram(env,exception)
|
9
|
-
::Appygram::Catcher.handle_with_controller(exception,
|
10
|
-
env['action_controller.instance'],
|
11
|
-
Rack::Request.new(env))
|
12
|
-
render_exception_without_appygram(env,exception)
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'rack'
|
3
|
-
|
4
|
-
module Rack
|
5
|
-
class Appygram
|
6
|
-
|
7
|
-
def initialize(app, api_key = nil)
|
8
|
-
@app = app
|
9
|
-
if api_key.nil?
|
10
|
-
appygram_config = "config/appygram.yml"
|
11
|
-
::Appygram::Config.load(appygram_config)
|
12
|
-
else
|
13
|
-
::Appygram.configure(api_key)
|
14
|
-
::Appygram::Config.enabled = true
|
15
|
-
::Appygram.logger.info "Enabling Appygram for Rack"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def call(env)
|
20
|
-
begin
|
21
|
-
status, headers, body = @app.call(env)
|
22
|
-
rescue Exception => e
|
23
|
-
::Appygram::Catcher.handle_with_rack(e,env, Rack::Request.new(env))
|
24
|
-
raise(e)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'logger'
|
2
|
-
|
3
|
-
module Appygram
|
4
|
-
class LogFactory
|
5
|
-
def self.logger
|
6
|
-
@logger ||= create_logger_with_fallback
|
7
|
-
end
|
8
|
-
|
9
|
-
private
|
10
|
-
def self.create_logger_with_fallback
|
11
|
-
begin
|
12
|
-
log_dir = File.join(Config.application_root, 'log')
|
13
|
-
Dir.mkdir(log_dir) unless File.directory?(log_dir)
|
14
|
-
log_path = File.join(log_dir, "/appygram.log")
|
15
|
-
log = Logger.new(log_path)
|
16
|
-
log.level = Logger::INFO
|
17
|
-
def log.format_message(severity, timestamp, progname, msg)
|
18
|
-
"[#{severity.upcase}] (#{[Kernel.caller[2].split('/').last]}) #{timestamp.utc.to_s} - #{msg2str(msg).gsub(/\n/, '').lstrip}\n"
|
19
|
-
end
|
20
|
-
def log.msg2str(msg)
|
21
|
-
case msg
|
22
|
-
when ::String
|
23
|
-
msg
|
24
|
-
when ::Exception
|
25
|
-
"#{ msg.message } (#{ msg.class }): " <<
|
26
|
-
(msg.backtrace || []).join(" | ")
|
27
|
-
else
|
28
|
-
msg.inspect
|
29
|
-
end
|
30
|
-
end
|
31
|
-
log
|
32
|
-
rescue
|
33
|
-
return Rails.logger if defined?(Rails) && defined?(Rails.logger)
|
34
|
-
return RAILS_DEFAULT_LOGGER if defined?(RAILS_DEFAULT_LOGGER)
|
35
|
-
return Logger.new(STDERR)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'digest/md5'
|
2
|
-
|
3
|
-
module Appygram
|
4
|
-
class RackExceptionData < ExceptionData
|
5
|
-
def initialize(exception, environment, request)
|
6
|
-
super(exception)
|
7
|
-
@environment = environment
|
8
|
-
@request = request
|
9
|
-
end
|
10
|
-
|
11
|
-
def framework
|
12
|
-
"rack"
|
13
|
-
end
|
14
|
-
|
15
|
-
def extra_stuff
|
16
|
-
return {} if @request.nil?
|
17
|
-
{
|
18
|
-
'request' => {
|
19
|
-
'url' => "#{@request.url}",
|
20
|
-
'parameters' => @request.params,
|
21
|
-
'request_method' => @request.request_method.to_s,
|
22
|
-
'remote_ip' => @request.ip,
|
23
|
-
'headers' => extract_http_headers(@environment),
|
24
|
-
'session' => self.class.sanitize_session(@request)
|
25
|
-
}
|
26
|
-
}
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'zlib'
|
2
|
-
require 'cgi'
|
3
|
-
require 'net/http'
|
4
|
-
require 'net/https'
|
5
|
-
require 'digest/md5'
|
6
|
-
|
7
|
-
module Appygram
|
8
|
-
class Remote
|
9
|
-
class << self
|
10
|
-
def startup_announce(startup_data)
|
11
|
-
#FIXME this is a noop based on an Exceptional behavior Appygram doesn't have
|
12
|
-
Appygram.logger.info 'Appygram remote exception forwarding started'
|
13
|
-
end
|
14
|
-
|
15
|
-
def error(exception_data)
|
16
|
-
url = "/api/exceptions?api_key=#{::Appygram::Config.api_key}"
|
17
|
-
if Appygram.restrict_duplicates exception_data.uniqueness_hash
|
18
|
-
Appygram.logger.debug "Duplicate notification suppressed."
|
19
|
-
else
|
20
|
-
call_remote(url, exception_data.to_json)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def call_remote(url, data)
|
25
|
-
config = Appygram::Config
|
26
|
-
optional_proxy = Net::HTTP::Proxy(config.http_proxy_host,
|
27
|
-
config.http_proxy_port,
|
28
|
-
config.http_proxy_username,
|
29
|
-
config.http_proxy_password)
|
30
|
-
client = optional_proxy.new(config.remote_host, config.remote_port)
|
31
|
-
client.open_timeout = config.http_open_timeout
|
32
|
-
client.read_timeout = config.http_read_timeout
|
33
|
-
client.use_ssl = config.ssl?
|
34
|
-
client.verify_mode = OpenSSL::SSL::VERIFY_NONE if config.ssl?
|
35
|
-
begin
|
36
|
-
response = client.post(url, data)
|
37
|
-
case response
|
38
|
-
when Net::HTTPSuccess
|
39
|
-
Appygram.logger.info( "#{url} - #{response.message}")
|
40
|
-
return true
|
41
|
-
else
|
42
|
-
Appygram.logger.error("#{url} - #{response.code} - #{response.message}")
|
43
|
-
end
|
44
|
-
rescue Exception => e
|
45
|
-
Appygram.logger.error('Problem notifying Appygram about the error')
|
46
|
-
Appygram.logger.error(e)
|
47
|
-
end
|
48
|
-
nil
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
module Appygram
|
2
|
-
class StartupException < StandardError;
|
3
|
-
end
|
4
|
-
class Startup
|
5
|
-
class << self
|
6
|
-
def announce
|
7
|
-
if Config.api_key.blank?
|
8
|
-
raise StartupException, 'API Key must be configured'
|
9
|
-
end
|
10
|
-
Remote.startup_announce(::Appygram::ApplicationEnvironment.to_hash('rails'))
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|