sfalma 0.7

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.
Files changed (50) hide show
  1. data/bin/sfalma +76 -0
  2. data/init.rb +27 -0
  3. data/install.rb +19 -0
  4. data/lib/sfalma/alert_data.rb +15 -0
  5. data/lib/sfalma/application_environment.rb +79 -0
  6. data/lib/sfalma/catcher.rb +26 -0
  7. data/lib/sfalma/config.rb +93 -0
  8. data/lib/sfalma/controller_exception_data.rb +69 -0
  9. data/lib/sfalma/exception_data.rb +146 -0
  10. data/lib/sfalma/integration/alerter.rb +11 -0
  11. data/lib/sfalma/integration/dj.rb +12 -0
  12. data/lib/sfalma/integration/rack.rb +28 -0
  13. data/lib/sfalma/integration/rack_rails.rb +26 -0
  14. data/lib/sfalma/integration/rails.rb +27 -0
  15. data/lib/sfalma/integration/sinatra.rb +6 -0
  16. data/lib/sfalma/integration/tester.rb +20 -0
  17. data/lib/sfalma/log_factory.rb +39 -0
  18. data/lib/sfalma/monkeypatches.rb +10 -0
  19. data/lib/sfalma/rack_exception_data.rb +29 -0
  20. data/lib/sfalma/railtie.rb +20 -0
  21. data/lib/sfalma/remote.rb +59 -0
  22. data/lib/sfalma/startup.rb +14 -0
  23. data/lib/sfalma/vcs.rb +45 -0
  24. data/lib/sfalma/version.rb +3 -0
  25. data/lib/sfalma.rb +71 -0
  26. data/lib/tasks/sfalma_tasks.rake +11 -0
  27. data/rails/init.rb +1 -0
  28. data/sfalma.gemspec +18 -0
  29. data/spec/bin/ginger +54 -0
  30. data/spec/dj_integration_spec.rb +29 -0
  31. data/spec/fixtures/favicon.png +0 -0
  32. data/spec/fixtures/sfalma.yml +10 -0
  33. data/spec/fixtures/sfalma_disabled.yml +4 -0
  34. data/spec/ginger_scenarios.rb +33 -0
  35. data/spec/rack_integration_spec.rb +21 -0
  36. data/spec/rails_integration_spec.rb +95 -0
  37. data/spec/rails_rack_integration_spec.rb +29 -0
  38. data/spec/sfalma/alert_exception_data_spec.rb +11 -0
  39. data/spec/sfalma/catcher_spec.rb +13 -0
  40. data/spec/sfalma/config_spec.rb +64 -0
  41. data/spec/sfalma/controller_exception_data_spec.rb +26 -0
  42. data/spec/sfalma/exception_data_spec.rb +198 -0
  43. data/spec/sfalma/monkeypatches_spec.rb +11 -0
  44. data/spec/sfalma/rack_exception_data_spec.rb +87 -0
  45. data/spec/sfalma/remote_spec.rb +31 -0
  46. data/spec/sfalma/startup_spec.rb +15 -0
  47. data/spec/sfalma_rescue_spec.rb +74 -0
  48. data/spec/spec_helper.rb +23 -0
  49. data/spec/standalone_spec.rb +9 -0
  50. metadata +111 -0
