appygram 0.1.4 → 1.0.0

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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in appygram.gemspec
4
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,55 @@
1
+ # Appygram <http://www.appygram.com>
2
+
3
+ Appygram is a simple service to handle messages from your web
4
+ or mobile app. This gem provides communication with the Appygram
5
+ service via a simple API. Useful features higher in the stack
6
+ are found in gems that depend on this one, e.g. appygram-rails,
7
+ which turns uncaught Rails exceptions into appygrams.
8
+
9
+ ## Installation
10
+
11
+ 1. Add gem entry to Gemfile
12
+
13
+ ```ruby
14
+ gem 'appygram'
15
+ ```
16
+
17
+ 2. Run <code>bundle install</code>
18
+
19
+ 3. Configure your API Key in an initializer, e.g. config/appygram.rb
20
+
21
+ ```ruby
22
+ Appygram.configure :api_key => 'your_api_key'
23
+ ```
24
+
25
+ using a valid API key for your app provided by Appygram
26
+
27
+ ## Invocation
28
+
29
+ ```ruby
30
+ require 'appygram'
31
+
32
+ Appygram.send :topic => 'Test', :message => 'This is a test.'
33
+ ```
34
+
35
+ ## Supported fields in an appygram
36
+
37
+ * topic
38
+ * subject
39
+ * message
40
+ * name
41
+ * email
42
+ * phone
43
+ * platform ('web' by default for this connector)
44
+ * software ('appygram.rb [VERSION]' by default for this connector)
45
+
46
+ ## Rules for improvement
47
+
48
+ * This gem must not have other dependencies.
49
+ * This gem may take advantage of other gems (e.g. async i/o,
50
+ background queueing, http pooling) if detected, and the advantage
51
+ is related directly to communication with the service
52
+ * Effort should be made to retain parity with other fully supported
53
+ connectors
54
+
55
+ Copyright © 2012 Solertium
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/appygram.gemspec CHANGED
@@ -1,16 +1,24 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/appygram/version', __FILE__)
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "appygram/version"
3
4
 
4
- Gem::Specification.new do |gem|
5
- gem.name = %q{appygram}
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'
5
+ Gem::Specification.new do |s|
6
+ s.name = "appygram"
7
+ s.version = Appygram::VERSION
8
+ s.authors = ["rfc2616"]
9
+ s.email = ["heittman.rob@gmail.com"]
10
+ s.homepage = "https://github.com/anythinglabs/appygram.rb"
11
+ s.summary = %q{Communicate with the Appygram message routing service}
12
+ s.description = %q{Discovers topics and sends messages}
13
+
14
+ s.rubyforge_project = "appygram"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ # s.add_runtime_dependency "rest-client"
16
24
  end
@@ -1,3 +1,3 @@
1
1
  module Appygram
2
- VERSION = '0.1.4'
2
+ VERSION = "1.0.0"
3
3
  end
data/lib/appygram.rb CHANGED
@@ -1,71 +1,47 @@
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)
1
+ require "appygram/version"
2
+ require 'net/http'
3
+ require 'net/https'
21
4
 
22
5
  module Appygram
23
- PROTOCOL_VERSION = 5
24
- CLIENT_NAME = 'getappygram-gem'
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
6
+ def self.configure(params)
7
+ Appygram::Config.api_key = params[:api_key]
8
+ endpoint = params[:endpoint] || 'https://appygram.herokuapp.com/appygrams'
9
+ Appygram::Config.endpoint = URI endpoint
10
+ Appygram::Config.platform = params[:platform] || 'web'
11
+ Appygram::Config.software = params[:software] || "appygram.rb #{Appygram::VERSION}"
33
12
  end
34
13
 
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
14
+ def self.send(params)
15
+ pc = params.clone
16
+ pc[:api_key] = Appygram::Config.api_key
17
+ pc[:platform] = Appygram::Config.platform unless pc[:platform]
18
+ pc[:software] = Appygram::Config.software unless pc[:software]
19
+ url = Appygram::Config.endpoint
20
+ req = Net::HTTP::Post.new url.request_uri
21
+ req.form_data = pc
22
+ session = Net::HTTP.new(url.hostname, url.port)
23
+ session.use_ssl = true
24
+ session.start {|http|
25
+ http.request(req)
26
+ }
48
27
  end
