loggr-rb 1.0.5
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/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
|
+
|