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 +4 -0
- data/Gemfile +4 -0
- data/README.markdown +55 -0
- data/Rakefile +1 -0
- data/appygram.gemspec +21 -13
- data/lib/appygram/version.rb +1 -1
- data/lib/appygram.rb +37 -61
- metadata +17 -48
- data/init.rb +0 -39
- data/lib/appygram/alert_data.rb +0 -15
- data/lib/appygram/application_environment.rb +0 -55
- data/lib/appygram/catcher.rb +0 -34
- data/lib/appygram/config.rb +0 -87
- data/lib/appygram/controller_exception_data.rb +0 -75
- data/lib/appygram/exception_data.rb +0 -108
- data/lib/appygram/integration/alerter.rb +0 -11
- data/lib/appygram/integration/debug_exceptions.rb +0 -16
- data/lib/appygram/integration/dj.rb +0 -15
- data/lib/appygram/integration/rack.rb +0 -28
- data/lib/appygram/integration/rack_rails.rb +0 -26
- data/lib/appygram/integration/rails.rb +0 -27
- data/lib/appygram/integration/sinatra.rb +0 -6
- data/lib/appygram/log_factory.rb +0 -39
- data/lib/appygram/monkeypatches.rb +0 -10
- data/lib/appygram/rack_exception_data.rb +0 -29
- data/lib/appygram/railtie.rb +0 -23
- data/lib/appygram/remote.rb +0 -48
- data/lib/appygram/startup.rb +0 -14
- data/rails/init.rb +0 -1
data/.gitignore
ADDED
data/Gemfile
ADDED
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
|
-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "appygram/version"
|
3
4
|
|
4
|
-
Gem::Specification.new do |
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
data/lib/appygram/version.rb
CHANGED
data/lib/appygram.rb
CHANGED
@@ -1,71 +1,47 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require '
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
::Appygram::
|
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.
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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.
|
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-
|
13
|
-
dependencies:
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
-
|
34
|
-
-
|
35
|
-
-
|
36
|
-
-
|
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
|
-
|
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
|
-
|
77
|
-
|
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:
|
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
|
data/lib/appygram/alert_data.rb
DELETED
@@ -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
|
data/lib/appygram/catcher.rb
DELETED
@@ -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
|
data/lib/appygram/config.rb
DELETED
@@ -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,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
|
data/lib/appygram/log_factory.rb
DELETED
@@ -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
|
data/lib/appygram/railtie.rb
DELETED
@@ -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
|
data/lib/appygram/remote.rb
DELETED
@@ -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
|
data/lib/appygram/startup.rb
DELETED
@@ -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')
|