49
28
 
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!
29
+ class Config
30
+ class << self
31
+ attr_accessor :api_key, :endpoint, :software, :platform
32
+ def api_key
33
+ return @api_key unless @api_key.nil?
34
+ end
35
+ def endpoint
36
+ return @endpoint unless @endpoint.nil?
37
+ end
38
+ def software
39
+ return @software unless @software.nil?
40
+ end
41
+ def platform
42
+ return @platform unless @platform.nil?
43
+ end
59
44
  end
60
45
  end
61
46
 
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
47
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appygram
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,52 +9,23 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-27 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: rack
16
- requirement: &70149039687960 !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: *70149039687960
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
12
+ date: 2012-09-13 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Discovers topics and sends messages
15
+ email:
16
+ - heittman.rob@gmail.com
29
17
  executables: []
30
18
  extensions: []
31
19
  extra_rdoc_files: []
32
20
  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/dj.rb
42
- - lib/appygram/integration/rack.rb
43
- - lib/appygram/integration/rack_rails.rb
44
- - lib/appygram/integration/rails.rb
45
- - lib/appygram/integration/sinatra.rb
46
- - lib/appygram/log_factory.rb
47
- - lib/appygram/monkeypatches.rb
48
- - lib/appygram/rack_exception_data.rb
49
- - lib/appygram/railtie.rb
50
- - lib/appygram/remote.rb
51
- - lib/appygram/startup.rb
52
- - lib/appygram/version.rb
53
- - lib/appygram.rb
54
- - rails/init.rb
55
- - init.rb
21
+ - .gitignore
22
+ - Gemfile
23
+ - README.markdown
24
+ - Rakefile
56
25
  - appygram.gemspec
57
- homepage: http://appygram.com/
26
+ - lib/appygram.rb
27
+ - lib/appygram/version.rb
28
+ homepage: https://github.com/anythinglabs/appygram.rb
58
29
  licenses: []
59
30
  post_install_message:
60
31
  rdoc_options: []
@@ -72,12 +43,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
43
  - - ! '>='
73
44
  - !ruby/object:Gem::Version
74
45
  version: '0'
75
- requirements:
76
- - json_pure, json-jruby or json gem required
77
- rubyforge_project:
78
- rubygems_version: 1.8.17
46
+ requirements: []
47
+ rubyforge_project: appygram
48
+ rubygems_version: 1.8.15
79
49
  signing_key:
80
50
  specification_version: 3
81
- summary: appygram is a hosted service for sending messages from mobile/web apps
51
+ summary: Communicate with the Appygram message routing service
82
52
  test_files: []