data/bin/sfalma ADDED
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ args = ARGV.dup
4
+ ARGV.clear
5
+ command = args.shift.strip rescue 'help'
6
+
7
+ case command
8
+ when 'help'
9
+ puts <<USAGE
10
+ help # Show this usage.
11
+ test # Send a test exception to Sfalma.
12
+ alert <message> # Send a message to Sfalma. Exits 0 for success, 1 for config error, and 2 for report failure
13
+ install <api_key> # Create config/sfalma.yml with your api_key. Overrites existing one.
14
+ install <api_key> <environment> # Create config/sfalma.yml with your api_key and enabled for a specific environment. Overrites existing config file.
15
+ install <api_key> <environment>,<environment> # Create config/sfalma.yml with your api_key enabled for multiple environments (comma seperated). Overrites existing config file.
16
+
17
+ USAGE
18
+ when 'test'
19
+ if defined?(RAILS_ROOT)
20
+ puts "Loading Rails environment."
21
+ require(File.join('config', 'boot'))
22
+ require(File.join(RAILS_ROOT, 'config', 'environment')) if defined?(RAILS_ROOT)
23
+ require "sfalma/integration/tester"
24
+ else
25
+ require 'json'
26
+ require 'sfalma'
27
+ require "sfalma/integration/tester"
28
+ Sfalma::Config.load('config/sfalma.yml')
29
+ end
30
+ if Sfalma::Config.api_key
31
+ Sfalma::Integration.test
32
+ else
33
+ puts 'API key not configured'
34
+ end
35
+ when 'alert'
36
+ require "sfalma"
37
+ require "sfalma/alert_data"
38
+ require "sfalma/integration/alerter"
39
+ Sfalma::Config.load('config/sfalma.yml')
40
+ if Sfalma::Config.api_key
41
+ exit(Sfalma::Integration.alert(args[0]) ? 0 : 2)
42
+ else
43
+ puts 'API key not configured. Put sfalma.yml in current directory or /config'
44
+ exit(1)
45
+ end
46
+ when 'install'
47
+ api_key = args[0]
48
+ environments = args[1]
49
+
50
+ if (api_key.nil?)
51
+ puts 'Missing required paramater <api-key>. Check your app configuration at http://sfalma.com.'
52
+ else
53
+ if (defined?(RAILS_ROOT) && !File.file?('config/environment.rb'))
54
+ puts "Run this command from the root of your rails application." and exit
55
+ else
56
+ Dir.mkdir('config') unless File.exists?('config')
57
+ end
58
+ end
59
+ config_file = File.open('config/sfalma.yml', 'w')
60
+ config_file.puts("api-key: #{api_key}\n")
61
+
62
+ unless(environments.nil?)
63
+ environments.split(',').each do |envo|
64
+ config_file.puts("#{envo}:\n")
65
+ config_file.puts(" enabled: true\n")
66
+ end
67
+ end
68
+
69
+ config_file.close
70
+ puts "Config file written as config/sfalma.yml.";
71
+ puts "----------------------------------------------";
72
+ File.open('config/sfalma.yml').readlines.each do |line|
73
+ puts line
74
+ end
75
+ puts "----------------------------------------------";
76
+ end
data/init.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'sfalma'
2
+ begin
3
+
4
+ if (Rails::VERSION::MAJOR < 3)
5
+ Sfalma::Config.load(File.join(RAILS_ROOT, "/config/sfalma.yml"))
6
+ if Sfalma::Config.should_send_to_api?
7
+ Sfalma.logger.info("Loading Sfalma #{Sfalma::VERSION} for #{Rails::VERSION::STRING}")
8
+ require File.join('sfalma', 'integration', 'rails')
9
+ require File.join('sfalma', 'integration', 'dj') if defined?(Delayed::Job)
10
+ end
11
+ else
12
+ Sfalma::Config.load(File.join(Rails.root, "/config/sfalma.yml"))
13
+
14
+ if Sfalma::Config.should_send_to_api?
15
+ Sfalma.logger.info("Loading Sfalma #{Sfalma::VERSION} for #{Rails::VERSION::STRING}")
16
+ Rails.configuration.middleware.use "Rack::RailsSfalma"
17
+ require File.join('sfalma', 'integration', 'dj') if defined?(Delayed::Job)
18
+ end
19
+ end
20
+
21
+ Sfalma::Startup.announce
22
+ rescue => e
23
+ STDERR.puts "Problem starting Sfalma Plugin. Your app will run as normal. #{e.message}"
24
+ Sfalma.logger.error(e.message)
25
+ Sfalma.logger.error(e.backtrace)
26
+ end
27
+
data/install.rb ADDED
@@ -0,0 +1,19 @@
1
+ # This is the post install hook for when Sfalma is installed as a plugin.
2
+ require 'fileutils'
3
+
4
+ # puts IO.read(File.join(File.dirname(__FILE__), 'README'))
5
+
6
+ config_file = File.expand_path("#{File.dirname(__FILE__)}/../../../config/sfalma.yml")
7
+ example_config_file = "#{File.dirname(__FILE__)}/sfalma.yml"
8
+
9
+ if File::exists? config_file
10
+ puts "Sfalma config file already exists. Please ensure it is up-to-date with the current format."
11
+ puts "See #{example_config_file}"
12
+ else
13
+ puts "Installing default Sfalma config."
14
+ puts " From #{example_config_file}"
15
+ puts "For sfalma to work you need to configure your API key."
16
+ puts " See #{example_config_file}"
17
+ puts "If you don't have an API key, get one at http://www.sfalma.com/."
18
+ FileUtils.copy example_config_file, config_file
19
+ end
@@ -0,0 +1,15 @@
1
+ module Sfalma
2
+ class AlertData < ExceptionData
3
+ # Overwrite backtrace, since it is irrelevant
4
+ def extra_data
5
+ {
6
+ 'exception' => {
7
+ 'exception_class' => @exception.class.to_s,
8
+ 'message' => @exception.message,
9
+ 'backtrace' => "",
10
+ 'occurred_at' => Time.now
11
+ }
12
+ }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,79 @@
1
+ require 'digest/md5'
2
+
3
+ module Sfalma
4
+ class ApplicationEnvironment
5
+ def self.to_hash(framework)
6
+ env = extract_environment(ENV)
7
+ {
8
+ 'client' => {
9
+ 'name' => Sfalma::CLIENT_NAME,
10
+ 'version' => Sfalma::VERSION,
11
+ 'protocol_version' => Sfalma::PROTOCOL_VERSION
12
+ },
13
+ 'application_environment' => {
14
+ 'environment' => environment,
15
+ 'host' => get_hostname,
16
+ 'run_as_user' => get_username,
17
+ 'app_home' => (application_root.to_s.respond_to?(:force_encoding) ? application_root.to_s.force_encoding("UTF-8") : application_root),
18
+ 'gem_home' => env.fetch('GEM_HOME',''),
19
+ 'language' => 'ruby',
20
+ 'language_version' => language_version_string,
21
+ 'framework' => framework,
22
+ 'libraries_loaded' => libraries_loaded
23
+ }
24
+ }
25
+ end
26
+
27
+ def self.to_hash_basic(framework)
28
+ {
29
+ 'client' => {
30
+ 'name' => Sfalma::CLIENT_NAME,
31
+ 'version' => Sfalma::VERSION,
32
+ 'protocol_version' => Sfalma::PROTOCOL_VERSION
33
+ },
34
+ 'application_environment' => {
35
+ 'environment' => environment,
36
+ 'app_home' => (application_root.to_s.respond_to?(:force_encoding) ? application_root.to_s.force_encoding("UTF-8") : application_root),
37
+ 'gem_home' => extract_environment(ENV).fetch('GEM_HOME','')
38
+ }
39
+ }
40
+ end
41
+
42
+ def self.environment
43
+ Config.application_environment
44
+ end
45
+
46
+ def self.application_root
47
+ Config.application_root
48
+ end
49
+
50
+ def self.extract_environment(env)
51
+ env.reject do |k, v|
52
+ (k =~ /^HTTP_/) || Sfalma::ENVIRONMENT_FILTER.include?(k)
53
+ end
54
+ end
55
+
56
+ def self.get_hostname
57
+ require 'socket' unless defined?(Socket)
58
+ Socket.gethostname
59
+ rescue
60
+ 'UNKNOWN'
61
+ end
62
+
63
+ def self.language_version_string
64
+ "#{RUBY_VERSION rescue '?.?.?'} p#{RUBY_PATCHLEVEL rescue '???'} #{RUBY_RELEASE_DATE rescue '????-??-??'} #{RUBY_PLATFORM rescue '????'}"
65
+ end
66
+
67
+ def self.get_username
68
+ ENV['LOGNAME'] || ENV['USER'] || ENV['USERNAME'] || ENV['APACHE_RUN_USER'] || 'UNKNOWN'
69
+ end
70
+
71
+ def self.libraries_loaded
72
+ begin
73
+ return Hash[*Gem.loaded_specs.map{|name, gem_specification| [name, gem_specification.version.to_s]}.flatten]
74
+ rescue
75
+ end
76
+ {}
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,26 @@
1
+ module Sfalma
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
+ end
9
+ end
10
+
11
+ def handle_with_rack(exception, environment, request)
12
+ if Config.should_send_to_api?
13
+ data = RackExceptionData.new(exception, environment, request)
14
+ Remote.error(data)
15
+ end
16
+ end
17
+
18
+ def handle(exception, name=nil)
19
+ if Config.should_send_to_api?
20
+ data = ExceptionData.new(exception, name)
21
+ Remote.error(data)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,93 @@
1
+ require 'yaml'
2
+
3
+ module Sfalma
4
+ class Config
5
+ class ConfigurationException < StandardError; end
6
+
7
+ class << self
8
+ DEFAULTS = {
9
+ :ssl => false,
10
+ :remote_host_http => 'http://www.sfalma.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
+ # VCS
39
+ @vcs = config['vcs'] unless config['vcs'].nil?
40
+ rescue Exception => e
41
+ raise ConfigurationException.new("Unable to load configuration #{config_file} for environment #{application_environment} : #{e.message}")
42
+ end
43
+ end
44
+ end
45
+
46
+ def vcs
47
+ @vcs ||= nil
48
+ end
49
+
50
+ def api_key
51
+ return @api_key unless @api_key.nil?
52
+ @api_key ||= ENV['EXCEPTIONAL_API_KEY'] unless ENV['EXCEPTIONAL_API_KEY'].nil?
53
+ end
54
+
55
+ def application_environment
56
+ ENV['RACK_ENV'] || ENV['RAILS_ENV']|| 'development'
57
+ end
58
+
59
+ def should_send_to_api?
60
+ return @enabled unless @enabled.nil?
61
+ @enabled = true#!(DEFAULTS[:disabled_by_default].include?(application_environment))
62
+ end
63
+
64
+ def application_root
65
+ (defined?(Rails) && Rails.respond_to?(:root)) ? Rails.root : Dir.pwd
66
+ end
67
+
68
+ def ssl?
69
+ @ssl ||= DEFAULTS[:ssl]
70
+ end
71
+
72
+ def remote_host
73
+ @remote_host ||= DEFAULTS[:remote_host_http]
74
+ end
75
+
76
+ def remote_port
77
+ @remote_port =80 #||= ssl? ? 443 : 80, we wait for naked domain SSL on GAE
78
+ end
79
+
80
+ def reset
81
+ @enabled = @ssl = @remote_host = @remote_port = @api_key = nil
82
+ end
83
+
84
+ def http_open_timeout
85
+ @http_open_timeout ||= DEFAULTS[:http_open_timeout]
86
+ end
87
+
88
+ def http_read_timeout
89
+ @http_read_timeout ||= DEFAULTS[:http_read_timeout]
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,69 @@
1
+ require 'digest/md5'
2
+
3
+ module Sfalma
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
+
18
+ {
19
+ 'request' => {
20
+ 'url' => (@request.respond_to?(:url) ? @request.url : "#{@request.protocol}#{@request.host}#{@request.request_uri}"),
21
+ 'controller' => @controller.class.to_s,
22
+ 'action' => action_name,
23
+ 'parameters' => filter_paramaters(@request.respond_to?(:parameters) ? @request.parameters : @request.params),
24
+ 'request_method' => @request.request_method.to_s,
25
+ 'remote_ip' => (@request.respond_to?(:remote_ip) ? @request.remote_ip : @request.ip),
26
+ 'headers' => extract_http_headers(@request.env),
27
+ 'session' => self.class.sanitize_session(@request)
28
+ }
29
+ }
30
+ end
31
+
32
+ def action_name
33
+ action_name = ''
34
+ if @controller.respond_to?(:action_name)
35
+ action_name = @controller.action_name.to_s
36
+ else
37
+ action_name = (@request.respond_to?(:parameters) ? @request.parameters['action'] : @request.params['action'])
38
+ end
39
+ action_name
40
+ end
41
+
42
+ def filter_hash(keys_to_filter, hash)
43
+ if keys_to_filter.is_a?(Array) && !keys_to_filter.empty?
44
+ hash.each do |key, value|
45
+ if value.respond_to?(:to_hash)
46
+ filter_hash(keys_to_filter, hash[key])
47
+ elsif key_match?(key, keys_to_filter)
48
+ hash[key] = "[FILTERED]"
49
+ end
50
+ end
51
+ end
52
+ hash
53
+ end
54
+
55
+ def key_match?(key, keys_to_filter)
56
+ keys_to_filter.map {|k| k.to_s}.include?(key.to_s)
57
+ end
58
+
59
+ def filter_paramaters(hash)
60
+ if @request.respond_to?(:env) && @request.env["action_dispatch.parameter_filter"]
61
+ filter_hash(@request.env["action_dispatch.parameter_filter"], hash)
62
+ elsif @controller.respond_to?(:filter_parameters)
63
+ @controller.send(:filter_parameters, hash)
64
+ else
65
+ hash
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,146 @@
1
+ require 'digest/md5'
2
+ require 'time'
3
+
4
+ module Sfalma
5
+ class ExceptionData
6
+
7
+ def initialize(exception, name=nil)
8
+ @exception = exception
9
+ @name = name
10
+ end
11
+
12
+ def to_hash
13
+ # Do not send the environment for every exception
14
+ hash = ::Sfalma::ApplicationEnvironment.to_hash_basic(framework)
15
+ app_home = hash['application_environment']['app_home']
16
+ gem_home = hash['application_environment']['gem_home']
17
+ line_and_number = where(@exception.backtrace, app_home, gem_home)
18
+
19
+ hash.merge!({
20
+ 'exception' => {
21
+ 'klass' => @exception.class.to_s,
22
+ 'message' => @exception.message,
23
+ 'backtrace' => normalize(@exception.backtrace, app_home, gem_home),
24
+ 'occurred_at' => Time.now.utc.iso8601,
25
+ 'where' => line_and_number
26
+ }
27
+ })
28
+ hash.merge!(extra_stuff)
29
+ hash.merge!(context_stuff)
30
+ #hash.merge!(::Sfalma::VCS(line_and_number, app_home).to_hash)
31
+ self.class.sanitize_hash(hash)
32
+ end
33
+
34
+ def normalize(trace, app_home, gem_home)
35
+ trace.map do |line|
36
+ if !line.index(app_home).nil?
37
+ line.gsub!(app_home,'[APP_HOME]')
38
+ elsif !line.index(gem_home).nil?
39
+ line.gsub!(gem_home, '[GEM_HOME]')
40
+ end
41
+ line
42
+ end
43
+ end
44
+
45
+ def where(trace, app_path, gem_path)
46
+ line_and_number = ''
47
+ trace.each do |line|
48
+ if !line.index(app_path).nil?
49
+ line_and_number = line[0,line.rindex(':')]
50
+ puts line
51
+ break
52
+ end
53
+ end
54
+ if line_and_number == ''
55
+ line_and_number = trace[0][0,trace[0].rindex(':')]
56
+ end
57
+ line_and_number.gsub!(app_path,'').gsub!(gem_path,'') rescue line_and_number
58
+ line_and_number
59
+ end
60
+
61
+ def extra_stuff
62
+ { 'rescue_block' => { 'name' => @name} }
63
+ end
64
+
65
+ def context_stuff
66
+ context = Thread.current[:exceptional_context]
67
+ (context.nil? || context.empty?) ? {} : {'context' => context}
68
+ end
69
+
70
+ def to_json
71
+ begin
72
+ to_hash.to_json
73
+ rescue NoMethodError
74
+ begin
75
+ require 'json'
76
+ return to_hash.to_json
77
+ rescue StandardError => e
78
+ Sfalma.logger.error(e.message)
79
+ Sfalma.logger.error(e.backtrace)
80
+ raise StandardError.new("You need a json gem/library installed to send errors to Sfalma (Object.to_json not defined). \nInstall json_pure, yajl-ruby, json-jruby, or the c-based json gem")
81
+ end
82
+ end
83
+ end
84
+
85
+ def framework
86
+ nil
87
+ end
88
+
89
+ def uniqueness_hash
90
+ return nil if (@exception.backtrace.nil? || @exception.backtrace.empty?)
91
+ # in case we have the same exception class at the same line but caused by different method
92
+ @exception.backtrace.push(@exception.message)
93
+ traces = @exception.backtrace.collect{ |line|
94
+ line if line.scan(/_run__\d+__process_action__\d+__callbacks/).size<1
95
+ }.compact
96
+ Digest::MD5.hexdigest(traces.join)
97
+ end
98
+
99
+ def self.sanitize_hash(hash)
100
+ case hash
101
+ when Hash
102
+ hash.inject({}) do |result, (key, value)|
103
+ result.update(key => sanitize_hash(value))
104
+ end
105
+ when Array
106
+ hash.collect{|value| sanitize_hash(value)}
107
+ when Fixnum, String, Bignum
108
+ hash
109
+ else
110
+ hash.to_s
111
+ end
112
+ rescue Exception => e
113
+ Sfalma.logger.error(hash)
114
+ Sfalma.logger.error(e.message)
115
+ Sfalma.logger.error(e.backtrace)
116
+ {}
117
+ end
118
+
119
+ def extract_http_headers(env)
120
+ headers = {}
121
+ env.select{|k, v| k =~ /^HTTP_/}.each do |name, value|
122
+ proper_name = name.sub(/^HTTP_/, '').split('_').map{|upper_case| upper_case.capitalize}.join('-')
123
+ headers[proper_name] = value
124
+ end
125
+ unless headers['Cookie'].nil?
126
+ headers['Cookie'] = headers['Cookie'].sub(/_session=\S+/, '_session=[FILTERED]')
127
+ end
128
+ headers
129
+ end
130
+
131
+ def self.sanitize_session(request)
132
+ session_hash = {'session_id' => "", 'data' => {}}
133
+
134
+ if request.respond_to?(:session)
135
+ session = request.session
136
+ session_hash['session_id'] = request.session_options ? request.session_options[:id] : nil
137
+ session_hash['session_id'] ||= session.respond_to?(:session_id) ? session.session_id : session.instance_variable_get("@session_id")
138
+ session_hash['data'] = session.respond_to?(:to_hash) ? session.to_hash : session.instance_variable_get("@data") || {}
139
+ session_hash['session_id'] ||= session_hash['data'][:session_id]
140
+ session_hash['data'].delete(:session_id)
141
+ end
142
+
143
+ self.sanitize_hash(session_hash)
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,11 @@
1
+ module Sfalma
2
+ class Alert <StandardError;
3
+ end
4
+
5
+ module Integration
6
+ def self.alert(msg, env={})
7
+ return Sfalma::Remote.error(Sfalma::AlertData.new(Alert.new(msg), "Alert"))
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,12 @@
1
+ begin
2
+ class Delayed::Job
3
+ def log_exception_with_sfalma(e)
4
+ Sfalma.handle(e, "Delayed::Job #{self.name}")
5
+ log_exception_without_sfalma(e)
6
+ Sfalma.context.clear!
7
+ end
8
+ alias_method_chain :log_exception, :sfalma
9
+ Sfalma.logger.info "DJ integration enabled"
10
+ end
11
+ rescue
12
+ end
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'rack'
3
+
4
+ module Rack
5
+ class Sfalma
6
+
7
+ def initialize(app, api_key = nil)
8
+ @app = app
9
+ if api_key.nil?
10
+ sfalma_config = "config/sfalma.yml"
11
+ ::Sfalma::Config.load(sfalma_config)
12
+ else
13
+ ::Sfalma.configure(api_key)
14
+ ::Sfalma::Config.enabled = true
15
+ ::Sfalma.logger.info "Enabling Sfalma 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
+ ::Sfalma::Catcher.handle_with_rack(e,env, Rack::Request.new(env))
24
+ raise(e)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require 'rack'
3
+
4
+ module Rack
5
+ class RailsSfalma
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
+ ::Sfalma::Catcher.handle_with_controller(e,env['action_controller.instance'], Rack::Request.new(env))
16
+ raise
17
+ end
18
+
19
+ if env['rack.exception']
20
+ ::Sfalma::Catcher.handle_with_controller(env['rack.exception'],env['action_controller.instance'], Rack::Request.new(env))
21
+ end
22
+
23
+ body
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,27 @@
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_exceptional(exception)
10
+ unless exception_handled_by_rescue_from?(exception)
11
+ Sfalma::Catcher.handle_with_controller(exception, self, request)
12
+ Sfalma.context.clear!
13
+ end
14
+ rescue_action_without_exceptional exception
15
+ end
16
+
17
+ alias_method :rescue_action_without_exceptional, :rescue_action
18
+ alias_method :rescue_action, :rescue_action_with_exceptional
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
@@ -0,0 +1,6 @@
1
+ if defined? Sinatra::Request
2
+ error do
3
+ Sfalma::Catcher.handle_with_rack(request.env['sinatra.error'], request.env, request)
4
+ raise request.env['sinatra.error']
5
+ end
6
+ end