ramon 0.1.1 → 0.2.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/init.rb +6 -0
- data/lib/ramon.rb +8 -1
- data/lib/ramon/catcher.rb +20 -0
- data/lib/ramon/config.rb +33 -33
- data/lib/ramon/controller_exception_data.rb +59 -0
- data/lib/ramon/enviroment_data.rb +39 -0
- data/lib/ramon/exception_data.rb +99 -0
- data/lib/ramon/integration/rails.rb +22 -0
- data/lib/ramon/logger.rb +8 -8
- data/lib/ramon/remote.rb +14 -14
- data/lib/ramon/version.rb +1 -1
- data/rails/init.rb +1 -0
- data/ramon.gemspec +3 -4
- metadata +12 -7
data/init.rb
CHANGED
data/lib/ramon.rb
CHANGED
@@ -5,12 +5,19 @@ end
|
|
5
5
|
require_local "version"
|
6
6
|
require_local "logger"
|
7
7
|
require_local "remote"
|
8
|
-
require_local "
|
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
|
data/lib/ramon/config.rb
CHANGED
@@ -1,44 +1,44 @@
|
|
1
1
|
require 'json'
|
2
2
|
|
3
3
|
module Ramon
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
14
|
-
|
13
|
+
def load
|
14
|
+
config_file ||= "/etc/amon.conf"
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
if File.file?(config_file)
|
17
|
+
begin
|
18
|
+
f = File.read(config_file)
|
19
|
+
config = JSON.parse(f)
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
33
|
+
def port
|
34
|
+
@port ||= DEFAULTS[:port]
|
35
|
+
end
|
36
|
+
|
37
|
+
def host
|
38
|
+
@host ||= DEFAULTS[:host]
|
39
|
+
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
data/lib/ramon/exception_data.rb
CHANGED
@@ -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
|
data/lib/ramon/logger.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
module Ramon
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
|
data/lib/ramon/remote.rb
CHANGED
@@ -4,20 +4,20 @@ require 'zlib'
|
|
4
4
|
require "#{File.dirname(__FILE__)}/config"
|
5
5
|
|
6
6
|
module Ramon
|
7
|
-
|
8
|
-
|
7
|
+
class Remote
|
8
|
+
def self.post(type, data)
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
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
|
data/lib/ramon/version.rb
CHANGED
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__) , '../init.rb')
|
data/ramon.gemspec
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
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 = ["
|
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:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
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-
|
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
|
-
-
|
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
|