appygram-rails 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
data/appygram.gemspec ADDED
@@ -0,0 +1,16 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/appygram/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = %q{appygram-rails}
6
+ gem.version = Appygram::VERSION
7
+ gem.authors = ["rfc2616"]
8
+ gem.summary = %q{ appygram is a hosted service for sending messages from mobile/web apps }
9
+ gem.description = %q{Appygram is the Ruby gem for communicating with http://appygram.com (hosted messaging service). It supports an exception reporting mechanism similar to http://exceptional.io, and this Ruby gem, forked from the Exceptional gem, emulates Exceptional functionality.}
10
+ gem.email = %q{heittman.rob@gmail.com}
11
+ gem.files = Dir['lib/**/*'] + Dir['spec/**/*'] + Dir['spec/**/*'] + Dir['rails/**/*'] + Dir['tasks/**/*'] + Dir['*.rb'] + ["appygram.gemspec"]
12
+ gem.homepage = %q{http://appygram.com/}
13
+ gem.require_paths = ["lib"]
14
+ gem.requirements << "json_pure, json-jruby or json gem required"
15
+ gem.add_dependency 'rack'
16
+ end
data/init.rb ADDED
@@ -0,0 +1,39 @@
1
+ require 'appygram'
2
+
3
+ # If old plugin still installed then we don't want to install this one.
4
+ # In production environments we should continue to work as before, but in development/test we should
5
+ # advise how to correct the problem and exit
6
+ if (defined?(Appygram::VERSION::STRING) rescue nil) && %w(development test).include?(RAILS_ENV)
7
+ message = %Q(
8
+ ***********************************************************************
9
+ You seem to still have an old version of the Appygram plugin installed.
10
+ Remove it from /vendor/plugins and try again.
11
+ ***********************************************************************
12
+ )
13
+ puts message
14
+ exit -1
15
+ else
16
+ begin
17
+
18
+ if (Rails::VERSION::MAJOR < 3)
19
+ Appygram::Config.load(File.join(RAILS_ROOT, "/config/Appygram.yml"))
20
+ if Appygram::Config.should_send_to_api?
21
+ Appygram.logger.info("Loading Appygram #{Appygram::VERSION} for #{Rails::VERSION::STRING}")
22
+ require File.join('Appygram', 'integration', 'rails')
23
+ require File.join('Appygram', 'integration', 'dj') if defined?(Delayed::Job)
24
+ end
25
+ else
26
+ Appygram::Config.load(File.join(Rails.root, "/config/Appygram.yml"))
27
+
28
+ if Appygram::Config.should_send_to_api?
29
+ Appygram.logger.info("Loading Appygram #{Appygram::VERSION} for #{Rails::VERSION::STRING}")
30
+ Rails.configuration.middleware.use "Rack::RailsAppygram"
31
+ require File.join('Appygram', 'integration', 'dj') if defined?(Delayed::Job)
32
+ end
33
+ end
34
+ rescue => e
35
+ STDERR.puts "Problem starting Appygram Plugin. Your app will run as normal. #{e.message}"
36
+ Appygram.logger.error(e.message)
37
+ Appygram.logger.error(e.backtrace)
38
+ end
39
+ end
@@ -0,0 +1,15 @@
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
@@ -0,0 +1,55 @@
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
@@ -0,0 +1,34 @@
1
+ module Appygram
2
+ class Catcher
3
+ class << self
4
+ def handle_with_controller(exception, controller=nil, request=nil)
5
+ if Config.should_send_to_api?
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
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,63 @@
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
@@ -0,0 +1,75 @@
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
@@ -0,0 +1,108 @@
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
@@ -0,0 +1,11 @@
1
+ module Appygram
2
+ class Alert <StandardError;
3
+ end
4
+
5
+ module Integration
6
+ def self.alert(msg, env={})
7
+ return Appygram::Remote.error(Appygram::AlertData.new(Alert.new(msg), "Alert"))
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,16 @@
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
@@ -0,0 +1,28 @@
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
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require 'rack'
3
+
4
+ module Rack
5
+ class RailsAppygram
6
+
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ begin
13
+ body = @app.call(env)
14
+ rescue Exception => e
15
+ ::Appygram::Catcher.handle_with_controller(e,env['action_controller.instance'], Rack::Request.new(env))
16
+ raise
17
+ end
18
+
19
+ if env['rack.exception']
20
+ ::Appygram::Catcher.handle_with_controller(env['rack.exception'],env['action_controller.instance'], Rack::Request.new(env))
21
+ end
22
+
23
+ body
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,39 @@
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
@@ -0,0 +1,10 @@
1
+ class Regexp
2
+ def to_json(options = {})
3
+ "\"#{self.to_s}\""
4
+ end
5
+ end
6
+ class Fixnum
7
+ def to_json(options = {})
8
+ to_s
9
+ end
10
+ end
@@ -0,0 +1,29 @@
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
@@ -0,0 +1,20 @@
1
+ require 'appygram'
2
+ require 'rails'
3
+
4
+ module Appygram
5
+ class Railtie < Rails::Railtie
6
+
7
+ initializer "appygram.middleware" do |app|
8
+
9
+ if Appygram::Config.should_send_to_api?
10
+ Appygram.logger.info("Loading Appygram #{Appygram::VERSION} for #{Rails::VERSION::STRING}")
11
+ if defined?(ActionDispatch::DebugExceptions)
12
+ ActionDispatch::DebugExceptions.send(:include,Appygram::DebugExceptions)
13
+ else
14
+ app.config.middleware.use "Rack::RailsAppygram"
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,48 @@
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
+ call_remote(url, exception_data.to_json)
18
+ end
19
+
20
+ def call_remote(url, data)
21
+ config = Appygram::Config
22
+ optional_proxy = Net::HTTP::Proxy(config.http_proxy_host,
23
+ config.http_proxy_port,
24
+ config.http_proxy_username,
25
+ config.http_proxy_password)
26
+ client = optional_proxy.new(config.remote_host, config.remote_port)
27
+ client.open_timeout = config.http_open_timeout
28
+ client.read_timeout = config.http_read_timeout
29
+ client.use_ssl = config.ssl?
30
+ client.verify_mode = OpenSSL::SSL::VERIFY_NONE if config.ssl?
31
+ begin
32
+ response = client.post(url, data)
33
+ case response
34
+ when Net::HTTPSuccess
35
+ Appygram.logger.info( "#{url} - #{response.message}")
36
+ return true
37
+ else
38
+ Appygram.logger.error("#{url} - #{response.code} - #{response.message}")
39
+ end
40
+ rescue Exception => e
41
+ Appygram.logger.error('Problem notifying Appygram about the error')
42
+ Appygram.logger.error(e)
43
+ end
44
+ nil
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,14 @@
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
@@ -0,0 +1,3 @@
1
+ module Appygram
2
+ VERSION = '0.9.1'
3
+ end
data/lib/appygram.rb ADDED
@@ -0,0 +1,71 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'appygram/monkeypatches'
4
+ require 'appygram/catcher'
5
+ require 'appygram/startup'
6
+ require 'appygram/log_factory'
7
+ require 'appygram/config'
8
+ require 'appygram/application_environment'
9
+ require 'appygram/exception_data'
10
+ require 'appygram/controller_exception_data'
11
+ require 'appygram/rack_exception_data'
12
+ require 'appygram/alert_data'
13
+ require 'appygram/remote'
14
+ require 'appygram/integration/rack'
15
+ require 'appygram/integration/rack_rails'
16
+ require 'appygram/integration/alerter'
17
+ require 'appygram/version'
18
+ require 'appygram/integration/debug_exceptions'
19
+
20
+ require 'appygram/railtie' if defined?(Rails::Railtie)
21
+
22
+ module Appygram
23
+ PROTOCOL_VERSION = 5
24
+ CLIENT_NAME = 'appygram-rails'
25
+ ENVIRONMENT_FILTER = []
26
+
27
+ def self.logger
28
+ ::Appygram::LogFactory.logger
29
+ end
30
+
31
+ def self.configure(api_key)
32
+ Appygram::Config.api_key = api_key
33
+ end
34
+
35
+ def self.handle(exception, name=nil)
36
+ Appygram::Catcher.handle(exception, name)
37
+ end
38
+
39
+ def self.rescue(name=nil, context=nil, &block)
40
+ begin
41
+ self.context(context) unless context.nil?
42
+ block.call
43
+ rescue Exception => e
44
+ Appygram::Catcher.handle(e,name)
45
+ ensure
46
+ self.clear!
47
+ end
48
+ end
49
+
50
+ def self.rescue_and_reraise(name=nil, context=nil, &block)
51
+ begin
52
+ self.context(context) unless context.nil?
53
+ block.call
54
+ rescue Exception => e
55
+ Appygram::Catcher.handle(e,name)
56
+ raise(e)
57
+ ensure
58
+ self.clear!
59
+ end
60
+ end
61
+
62
+ def self.clear!
63
+ Thread.current[:appygram_context] = nil
64
+ end
65
+
66
+ def self.context(hash = {})
67
+ Thread.current[:appygram_context] ||= {}
68
+ Thread.current[:appygram_context].merge!(hash)
69
+ self
70
+ end
71
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__) , '../init.rb')
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: appygram-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - rfc2616
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: &70216562368600 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70216562368600
25
+ description: Appygram is the Ruby gem for communicating with http://appygram.com (hosted
26
+ messaging service). It supports an exception reporting mechanism similar to http://exceptional.io,
27
+ and this Ruby gem, forked from the Exceptional gem, emulates Exceptional functionality.
28
+ email: heittman.rob@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/appygram/alert_data.rb
34
+ - lib/appygram/application_environment.rb
35
+ - lib/appygram/catcher.rb
36
+ - lib/appygram/config.rb
37
+ - lib/appygram/controller_exception_data.rb
38
+ - lib/appygram/exception_data.rb
39
+ - lib/appygram/integration/alerter.rb
40
+ - lib/appygram/integration/debug_exceptions.rb
41
+ - lib/appygram/integration/rack.rb
42
+ - lib/appygram/integration/rack_rails.rb
43
+ - lib/appygram/log_factory.rb
44
+ - lib/appygram/monkeypatches.rb
45
+ - lib/appygram/rack_exception_data.rb
46
+ - lib/appygram/railtie.rb
47
+ - lib/appygram/remote.rb
48
+ - lib/appygram/startup.rb
49
+ - lib/appygram/version.rb
50
+ - lib/appygram.rb
51
+ - rails/init.rb
52
+ - init.rb
53
+ - appygram.gemspec
54
+ homepage: http://appygram.com/
55
+ licenses: []
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements:
73
+ - json_pure, json-jruby or json gem required
74
+ rubyforge_project:
75
+ rubygems_version: 1.8.17
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: appygram is a hosted service for sending messages from mobile/web apps
79
+ test_files: []
80
+ has_rdoc: