ramon 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/init.rb CHANGED
@@ -1 +1,7 @@
1
+ # Load the exception handler
2
+ # Aplicable only for Rails apps
1
3
  require 'ramon'
4
+
5
+ require File.join('amon', 'integration', 'rails')
6
+
7
+ Rails.configuration.middleware.use "Rack::RailsAmonException"
@@ -5,12 +5,19 @@ end
5
5
  require_local "version"
6
6
  require_local "logger"
7
7
  require_local "remote"
8
- require_local "exception_data"
8
+ require_local "catcher"
9
+ require_local "exception_data"
10
+ require_local "controller_exception_data"
11
+ require_local "enviroment_data"
9
12
 
10
13
  module Ramon
11
14
  def self.log(message, level=nil)
12
15
  log_hash = Log.log(message, level)
13
16
  Remote.post('log', log_hash)
14
17
  end
18
+
19
+ def self.post(type, data)
20
+ Remote.post(type, data)
21
+ end
15
22
  end
16
23
 
@@ -0,0 +1,20 @@
1
+ module Ramon
2
+ class Catcher
3
+ class << self
4
+
5
+ def handle_with_controller(exception, controller=nil, request=nil)
6
+ data = ControllerExceptionData.new(exception, controller, request)
7
+ Ramon.post('exception', data)
8
+ end
9
+
10
+ def handle_with_rack(exception, environment, request)
11
+ data = RackExceptionData.new(exception, environment, request)
12
+ end
13
+
14
+ def handle(exception, name=nil)
15
+ data = ExceptionData.new(exception, name)
16
+ end
17
+
18
+ end
19
+ end # class end
20
+ end # module end
@@ -1,44 +1,44 @@
1
1
  require 'json'
2
2
 
3
3
  module Ramon
4
- class Config
5
- class ConfigurationException < StandardError; end
6
-
7
- class << self
8
- DEFAULTS = {
9
- :host => 'http://127.0.0.1',
10
- :port => 2464
11
- }
4
+ class Config
5
+ class ConfigurationException < StandardError; end
6
+
7
+ class << self
8
+ DEFAULTS = {
9
+ :host => 'http://127.0.0.1',
10
+ :port => 2464
11
+ }
12
12
 
13
- def load
14
- config_file ||= "/etc/amon.conf"
13
+ def load
14
+ config_file ||= "/etc/amon.conf"
15
15
 
16
- if File.file?(config_file)
17
- begin
18
- f = File.read(config_file)
19
- config = JSON.parse(f)
16
+ if File.file?(config_file)
17
+ begin
18
+ f = File.read(config_file)
19
+ config = JSON.parse(f)
20
20
 
21
- @app_key = config['application_key'] unless config['application_key'].nil?
22
- @port = config['web_app']['port'].to_i unless config['web_app']['port'].nil?
23
- @host = config['web_app']['host'].to_s unless config['web_app']['host'].nil?
21
+ @app_key = config['application_key'] unless config['application_key'].nil?
22
+ @port = config['web_app']['port'].to_i unless config['web_app']['port'].nil?
23
+ @host = config['web_app']['host'].to_s unless config['web_app']['host'].nil?
24
24
 
25
- rescue Exception => e
26
- raise ConfigurationException.new("Unable to load configuration file: #{config_file}")
27
- end
28
- else
29
- puts "Amon::Config.load - /etc/amon.conf not found"
30
- end
25
+ rescue Exception => e
26
+ raise ConfigurationException.new("Unable to load configuration file: #{config_file}")
27
+ end
28
+ else
29
+ puts "Amon::Config.load - /etc/amon.conf not found"
31
30
  end
31
+ end
32
32
 
33
- def port
34
- @port ||= DEFAULTS[:port]
35
- end
36
-
37
- def host
38
- @host ||= DEFAULTS[:host]
39
- end
33
+ def port
34
+ @port ||= DEFAULTS[:port]
35
+ end
36
+
37
+ def host
38
+ @host ||= DEFAULTS[:host]
39
+ end
40
40
 
41
- end # self end
42
- load
43
- end # Config end
41
+ end # self end
42
+ load
43
+ end # Config end
44
44
  end # Module end
