loggr-rb 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/loggr +70 -0
- data/init.rb +38 -0
- data/install.rb +19 -0
- data/lib/loggr-rb.rb +64 -0
- data/lib/loggr-rb/catcher.rb +23 -0
- data/lib/loggr-rb/config.rb +93 -0
- data/lib/loggr-rb/events.rb +169 -0
- data/lib/loggr-rb/exceptiondata.rb +49 -0
- data/lib/loggr-rb/http.rb +32 -0
- data/lib/loggr-rb/integration/dj.rb +12 -0
- data/lib/loggr-rb/integration/rack.rb +28 -0
- data/lib/loggr-rb/integration/rack_rails.rb +26 -0
- data/lib/loggr-rb/integration/rails.rb +27 -0
- data/lib/loggr-rb/integration/sinatra.rb +6 -0
- data/lib/loggr-rb/integration/tester.rb +13 -0
- data/lib/loggr-rb/logclient.rb +63 -0
- data/lib/loggr-rb/logfactory.rb +39 -0
- data/lib/loggr-rb/railtie.rb +19 -0
- data/lib/loggr-rb/version.rb +3 -0
- data/lib/tasks/exceptional_tasks.rake +11 -0
- data/lib/tasks/loggr_tasks.rake +11 -0
- data/loggr-rb.gemspec +17 -0
- data/rails/init.rb +1 -0
- metadata +94 -0
data/bin/loggr
ADDED
@@ -0,0 +1,70 @@
|
|
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 Loggr.
|
12
|
+
install <log_key> <api_key> # Create config/loggr.yml with your api_key. Overrites existing one.
|
13
|
+
|
14
|
+
USAGE
|
15
|
+
when 'test'
|
16
|
+
if defined?(RAILS_ROOT)
|
17
|
+
puts "Loading Rails environment."
|
18
|
+
require(File.join('config', 'boot'))
|
19
|
+
require(File.join(RAILS_ROOT, 'config', 'environment')) if defined?(RAILS_ROOT)
|
20
|
+
require "loggr-rb/integration/tester"
|
21
|
+
else
|
22
|
+
require 'loggr-rb'
|
23
|
+
require "loggr-rb/integration/tester"
|
24
|
+
Loggr::Config.load('config/loggr.yml')
|
25
|
+
end
|
26
|
+
if Loggr::Config.api_key
|
27
|
+
Loggr::Integration.test
|
28
|
+
else
|
29
|
+
puts 'API key not configured'
|
30
|
+
end
|
31
|
+
when 'install'
|
32
|
+
log_key = args[0]
|
33
|
+
api_key = args[1]
|
34
|
+
environments = args[2]
|
35
|
+
|
36
|
+
if (log_key.nil?)
|
37
|
+
puts 'Missing required paramater <log-key>. Check your app configuration at http://loggr.net.'
|
38
|
+
else
|
39
|
+
if (api_key.nil?)
|
40
|
+
puts 'Missing required paramater <api-key>. Check your app configuration at http://loggr.net.'
|
41
|
+
else
|
42
|
+
if (defined?(RAILS_ROOT) && !File.file?('config/environment.rb'))
|
43
|
+
puts "Run this command from the root of your rails application." and exit
|
44
|
+
else
|
45
|
+
Dir.mkdir('config') unless File.exists?('config')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
config_file = File.open('config/loggr.yml', 'w')
|
50
|
+
config_file.puts("log-key: #{log_key}\n")
|
51
|
+
config_file.puts("api-key: #{api_key}\n")
|
52
|
+
config_file.puts("\n")
|
53
|
+
config_file.puts("development:\n")
|
54
|
+
config_file.puts(" enabled: true\n")
|
55
|
+
|
56
|
+
unless(environments.nil?)
|
57
|
+
environments.split(',').each do |envo|
|
58
|
+
config_file.puts("#{envo}:\n")
|
59
|
+
config_file.puts(" enabled: true\n")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
config_file.close
|
64
|
+
puts "Config file written as config/loggr.yml.";
|
65
|
+
puts "----------------------------------------------";
|
66
|
+
File.open('config/loggr.yml').readlines.each do |line|
|
67
|
+
puts line
|
68
|
+
end
|
69
|
+
puts "----------------------------------------------";
|
70
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'loggr-rb'
|
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?(Loggr::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 Loggr plugin installed.
|
10
|
+
Remove it from /vendor/plugins and try again.
|
11
|
+
***********************************************************************
|
12
|
+
)
|
13
|
+
puts message
|
14
|
+
exit -1
|
15
|
+
else
|
16
|
+
begin
|
17
|
+
if (Rails::VERSION::MAJOR < 3)
|
18
|
+
Loggr::Config.load(File.join(RAILS_ROOT, "/config/loggr.yml"))
|
19
|
+
if Loggr::Config.should_send_to_api?
|
20
|
+
Loggr.logger.info("Loading Loggr #{Loggr::VERSION} for #{Rails::VERSION::STRING}")
|
21
|
+
require File.join('loggr-rb', 'integration', 'rails')
|
22
|
+
require File.join('loggr-rb', 'integration', 'dj') if defined?(Delayed::Job)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
Loggr::Config.load(File.join(Rails.root, "/config/loggr.yml"))
|
26
|
+
|
27
|
+
if Loggr::Config.should_send_to_api?
|
28
|
+
Loggr.logger.info("Loading Loggr #{Loggr::VERSION} for #{Rails::VERSION::STRING}")
|
29
|
+
Rails.configuration.middleware.use "Rack::RailsLoggr"
|
30
|
+
require File.join('loggr-rb', 'integration', 'dj') if defined?(Delayed::Job)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
rescue => e
|
34
|
+
STDERR.puts "Problem starting Loggr Plugin. Your app will run as normal. #{e.message}"
|
35
|
+
Loggr.logger.error(e.message)
|
36
|
+
Loggr.logger.error(e.backtrace)
|
37
|
+
end
|
38
|
+
end
|
data/install.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# This is the post install hook for when Loggr 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/loggr.yml")
|
7
|
+
example_config_file = "#{File.dirname(__FILE__)}/loggr.yml"
|
8
|
+
|
9
|
+
if File::exists? config_file
|
10
|
+
puts "Loggr 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 Loggr config."
|
14
|
+
puts " From #{example_config_file}"
|
15
|
+
puts "For loggr 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://loggr.net/."
|
18
|
+
FileUtils.copy example_config_file, config_file
|
19
|
+
end
|
data/lib/loggr-rb.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'loggr-rb/catcher'
|
4
|
+
require 'loggr-rb/logfactory'
|
5
|
+
require 'loggr-rb/config'
|
6
|
+
require 'loggr-rb/exceptiondata'
|
7
|
+
require 'loggr-rb/integration/rack'
|
8
|
+
require 'loggr-rb/integration/rack_rails'
|
9
|
+
require 'loggr-rb/logclient'
|
10
|
+
require 'loggr-rb/events'
|
11
|
+
|
12
|
+
require 'loggr-rb/version' if !defined?(Loggr::VERSION)
|
13
|
+
require 'loggr-rb/railtie' if defined?(Rails::Railtie)
|
14
|
+
|
15
|
+
module Loggr
|
16
|
+
PROTOCOL_VERSION = 5
|
17
|
+
CLIENT_NAME = 'loggr-rb-gem'
|
18
|
+
ENVIRONMENT_FILTER = []
|
19
|
+
|
20
|
+
def self.logger
|
21
|
+
::Loggr::LogFactory.logger
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.configure(api_key)
|
25
|
+
Loggr::Config.api_key = api_key
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.handle(exception, request=nil)
|
29
|
+
Loggr::Catcher.handle(exception, request)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.rescue(name=nil, context=nil, &block)
|
33
|
+
begin
|
34
|
+
self.context(context) unless context.nil?
|
35
|
+
block.call
|
36
|
+
rescue Exception => e
|
37
|
+
Loggr::Catcher.handle(e,name)
|
38
|
+
ensure
|
39
|
+
self.clear!
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.rescue_and_reraise(name=nil, context=nil, &block)
|
44
|
+
begin
|
45
|
+
self.context(context) unless context.nil?
|
46
|
+
block.call
|
47
|
+
rescue Exception => e
|
48
|
+
Loggr::Catcher.handle(e,name)
|
49
|
+
raise(e)
|
50
|
+
ensure
|
51
|
+
self.clear!
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.clear!
|
56
|
+
Thread.current[:loggr_context] = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.context(hash = {})
|
60
|
+
Thread.current[:loggr_context] ||= {}
|
61
|
+
Thread.current[:loggr_context].merge!(hash)
|
62
|
+
self
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Loggr
|
2
|
+
class Catcher
|
3
|
+
class << self
|
4
|
+
def handle_with_controller(exception, controller=nil, request=nil)
|
5
|
+
if Config.should_send_to_api?
|
6
|
+
Loggr::Events.create_from_exception(exception, request).post()
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle_with_rack(exception, environment, request)
|
11
|
+
if Config.should_send_to_api?
|
12
|
+
Loggr::Events.create_from_exception(exception, request).post()
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def handle(exception, request=nil)
|
17
|
+
if Config.should_send_to_api?
|
18
|
+
Loggr::Events.create_from_exception(exception, request).post()
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Loggr
|
4
|
+
class Config
|
5
|
+
class ConfigurationException < StandardError; end
|
6
|
+
|
7
|
+
class << self
|
8
|
+
DEFAULTS = {
|
9
|
+
:ssl => false,
|
10
|
+
:remote_host_http => 'plugin.getloggr.com',
|
11
|
+
:http_open_timeout => 2,
|
12
|
+
:http_read_timeout => 4,
|
13
|
+
:disabled_by_default => %w(development test)
|
14
|
+
}
|
15
|
+
|
16
|
+
attr_accessor :log_key, :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
|
+
@log_key = config['log-key'] || env_config['log-key']
|
26
|
+
@api_key = config['api-key'] || env_config['api-key']
|
27
|
+
|
28
|
+
@http_proxy_host = config['http-proxy-host']
|
29
|
+
@http_proxy_port = config['http-proxy-port']
|
30
|
+
@http_proxy_username = config['http-proxy-username']
|
31
|
+
@http_proxy_password = config['http-proxy-password']
|
32
|
+
@http_open_timeout = config['http-open-timeout']
|
33
|
+
@http_read_timeout = config['http-read-timeout']
|
34
|
+
|
35
|
+
@ssl = config['ssl'] || env_config['ssl']
|
36
|
+
@enabled = env_config['enabled']
|
37
|
+
@remote_port = config['remote-port'].to_i unless config['remote-port'].nil?
|
38
|
+
@remote_host = config['remote-host'] unless config['remote-host'].nil?
|
39
|
+
rescue Exception => e
|
40
|
+
raise ConfigurationException.new("Unable to load configuration #{config_file} for environment #{application_environment} : #{e.message}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def log_key
|
46
|
+
return @log_key unless @log_key.nil?
|
47
|
+
@log_key ||= ENV['LOGGR_LOG_KEY'] unless ENV['LOGGR_LOG_KEY'].nil?
|
48
|
+
end
|
49
|
+
|
50
|
+
def api_key
|
51
|
+
return @api_key unless @api_key.nil?
|
52
|
+
@api_key ||= ENV['LOGGR_API_KEY'] unless ENV['LOGGR_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 = !(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 ||= ssl? ? 443 : 80
|
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,169 @@
|
|
1
|
+
module Loggr
|
2
|
+
class Events
|
3
|
+
def self.create(callback=nil)
|
4
|
+
return FluentEvent.new(callback)
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.create_from_exception(ex, request=nil, callback=nil)
|
8
|
+
source = ""
|
9
|
+
begin
|
10
|
+
if !request.nil?
|
11
|
+
if !request.parameters.nil?
|
12
|
+
controller = request.params['controller'].camelize
|
13
|
+
action = request.params['action']
|
14
|
+
if !controller.nil?
|
15
|
+
source = controller.camelize + "Controller"
|
16
|
+
if !action.nil?
|
17
|
+
source = source + "#" + action.camelize
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
rescue
|
23
|
+
# no source
|
24
|
+
end
|
25
|
+
ip = ""
|
26
|
+
if !request.nil?
|
27
|
+
ip = (request.respond_to?(:remote_ip) ? request.remote_ip : request.ip)
|
28
|
+
end
|
29
|
+
ev = self.create(callback)
|
30
|
+
ev.text("Exception '#{ex.message}'")
|
31
|
+
ev.tags("error")
|
32
|
+
ev.add_tags(ex.class)
|
33
|
+
ev.data(Loggr::ExceptionData.format_exception(ex, request))
|
34
|
+
ev.datatype(DataType::HTML)
|
35
|
+
ev.source(source)
|
36
|
+
ev.geo_ip(ip)
|
37
|
+
return ev
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class DataType
|
42
|
+
HTML = 0
|
43
|
+
PLAINTEXT = 1
|
44
|
+
end
|
45
|
+
|
46
|
+
class Event
|
47
|
+
attr_accessor :text, :source, :link, :data, :value, :tags, :geo, :datatype
|
48
|
+
end
|
49
|
+
|
50
|
+
class FluentEvent
|
51
|
+
|
52
|
+
def initialize(callback=nil)
|
53
|
+
@callback = callback
|
54
|
+
@event = Event.new()
|
55
|
+
end
|
56
|
+
|
57
|
+
def post(async=true)
|
58
|
+
if !@callback.nil?
|
59
|
+
@callback.call(self)
|
60
|
+
end
|
61
|
+
client = LogClient.new()
|
62
|
+
client.post(@event, async)
|
63
|
+
end
|
64
|
+
|
65
|
+
def text(text)
|
66
|
+
@event.text = self.assign_w_macros(text, @event.text)
|
67
|
+
return self
|
68
|
+
end
|
69
|
+
|
70
|
+
def textf(fmt, *args)
|
71
|
+
self.text(sprintf(fmt, args))
|
72
|
+
return self
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_text(text)
|
76
|
+
@event.text = sprintf("%s%s", @event.text, text)
|
77
|
+
return self
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_textf(fmt, *args)
|
81
|
+
self.add_text(sprintf(fmt, args))
|
82
|
+
return self
|
83
|
+
end
|
84
|
+
|
85
|
+
def source(text)
|
86
|
+
@event.source = self.assign_w_macros(text, @event.source)
|
87
|
+
return self
|
88
|
+
end
|
89
|
+
|
90
|
+
def sourcef(fmt, *args)
|
91
|
+
self.source(sprintf(fmt, args))
|
92
|
+
end
|
93
|
+
|
94
|
+
def link(text)
|
95
|
+
@event.link = self.assign_w_macros(text, @event.link)
|
96
|
+
return self
|
97
|
+
end
|
98
|
+
|
99
|
+
def linkf(fmt, *args)
|
100
|
+
self.link(sprintf(fmt, args))
|
101
|
+
end
|
102
|
+
|
103
|
+
def data(text)
|
104
|
+
@event.data = self.assign_w_macros(text, @event.data)
|
105
|
+
return self
|
106
|
+
end
|
107
|
+
|
108
|
+
def dataf(fmt, *args)
|
109
|
+
self.data(sprintf(fmt, args))
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_data(text)
|
113
|
+
@event.data = sprintf("%s%s", @event.data, text)
|
114
|
+
return self
|
115
|
+
end
|
116
|
+
|
117
|
+
def add_dataf(fmt, *args)
|
118
|
+
self.add_data(sprintf(fmt, args))
|
119
|
+
return self
|
120
|
+
end
|
121
|
+
|
122
|
+
def value(val)
|
123
|
+
@event.value = val
|
124
|
+
return self
|
125
|
+
end
|
126
|
+
|
127
|
+
def value_clear()
|
128
|
+
@event.value = nil
|
129
|
+
return self
|
130
|
+
end
|
131
|
+
|
132
|
+
def tags(tags)
|
133
|
+
@event.tags = tags
|
134
|
+
return self
|
135
|
+
end
|
136
|
+
|
137
|
+
def add_tags(tags)
|
138
|
+
@event.tags = sprintf("%s %s", @event.tags, tags)
|
139
|
+
return self
|
140
|
+
end
|
141
|
+
|
142
|
+
def datatype(t)
|
143
|
+
@event.datatype = t
|
144
|
+
return self
|
145
|
+
end
|
146
|
+
|
147
|
+
def geo(lat, lon)
|
148
|
+
@event.geo = sprintf("%d,%d", lat, lon)
|
149
|
+
return self
|
150
|
+
end
|
151
|
+
|
152
|
+
def geo_ip(ip)
|
153
|
+
@event.geo = sprintf("ip:%s", ip)
|
154
|
+
return self
|
155
|
+
end
|
156
|
+
|
157
|
+
def geo_clear()
|
158
|
+
@event.geo = nil
|
159
|
+
return self
|
160
|
+
end
|
161
|
+
|
162
|
+
def assign_w_macros(input, base)
|
163
|
+
if base.nil?
|
164
|
+
base = ""
|
165
|
+
end
|
166
|
+
return input.gsub("$$", base)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Loggr
|
4
|
+
class ExceptionData
|
5
|
+
def self.format_exception(ex, request=nil)
|
6
|
+
res = ""
|
7
|
+
|
8
|
+
# basic info
|
9
|
+
res = res + sprintf("<b>Exception</b>: %s<br />", ex.message)
|
10
|
+
res = res + sprintf("<b>Type</b>: %s<br />", ex.class)
|
11
|
+
res = res + sprintf("<b>Machine</b>: %s<br />", get_hostname)
|
12
|
+
res = res + sprintf("<b>Language</b>: ruby %s<br />", language_version_string)
|
13
|
+
res = res + "<br />"
|
14
|
+
|
15
|
+
# web details
|
16
|
+
if !request.nil?
|
17
|
+
res = res + sprintf("<b>Request URL</b>: %s<br />", (request.respond_to?(:url) ? request.url : "#{request.protocol}#{request.host}#{request.request_uri}"))
|
18
|
+
res = res + sprintf("<b>User</b>: %s<br />", get_username)
|
19
|
+
res = res + sprintf("<b>User host address</b>: %s<br />", (request.respond_to?(:remote_ip) ? request.remote_ip : request.ip))
|
20
|
+
res = res + sprintf("<b>Request Method</b>: %s<br />", request.request_method.to_s)
|
21
|
+
res = res + sprintf("<b>User Agent</b>: %s<br />", request.env['HTTP_USER_AGENT'] || '')
|
22
|
+
res = res + sprintf("<b>Referer</b>: %s<br />", request.env['HTTP_REFERER'] || '')
|
23
|
+
res = res + sprintf("<b>Script Name</b>: %s<br />", request.env['SCRIPT_NAME'] || '')
|
24
|
+
res = res + "<br />"
|
25
|
+
end
|
26
|
+
|
27
|
+
# stack
|
28
|
+
res = res + "<b>Stack Trace</b><br />"
|
29
|
+
res = res + (ex.backtrace || []).join("<br/>")
|
30
|
+
|
31
|
+
return res
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.get_hostname
|
35
|
+
require 'socket' unless defined?(Socket)
|
36
|
+
Socket.gethostname
|
37
|
+
rescue
|
38
|
+
'UNKNOWN'
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.language_version_string
|
42
|
+
"#{RUBY_VERSION rescue '?.?.?'} p#{RUBY_PATCHLEVEL rescue '???'} #{RUBY_RELEASE_DATE rescue '????-??-??'} #{RUBY_PLATFORM rescue '????'}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.get_username
|
46
|
+
ENV['LOGNAME'] || ENV['USER'] || ENV['USERNAME'] || ENV['APACHE_RUN_USER'] || 'UNKNOWN'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Net
|
4
|
+
class HTTP < Protocol
|
5
|
+
# pasted first half of HTTP.request that writes the request to the server,
|
6
|
+
# does not return HTTPResponse and does not take a block
|
7
|
+
def request_async(req, body = nil)
|
8
|
+
if proxy_user()
|
9
|
+
unless use_ssl?
|
10
|
+
req.proxy_basic_auth proxy_user(), proxy_pass()
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
req.set_body_internal body
|
15
|
+
begin_transport req
|
16
|
+
req.exec @socket, @curr_http_version, edit_path(req.path)
|
17
|
+
end
|
18
|
+
|
19
|
+
# second half of HTTP.request that yields or returns the response
|
20
|
+
def read_response(req, body = nil, &block) # :yield: +response+
|
21
|
+
begin
|
22
|
+
res = HTTPResponse.read_new(@socket)
|
23
|
+
end while res.kind_of?(HTTPContinue)
|
24
|
+
res.reading_body(@socket, req.response_body_permitted?) {
|
25
|
+
yield res if block_given?
|
26
|
+
}
|
27
|
+
end_transport req, res
|
28
|
+
|
29
|
+
res
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
begin
|
2
|
+
class Delayed::Job
|
3
|
+
def log_exception_with_loggr(e)
|
4
|
+
Loggr.handle(e, "Delayed::Job #{self.name}")
|
5
|
+
log_exception_without_loggr(e)
|
6
|
+
Loggr.context.clear!
|
7
|
+
end
|
8
|
+
alias_method_chain :log_exception, :loggr
|
9
|
+
Loggr.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 Loggr
|
6
|
+
|
7
|
+
def initialize(app, api_key = nil)
|
8
|
+
@app = app
|
9
|
+
if api_key.nil?
|
10
|
+
loggr_config = "config/loggr.yml"
|
11
|
+
::Loggr::Config.load(loggr_config)
|
12
|
+
else
|
13
|
+
::Loggr.configure(api_key)
|
14
|
+
::Loggr::Config.enabled = true
|
15
|
+
::Loggr.logger.info "Enabling Loggr 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
|
+
::Loggr::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 RailsLoggr
|
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
|
+
::Loggr::Catcher.handle_with_controller(e,env['action_controller.instance'], Rack::Request.new(env))
|
16
|
+
raise
|
17
|
+
end
|
18
|
+
|
19
|
+
if env['rack.exception']
|
20
|
+
::Loggr::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_loggr(exception)
|
10
|
+
unless exception_handled_by_rescue_from?(exception)
|
11
|
+
Loggr::Catcher.handle_with_controller(exception, self, request)
|
12
|
+
Loggr.context.clear!
|
13
|
+
end
|
14
|
+
rescue_action_without_loggr exception
|
15
|
+
end
|
16
|
+
|
17
|
+
alias_method :rescue_action_without_loggr, :rescue_action
|
18
|
+
alias_method :rescue_action, :rescue_action_with_loggr
|
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,13 @@
|
|
1
|
+
module Loggr
|
2
|
+
module Integration
|
3
|
+
class LoggrTestException <StandardError;
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.test
|
7
|
+
Loggr::Events.create().text("Test event").tags("test").source("loggr-rb-#{Loggr::VERSION}").post()
|
8
|
+
puts "Test Event sent. Please login to http://loggr.net to see it!"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'loggr-rb/http'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module Loggr
|
5
|
+
class LogClient
|
6
|
+
def post(e, async=true)
|
7
|
+
logkey = ::Loggr::Config.log_key
|
8
|
+
if async == true
|
9
|
+
call_remote_async("post.loggr.net", "/1/logs/#{logkey}/events", create_params(e))
|
10
|
+
else
|
11
|
+
call_remote("post.loggr.net", "/1/logs/#{logkey}/events", create_params(e))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_params(e)
|
16
|
+
apikey = ::Loggr::Config.api_key
|
17
|
+
params = {"apikey" => apikey, "text" => e.text}
|
18
|
+
params = params.merge({"link" => e.link}) if !e.link.nil?
|
19
|
+
params = params.merge({"tags" => e.tags}) if !e.tags.nil?
|
20
|
+
params = params.merge({"source" => e.source}) if !e.source.nil?
|
21
|
+
params = params.merge({"geo" => e.geo}) if !e.geo.nil?
|
22
|
+
params = params.merge({"value" => e.value}) if !e.value.nil?
|
23
|
+
if e.datatype == DataType::HTML
|
24
|
+
params = params.merge({"data" => sprintf("@html\r\n%s", e.data)}) if !e.data.nil?
|
25
|
+
else
|
26
|
+
params = params.merge({"data" => e.data}) if !e.data.nil?
|
27
|
+
end
|
28
|
+
return params
|
29
|
+
end
|
30
|
+
|
31
|
+
def call_remote(host, path, params)
|
32
|
+
http = Net::HTTP.new(host)
|
33
|
+
req = Net::HTTP::Get.new(path)
|
34
|
+
data = params.collect { |k, v| "#{k}=#{v}&" }.join
|
35
|
+
http.start
|
36
|
+
begin
|
37
|
+
http.request_async(req, data)
|
38
|
+
res = http.read_response(req)
|
39
|
+
rescue Exception => e
|
40
|
+
Loggr.logger.error('Problem notifying Loggr about the event')
|
41
|
+
Loggr.logger.error(e)
|
42
|
+
ensure
|
43
|
+
http.finish
|
44
|
+
end
|
45
|
+
res.value # raise if error
|
46
|
+
end
|
47
|
+
|
48
|
+
def call_remote_async(host, path, params)
|
49
|
+
http = Net::HTTP.new(host)
|
50
|
+
req = Net::HTTP::Get.new(path)
|
51
|
+
data = params.collect { |k, v| "#{k}=#{v}&" }.join
|
52
|
+
http.start
|
53
|
+
begin
|
54
|
+
http.request_async(req, data)
|
55
|
+
rescue Exception => e
|
56
|
+
Loggr.logger.error('Problem notifying Loggr about the event')
|
57
|
+
Loggr.logger.error(e)
|
58
|
+
ensure
|
59
|
+
http.finish
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Loggr
|
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, "/loggr.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
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'loggr-rb'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
module Loggr
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
|
7
|
+
initializer "loggr.middleware" do |app|
|
8
|
+
|
9
|
+
config_file = File.join(Rails.root, "/config/loggr.yml")
|
10
|
+
Loggr::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 Loggr::Config.should_send_to_api?
|
14
|
+
Loggr.logger.info("Loading Loggr #{Loggr::VERSION} for #{Rails::VERSION::STRING}")
|
15
|
+
app.config.middleware.use "Rack::RailsLoggr"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
namespace :exceptional do
|
2
|
+
desc 'Send a test exception to Exceptional.'
|
3
|
+
task :test => :environment do
|
4
|
+
unless Exceptional::Config.api_key.blank?
|
5
|
+
puts "Sending test exception to Exceptional."
|
6
|
+
require "exceptional/integration/tester"
|
7
|
+
Exceptional::Integration.test
|
8
|
+
puts "Done."
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
namespace :loggr do
|
2
|
+
desc 'Send a test event to Loggr.'
|
3
|
+
task :test => :environment do
|
4
|
+
unless Loggr::Config.api_key.blank?
|
5
|
+
puts "Sending test exception to Loggr."
|
6
|
+
require "loggr-rb/integration/tester"
|
7
|
+
Loggr::Integration.test
|
8
|
+
puts "Done."
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/loggr-rb.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/loggr-rb/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = %q{loggr-rb}
|
6
|
+
gem.version = Loggr::VERSION
|
7
|
+
gem.authors = ["Loggr.net"]
|
8
|
+
gem.summary = %q{ loggr.net is a hosted service for logging events in your Ruby/Rails/Rack apps }
|
9
|
+
gem.description = %q{loggr-rb is the Ruby gem for communicating with http://loggr.net (hosted logging service).}
|
10
|
+
gem.email = %q{info@loggr.net}
|
11
|
+
gem.files = Dir['lib/**/*'] + Dir['rails/**/*'] + Dir['tasks/**/*'] + Dir['*.rb'] + ["loggr-rb.gemspec"]
|
12
|
+
gem.homepage = %q{http://loggr.net/}
|
13
|
+
gem.require_paths = ["lib"]
|
14
|
+
gem.executables << 'loggr'
|
15
|
+
gem.requirements << ""
|
16
|
+
gem.add_dependency 'rack'
|
17
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__) , '../init.rb')
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: loggr-rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 5
|
9
|
+
version: 1.0.5
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Loggr.net
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-07-23 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rack
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
description: loggr-rb is the Ruby gem for communicating with http://loggr.net (hosted logging service).
|
33
|
+
email: info@loggr.net
|
34
|
+
executables:
|
35
|
+
- loggr
|
36
|
+
extensions: []
|
37
|
+
|
38
|
+
extra_rdoc_files: []
|
39
|
+
|
40
|
+
files:
|
41
|
+
- lib/loggr-rb.rb
|
42
|
+
- lib/loggr-rb/integration/tester.rb
|
43
|
+
- lib/loggr-rb/integration/dj.rb
|
44
|
+
- lib/loggr-rb/integration/rails.rb
|
45
|
+
- lib/loggr-rb/integration/sinatra.rb
|
46
|
+
- lib/loggr-rb/integration/rack_rails.rb
|
47
|
+
- lib/loggr-rb/integration/rack.rb
|
48
|
+
- lib/loggr-rb/config.rb
|
49
|
+
- lib/loggr-rb/version.rb
|
50
|
+
- lib/loggr-rb/logclient.rb
|
51
|
+
- lib/loggr-rb/logfactory.rb
|
52
|
+
- lib/loggr-rb/exceptiondata.rb
|
53
|
+
- lib/loggr-rb/railtie.rb
|
54
|
+
- lib/loggr-rb/events.rb
|
55
|
+
- lib/loggr-rb/http.rb
|
56
|
+
- lib/loggr-rb/catcher.rb
|
57
|
+
- lib/tasks/loggr_tasks.rake
|
58
|
+
- lib/tasks/exceptional_tasks.rake
|
59
|
+
- rails/init.rb
|
60
|
+
- init.rb
|
61
|
+
- install.rb
|
62
|
+
- loggr-rb.gemspec
|
63
|
+
has_rdoc: true
|
64
|
+
homepage: http://loggr.net/
|
65
|
+
licenses: []
|
66
|
+
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
version: "0"
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
segments:
|
84
|
+
- 0
|
85
|
+
version: "0"
|
86
|
+
requirements:
|
87
|
+
- ""
|
88
|
+
rubyforge_project:
|
89
|
+
rubygems_version: 1.3.6
|
90
|
+
signing_key:
|
91
|
+
specification_version: 3
|
92
|
+
summary: loggr.net is a hosted service for logging events in your Ruby/Rails/Rack apps
|
93
|
+
test_files: []
|
94
|
+
|