appygram 0.1.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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')