83
- has_rdoc:
data/init.rb DELETED
@@ -1,39 +0,0 @@
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
@@ -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,34 +0,0 @@
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
@@ -1,87 +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 load(config_file=nil)
21
- if (config_file && File.file?(config_file))
22
- begin
23
- config = YAML::load_file(config_file)
24
- env_config = config[application_environment] || {}
25
- @api_key = config['api-key'] || env_config['api-key']
26
-
27
- @http_proxy_host = config['http-proxy-host']
28
- @http_proxy_port = config['http-proxy-port']
29
- @http_proxy_username = config['http-proxy-username']
30
- @http_proxy_password = config['http-proxy-password']
31
- @http_open_timeout = config['http-open-timeout']
32
- @http_read_timeout = config['http-read-timeout']
33
-
34
- @ssl = config['ssl'] || env_config['ssl']
35
- @enabled = env_config['enabled']
36
- @remote_port = config['remote-port'].to_i unless config['remote-port'].nil?
37
- @remote_host = config['remote-host'] unless config['remote-host'].nil?
38
- rescue Exception => e
39
- raise ConfigurationException.new("Unable to load configuration #{config_file} for environment #{application_environment} : #{e.message}")
40
- end
41
- end
42
- end
43
-
44
- def api_key
45
- return @api_key unless @api_key.nil?
46
- @api_key ||= ENV['EXCEPTIONAL_API_KEY'] unless ENV['EXCEPTIONAL_API_KEY'].nil?
47
- end
48
-
49
- def application_environment
50
- ENV['RACK_ENV'] || ENV['RAILS_ENV']|| 'development'
51
- end
52
-
53
- def should_send_to_api?
54
- return @enabled unless @enabled.nil?
55
- @enabled = !(DEFAULTS[:disabled_by_default].include?(application_environment))
56
- end
57
-
58
- def application_root
59
- (defined?(Rails) && Rails.respond_to?(:root)) ? Rails.root : Dir.pwd
60
- end
61
-
62
- def ssl?
63
- @ssl ||= DEFAULTS[:ssl]
64
- end
65
-
66
- def remote_host
67
- @remote_host ||= DEFAULTS[:remote_host_http]
68
- end
69
-
70
- def remote_port
71
- @remote_port ||= ssl? ? 443 : 80
72
- end
73
-
74
- def reset
75
- @enabled = @ssl = @remote_host = @remote_port = @api_key = nil
76
- end
77
-
78
- def http_open_timeout
79
- @http_open_timeout ||= DEFAULTS[:http_open_timeout]
80
- end
81
-
82
- def http_read_timeout
83
- @http_read_timeout ||= DEFAULTS[:http_read_timeout]
84
- end
85
- end
86
- end
87
- 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,11 +0,0 @@
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
-
@@ -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,15 +0,0 @@
1
- if Delayed::Worker.method_defined? :handle_failed_job
2
- class Delayed::Worker
3
- def handle_failed_job_with_appygram(job, e)
4
- Appygram.handle(e, "Delayed::Job #{job.name}")
5
- handle_failed_job_without_appygram(job, e)
6
- Appygram.context.clear!
7
- end
8
- alias_method_chain :handle_failed_job, :appygram
9
- Appygram.logger.info "DJ integration enabled"
10
- end
11
- else
12
- message = "\n\n\nThe Appygram gem does not support Delayed Job 1.8.4 or earlier.\n\n\n"
13
- STDERR.puts(message)
14
- Appygram.logger.error(message)
15
- 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,26 +0,0 @@
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
@@ -1,27 +0,0 @@
1
- # force Rails < 2.0 to use quote keys as per the JSON standard...
2
- if defined?(ActiveSupport) && defined?(ActiveSupport::JSON) && ActiveSupport::JSON.respond_to?(:unquote_hash_key_identifiers)
3
- ActiveSupport::JSON.unquote_hash_key_identifiers = false
4
- end
5
-
6
- if defined? ActionController
7
- module ActionController
8
- class Base
9
- def rescue_action_with_appygram(exception)
10
- unless exception_handled_by_rescue_from?(exception)
11
- Appygram::Catcher.handle_with_controller(exception, self, request)
12
- Appygram.context.clear!
13
- end
14
- rescue_action_without_appygram exception
15
- end
16
-
17
- alias_method :rescue_action_without_appygram, :rescue_action
18
- alias_method :rescue_action, :rescue_action_with_appygram
19
- protected :rescue_action
20
-
21
- private
22
- def exception_handled_by_rescue_from?(exception)
23
- respond_to?(:handler_for_rescue) && handler_for_rescue(exception)
24
- end
25
- end
26
- end
27
- end
@@ -1,6 +0,0 @@
1
- if defined? Sinatra::Request
2
- error do
3
- Appygram::Catcher.handle_with_rack(request.env['sinatra.error'], request.env, request)
4
- raise request.env['sinatra.error']
5
- end
6
- 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,10 +0,0 @@
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
@@ -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,23 +0,0 @@
1
- require 'appygram'
2
- require 'rails'
3
-
4
- module Appygram
5
- class Railtie < Rails::Railtie
6
-
7
- initializer "appygram.middleware" do |app|
8
-
9
- config_file = File.join(Rails.root, "/config/appygram.yml")
10
- Appygram::Config.load config_file if File.exist?(config_file)
11
- # On Heroku config is loaded via the ENV so no need to load it from the file
12
-
13
- if Appygram::Config.should_send_to_api?
14
- Appygram.logger.info("Loading Appygram #{Appygram::VERSION} for #{Rails::VERSION::STRING}")
15
- if defined?(ActionDispatch::DebugExceptions)
16
- ActionDispatch::DebugExceptions.send(:include,Appygram::DebugExceptions)
17
- else
18
- app.config.middleware.use "Rack::RailsAppygram"
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,48 +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
- 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
@@ -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 (/config/appygram.yml)'
9
- end
10
- Remote.startup_announce(::Appygram::ApplicationEnvironment.to_hash('rails'))
11
- end
12
- end
13
- end
14
- end
data/rails/init.rb DELETED
@@ -1 +0,0 @@
1
- require File.join(File.dirname(__FILE__) , '../init.rb')