@@ -0,0 +1,59 @@
1
+ require 'digest/md5'
2
+
3
+ module Ramon
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 additional_data
16
+ return {} if @request.nil?
17
+ {
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_paramaters(@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
+ end
30
+
31
+ def filter_hash(keys_to_filter, hash)
32
+ if keys_to_filter.is_a?(Array) && !keys_to_filter.empty?
33
+ hash.each do |key, value|
34
+ if value.respond_to?(:to_hash)
35
+ filter_hash(keys_to_filter, hash[key])
36
+ elsif key_match?(key, keys_to_filter)
37
+ hash[key] = "[FILTERED]"
38
+ end
39
+ end
40
+ end
41
+ hash
42
+ end
43
+
44
+ def key_match?(key, keys_to_filter)
45
+ keys_to_filter.map {|k| k.to_s}.include?(key.to_s)
46
+ end
47
+
48
+ def filter_paramaters(hash)
49
+ if @request.respond_to?(:env) && @request.env["action_dispatch.parameter_filter"]
50
+ filter_hash(@request.env["action_dispatch.parameter_filter"], hash)
51
+ elsif @controller.respond_to?(:filter_parameters)
52
+ @controller.send(:filter_parameters, hash)
53
+ else
54
+ hash
55
+ end
56
+ end
57
+
58
+ end # class end
59
+ end # module end
@@ -0,0 +1,39 @@
1
+ require 'digest/md5'
2
+
3
+ module Ramon
4
+ class ApplicationEnvironment
5
+ def self.to_hash(framework)
6
+ {
7
+ 'language' => 'ruby',
8
+ 'language_version' => language_version_string,
9
+ 'framework' => framework,
10
+ #'libraries_loaded' => libraries_loaded
11
+ }
12
+ end
13
+
14
+
15
+ def self.get_hostname
16
+ require 'socket' unless defined?(Socket)
17
+ Socket.gethostname
18
+ rescue
19
+ 'UNKNOWN'
20
+ end
21
+
22
+ def self.language_version_string
23
+ "#{RUBY_VERSION rescue '?.?.?'} p#{RUBY_PATCHLEVEL rescue '???'} #{RUBY_RELEASE_DATE rescue '????-??-??'} #{RUBY_PLATFORM rescue '????'}"
24
+ end
25
+
26
+ def self.get_username
27
+ ENV['LOGNAME'] || ENV['USER'] || ENV['USERNAME'] || ENV['APACHE_RUN_USER'] || 'UNKNOWN'
28
+ end
29
+
30
+ def self.libraries_loaded
31
+ begin
32
+ return Hash[*Gem.loaded_specs.map{|name, gem_specification| [name, gem_specification.version.to_s]}.flatten]
33
+ rescue
34
+ end
35
+ {}
36
+ end
37
+
38
+ end # class end
39
+ end # module end
@@ -0,0 +1,99 @@
1
+ module Ramon
2
+ class ExceptionData
3
+
4
+ def initialize(exception, name=nil)
5
+ @exception = exception
6
+ @name = name
7
+ end
8
+
9
+ def to_hash
10
+ hash = {}
11
+ # We need the url before the main exception info
12
+ hash['data'] = additional_data
13
+
14
+ hash.merge!({
15
+ 'exception_class' => @exception.class.to_s,
16
+ 'message' => @exception.message,
17
+ 'backtrace' => @exception.backtrace,
18
+ 'url' => hash['data']['request']['url']
19
+ })
20
+
21
+ hash['data'].merge!(ApplicationEnvironment.to_hash(framework))
22
+ hash['data'].merge!(context_stuff)
23
+ hash['data'].merge!(extra_stuff)
24
+ self.class.sanitize_hash(hash)
25
+ end
26
+
27
+ def extra_stuff
28
+ if @name
29
+ {'name' => @name}
30
+ else
31
+ {}
32
+ end
33
+ end
34
+
35
+ def context_stuff
36
+ context = Thread.current[:exceptional_context]
37
+ (context.nil? || context.empty?) ? {} : {'context' => context}
38
+ end
39
+
40
+ def framework
41
+ nil
42
+ end
43
+
44
+
45
+ def self.sanitize_hash(hash)
46
+
47
+ case hash
48
+ when Hash
49
+ hash.inject({}) do |result, (key, value)|
50
+ result.update(key => sanitize_hash(value))
51
+ end
52
+ when Array
53
+ hash.collect{|value| sanitize_hash(value)}
54
+ when Fixnum, String, Bignum
55
+ hash
56
+ else
57
+ hash.to_s
58
+ end
59
+ rescue Exception => e
60
+ {}
61
+ end
62
+
63
+ def extract_http_headers(env)
64
+ headers = {}
65
+ env.select{|k, v| k =~ /^HTTP_/}.each do |name, value|
66
+ proper_name = name.sub(/^HTTP_/, '').split('_').map{|upper_case| upper_case.capitalize}.join('-')
67
+ headers[proper_name] = value
68
+ end
69
+ unless headers['Cookie'].nil?
70
+ headers['Cookie'] = headers['Cookie'].sub(/_session=\S+/, '_session=[FILTERED]')
71
+ end
72
+ headers
73
+ end
74
+
75
+ def self.sanitize_session(request)
76
+
77
+ session_hash = {'session_id' => "", 'data' => {}}
78
+
79
+ if request.respond_to?(:session)
80
+
81
+ session = request.session
82
+ session_hash['session_id'] = request.session_options ? request.session_options[:id] : nil
83
+ session_hash['session_id'] ||= session.respond_to?(:session_id) ? session.session_id : session.instance_variable_get("@session_id")
84
+ session_hash['data'] = session.respond_to?(:to_hash) ? session.to_hash : session.instance_variable_get("@data") || {}
85
+ session_hash['session_id'] ||= session_hash['data'][:session_id]
86
+ session_hash['data'].delete(:session_id)
87
+ end
88
+
89
+ # Don't return the session hash if there is nothing in it
90
+ if session_hash['session_id'].nil? && session_hash['data'].empty?
91
+ {}
92
+ else
93
+ self.sanitize_hash(session_hash)
94
+ end
95
+
96
+ end
97
+
98
+ end # class end
99
+ end # module end
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'rack'
3
+
4
+ module Rack
5
+ class RailsAmonException
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
+ Ramon::Catcher.handle_with_controller(e,env['action_controller.instance'], Rack::Request.new(env))
16
+ raise
17
+ end
18
+
19
+ body
20
+ end
21
+ end
22
+ end
@@ -1,13 +1,13 @@
1
1
  module Ramon
2
- class Log
3
- def self.log(message, level)
4
- level ||= 'notset'
5
- log = {"message" => message, "level" => level}
6
-
7
- log
8
- end
2
+ class Log
3
+ def self.log(message, level)
4
+ level ||= 'notset'
5
+ log = {"message" => message, "level" => level}
6
+
7
+ log
9
8
  end
10
- end
9
+ end # class end
10
+ end # module end
11
11
 
12
12
 
13
13
 
@@ -4,20 +4,20 @@ require 'zlib'
4
4
  require "#{File.dirname(__FILE__)}/config"
5
5
 
6
6
  module Ramon
7
- class Remote
8
- def self.post(type, data)
7
+ class Remote
8
+ def self.post(type, data)
9
9
 
10
- if type == 'log':
11
- @url = '/api/log'
12
- else
13
- @url = '/api/exception'
14
- end
15
-
16
- req = Net::HTTP::Post.new(@url, initheader = {'Content-Type' =>'application/json'})
17
- #req.body = Zlib::Deflate.deflate(data.to_json, Zlib::BEST_SPEED)
18
- req.body = data.to_json
19
- response = Net::HTTP.new(Config::host, Config::port).start {|http| http.request(req) }
20
- #puts "Response #{response.code} #{response.message}: #{response.body}"
10
+ if type == 'log':
11
+ @url = '/api/log'
12
+ else
13
+ @url = '/api/exception'
21
14
  end
22
- end # class end
15
+
16
+ req = Net::HTTP::Post.new(@url, initheader = {'Content-Type' =>'application/json'})
17
+ #req.body = Zlib::Deflate.deflate(data.to_json, Zlib::BEST_SPEED)
18
+ req.body = data.to_json
19
+ response = Net::HTTP.new(Config::host, Config::port).start {|http| http.request(req) }
20
+ #puts "Response #{response.code} #{response.message}: #{response.body}"
21
+ end
22
+ end # class end
23
23
  end # module end
@@ -1,3 +1,3 @@
1
1
  module Ramon
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__) , '../init.rb')
@@ -1,15 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "ramon/version"
2
+ require File.expand_path('../lib/ramon/version', __FILE__)
4
3
 
5
4
  Gem::Specification.new do |s|
6
5
  s.name = "ramon"
7
6
  s.version = Ramon::VERSION
8
7
  s.authors = ["martinrusev"]
9
- s.email = ["martinrusev@zoho.com"]
8
+ s.email = ["martin@amon.cx"]
10
9
  s.homepage = "http://amon.cx"
11
10
  s.summary = %q{Ruby binding for Amon}
12
- s.description = %q{Amon client that provides logging and exception handling}
11
+ s.description = %q{Amon client for Ruby that provides logging and exception handling for web applications}
13
12
 
14
13
  s.rubyforge_project = "ramon"
15
14
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ramon
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - martinrusev
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-11-09 00:00:00 +00:00
18
+ date: 2011-11-14 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -32,9 +32,9 @@ dependencies:
32
32
  version: "0"
33
33
  type: :runtime
34
34
  version_requirements: *id001
35
- description: Amon client that provides logging and exception handling
35
+ description: Amon client for Ruby that provides logging and exception handling for web applications
36
36
  email:
37
- - martinrusev@zoho.com
37
+ - martin@amon.cx
38
38
  executables: []
39
39
 
40
40
  extensions: []
@@ -47,11 +47,16 @@ files:
47
47
  - Rakefile
48
48
  - init.rb
49
49
  - lib/ramon.rb
50
+ - lib/ramon/catcher.rb
50
51
  - lib/ramon/config.rb
52
+ - lib/ramon/controller_exception_data.rb
53
+ - lib/ramon/enviroment_data.rb
51
54
  - lib/ramon/exception_data.rb
55
+ - lib/ramon/integration/rails.rb
52
56
  - lib/ramon/logger.rb
53
57
  - lib/ramon/remote.rb
54
58
  - lib/ramon/version.rb
59
+ - rails/init.rb
55
60
  - ramon.gemspec
56
61
  has_rdoc: true
57
62
  homepage: http://amon.cx