logstasher 0.7.1 → 0.8.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.
- checksums.yaml +4 -4
- data/lib/logstasher.rb +70 -33
- data/lib/logstasher/action_view/log_subscriber.rb +70 -0
- data/lib/logstasher/active_record/log_subscriber.rb +59 -0
- data/lib/logstasher/active_support/log_subscriber.rb +106 -0
- data/lib/logstasher/active_support/mailer_log_subscriber.rb +37 -0
- data/lib/logstasher/delayed/plugin.rb +16 -0
- data/lib/logstasher/rails_ext/action_controller/base.rb +48 -0
- data/lib/logstasher/rails_ext/action_controller/metal/instrumentation.rb +2 -0
- data/lib/logstasher/railtie.rb +9 -2
- data/lib/logstasher/version.rb +1 -1
- metadata +36 -3
- data/lib/logstasher/log_subscriber.rb +0 -132
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdbb1f20cf68e8fbe11c54a8f036a4306e3ea298
|
4
|
+
data.tar.gz: 13fe5a49bece9ce24864711ab9998e02305d9490
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6e0170213a368025a4ec1bc04ce682ed31827006288c28f003cfa469945706017f189f353e35e72310bdc7a78807049b9e4dca38fa0cd80396a7568f1b72176
|
7
|
+
data.tar.gz: d36293ed895eac912267708acb408e30815793689cb9f8ef4be78e4c6808ee58e3ef31f6ace71bce7aed61b91ff5735fc650a37a3fd8475f8c0433b07372f9e3
|
data/lib/logstasher.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
require 'logstasher/version'
|
2
|
-
require 'logstasher/log_subscriber'
|
2
|
+
require 'logstasher/active_support/log_subscriber'
|
3
|
+
require 'logstasher/active_support/mailer_log_subscriber'
|
4
|
+
require 'logstasher/active_record/log_subscriber'
|
5
|
+
require 'logstasher/action_view/log_subscriber'
|
6
|
+
require 'logstasher/rails_ext/action_controller/base'
|
3
7
|
require 'request_store'
|
4
8
|
require 'active_support/core_ext/module/attribute_accessors'
|
5
9
|
require 'active_support/core_ext/string/inflections'
|
@@ -10,14 +14,15 @@ module LogStasher
|
|
10
14
|
STORE_KEY = :logstasher_data
|
11
15
|
REQUEST_CONTEXT_KEY = :logstasher_request_context
|
12
16
|
|
13
|
-
attr_accessor :logger, :logger_path, :enabled, :log_controller_parameters, :source, :backtrace
|
17
|
+
attr_accessor :logger, :logger_path, :enabled, :log_controller_parameters, :source, :backtrace,
|
18
|
+
:delayed_jobs_support, :controller_monkey_patch
|
14
19
|
# Setting the default to 'unknown' to define the default behaviour
|
15
20
|
@source = 'unknown'
|
16
21
|
# By default log the backtrace of exceptions
|
17
22
|
@backtrace = true
|
18
23
|
|
19
24
|
def remove_existing_log_subscriptions
|
20
|
-
ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber|
|
25
|
+
::ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber|
|
21
26
|
case subscriber.class.name
|
22
27
|
when 'ActionView::LogSubscriber'
|
23
28
|
unsubscribe(:action_view, subscriber)
|
@@ -32,9 +37,9 @@ module LogStasher
|
|
32
37
|
def unsubscribe(component, subscriber)
|
33
38
|
events = subscriber.public_methods(false).reject{ |method| method.to_s == 'call' }
|
34
39
|
events.each do |event|
|
35
|
-
ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
|
40
|
+
::ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
|
36
41
|
if listener.instance_variable_get('@delegate') == subscriber
|
37
|
-
ActiveSupport::Notifications.unsubscribe listener
|
42
|
+
::ActiveSupport::Notifications.unsubscribe listener
|
38
43
|
end
|
39
44
|
end
|
40
45
|
end
|
@@ -46,7 +51,7 @@ module LogStasher
|
|
46
51
|
payload[:request_id] = request.env['action_dispatch.request_id']
|
47
52
|
self.custom_fields += [:ip, :route, :request_id]
|
48
53
|
if self.log_controller_parameters
|
49
|
-
payload[:parameters] = payload[:params].except(
|
54
|
+
payload[:parameters] = payload[:params].except(*::ActionController::LogSubscriber::INTERNAL_PARAMS)
|
50
55
|
self.custom_fields += [:parameters]
|
51
56
|
end
|
52
57
|
end
|
@@ -56,8 +61,8 @@ module LogStasher
|
|
56
61
|
LogStasher.custom_fields.concat(LogStasher.store.keys)
|
57
62
|
instance_exec(fields, &block)
|
58
63
|
end
|
59
|
-
ActionController::Metal.send(:define_method, :logtasher_add_custom_fields_to_payload, &wrapped_block)
|
60
|
-
ActionController::Base.send(:define_method, :logtasher_add_custom_fields_to_payload, &wrapped_block)
|
64
|
+
::ActionController::Metal.send(:define_method, :logtasher_add_custom_fields_to_payload, &wrapped_block)
|
65
|
+
::ActionController::Base.send(:define_method, :logtasher_add_custom_fields_to_payload, &wrapped_block)
|
61
66
|
end
|
62
67
|
|
63
68
|
def add_custom_fields_to_request_context(&block)
|
@@ -65,8 +70,8 @@ module LogStasher
|
|
65
70
|
instance_exec(fields, &block)
|
66
71
|
LogStasher.custom_fields.concat(fields.keys)
|
67
72
|
end
|
68
|
-
ActionController::Metal.send(:define_method, :logstasher_add_custom_fields_to_request_context, &wrapped_block)
|
69
|
-
ActionController::Base.send(:define_method, :logstasher_add_custom_fields_to_request_context, &wrapped_block)
|
73
|
+
::ActionController::Metal.send(:define_method, :logstasher_add_custom_fields_to_request_context, &wrapped_block)
|
74
|
+
::ActionController::Base.send(:define_method, :logstasher_add_custom_fields_to_request_context, &wrapped_block)
|
70
75
|
end
|
71
76
|
|
72
77
|
def add_default_fields_to_request_context(request)
|
@@ -77,33 +82,65 @@ module LogStasher
|
|
77
82
|
request_context.clear
|
78
83
|
end
|
79
84
|
|
80
|
-
def
|
81
|
-
app.config.action_dispatch.rack_cache[:verbose] = false if app.config.action_dispatch.rack_cache
|
82
|
-
# Path instrumentation class to insert our hook
|
83
|
-
require 'logstasher/rails_ext/action_controller/metal/instrumentation'
|
85
|
+
def setup_before(config)
|
84
86
|
require 'logstash-event'
|
85
|
-
self.
|
86
|
-
LogStasher::
|
87
|
-
LogStasher::MailerLogSubscriber.attach_to :action_mailer
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
87
|
+
self.enabled = config.enabled
|
88
|
+
LogStasher::ActiveSupport::LogSubscriber.attach_to :action_controller
|
89
|
+
LogStasher::ActiveSupport::MailerLogSubscriber.attach_to :action_mailer
|
90
|
+
LogStasher::ActiveRecord::LogSubscriber.attach_to :active_record
|
91
|
+
LogStasher::ActionView::LogSubscriber.attach_to :action_view
|
92
|
+
end
|
93
|
+
|
94
|
+
def setup(config)
|
95
|
+
# Path instrumentation class to insert our hook
|
96
|
+
if (! config.controller_monkey_patch && config.controller_monkey_patch != false) || config.controller_monkey_patch == true
|
97
|
+
require 'logstasher/rails_ext/action_controller/metal/instrumentation'
|
98
|
+
end
|
99
|
+
self.delayed_plugin(config)
|
100
|
+
self.suppress_app_logs(config)
|
101
|
+
self.logger_path = config.logger_path || "#{Rails.root}/log/logstash_#{Rails.env}.log"
|
102
|
+
self.logger = config.logger || new_logger(self.logger_path)
|
103
|
+
self.logger.level = config.log_level || Logger::WARN
|
104
|
+
self.source = config.source unless config.source.nil?
|
105
|
+
self.log_controller_parameters = !! config.log_controller_parameters
|
106
|
+
self.backtrace = !! config.backtrace unless config.backtrace.nil?
|
107
|
+
self.set_data_for_rake
|
108
|
+
self.set_data_for_console
|
109
|
+
end
|
110
|
+
|
111
|
+
def set_data_for_rake
|
112
|
+
self.request_context['request_id'] = ::Rake.application.top_level_tasks if self.called_as_rake?
|
113
|
+
end
|
114
|
+
|
115
|
+
def set_data_for_console
|
116
|
+
self.request_context['request_id'] = "#{Process.pid}" if self.called_as_console?
|
117
|
+
end
|
118
|
+
|
119
|
+
def called_as_rake?
|
120
|
+
File.basename($0) == 'rake'
|
121
|
+
end
|
122
|
+
|
123
|
+
def called_as_console?
|
124
|
+
defined?(Rails::Console) && true || false
|
125
|
+
end
|
126
|
+
|
127
|
+
def delayed_plugin(config)
|
128
|
+
if config.delayed_jobs_support || false
|
129
|
+
require 'logstasher/delayed/plugin'
|
130
|
+
::Delayed::Worker.plugins << ::LogStasher::Delayed::Plugin
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def suppress_app_logs(config)
|
135
|
+
if configured_to_suppress_app_logs?(config)
|
99
136
|
require 'logstasher/rails_ext/rack/logger'
|
100
137
|
LogStasher.remove_existing_log_subscriptions
|
101
138
|
end
|
102
139
|
end
|
103
140
|
|
104
|
-
def configured_to_suppress_app_logs?(
|
141
|
+
def configured_to_suppress_app_logs?(config)
|
105
142
|
# This supports both spellings: "suppress_app_log" and "supress_app_log"
|
106
|
-
!!(
|
143
|
+
!!(config.suppress_app_log.nil? ? config.supress_app_log : config.suppress_app_log)
|
107
144
|
end
|
108
145
|
|
109
146
|
def custom_fields
|
@@ -127,7 +164,7 @@ module LogStasher
|
|
127
164
|
end
|
128
165
|
|
129
166
|
def build_logstash_event(data, tags)
|
130
|
-
LogStash::Event.new(data.merge('source' => self.source, 'tags' => tags))
|
167
|
+
::LogStash::Event.new(data.merge('source' => self.source, 'tags' => tags))
|
131
168
|
end
|
132
169
|
|
133
170
|
def store
|
@@ -144,7 +181,7 @@ module LogStasher
|
|
144
181
|
|
145
182
|
def watch(event, opts = {}, &block)
|
146
183
|
event_group = opts[:event_group] || event
|
147
|
-
ActiveSupport::Notifications.subscribe(event) do |*args|
|
184
|
+
::ActiveSupport::Notifications.subscribe(event) do |*args|
|
148
185
|
# Calling the processing block with the Notification args and the store
|
149
186
|
block.call(*args, store[event_group])
|
150
187
|
end
|
@@ -159,7 +196,7 @@ module LogStasher
|
|
159
196
|
end
|
160
197
|
|
161
198
|
def enabled?
|
162
|
-
self.enabled
|
199
|
+
self.enabled || false
|
163
200
|
end
|
164
201
|
|
165
202
|
private
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'active_support/notifications'
|
2
|
+
require 'action_view/log_subscriber'
|
3
|
+
|
4
|
+
module LogStasher
|
5
|
+
module ActionView
|
6
|
+
class LogSubscriber < ::ActionView::LogSubscriber
|
7
|
+
def render_template(event)
|
8
|
+
logstash_event(event)
|
9
|
+
end
|
10
|
+
alias :render_partial :render_template
|
11
|
+
alias :render_collection :render_template
|
12
|
+
|
13
|
+
def logger
|
14
|
+
LogStasher.logger
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def logstash_event(event)
|
20
|
+
data = event.payload
|
21
|
+
|
22
|
+
data.merge! event_data(event)
|
23
|
+
data.merge! runtimes(event)
|
24
|
+
data.merge! extract_data(data)
|
25
|
+
data.merge! request_context
|
26
|
+
# data.merge! store
|
27
|
+
data.merge! extract_custom_fields(data)
|
28
|
+
|
29
|
+
tags = []
|
30
|
+
tags.push('exception') if data[:exception]
|
31
|
+
logger << LogStasher.build_logstash_event(data, tags).to_json + "\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
def extract_data(data)
|
35
|
+
{ identifier: from_rails_root(data[:identifier]) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def request_context
|
39
|
+
LogStasher.request_context
|
40
|
+
end
|
41
|
+
|
42
|
+
def store
|
43
|
+
LogStasher.store
|
44
|
+
end
|
45
|
+
|
46
|
+
def event_data(event)
|
47
|
+
{
|
48
|
+
name: event.name,
|
49
|
+
transaction_id: event.transaction_id,
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def runtimes(event)
|
54
|
+
{
|
55
|
+
duration: event.duration,
|
56
|
+
}.inject({}) do |runtimes, (name, runtime)|
|
57
|
+
runtimes[name] = runtime.to_f.round(2) if runtime
|
58
|
+
runtimes
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
def extract_custom_fields(data)
|
64
|
+
custom_fields = (!LogStasher.custom_fields.empty? && data.extract!(*LogStasher.custom_fields)) || {}
|
65
|
+
LogStasher.custom_fields.clear
|
66
|
+
custom_fields
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'active_support/notifications'
|
2
|
+
require 'active_record/log_subscriber'
|
3
|
+
|
4
|
+
module LogStasher
|
5
|
+
module ActiveRecord
|
6
|
+
class LogSubscriber < ::ActiveRecord::LogSubscriber
|
7
|
+
def identity(event)
|
8
|
+
if logger
|
9
|
+
logger << logstash_event(event).to_json + "\n"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
alias :sql :identity
|
13
|
+
|
14
|
+
def logger
|
15
|
+
LogStasher.logger
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def logstash_event(event)
|
21
|
+
data = event.payload
|
22
|
+
|
23
|
+
return unless logger.debug?
|
24
|
+
return if 'SCHEMA' == data[:name]
|
25
|
+
|
26
|
+
data.merge! runtimes(event)
|
27
|
+
data.merge! extract_sql(data)
|
28
|
+
data.merge! request_context
|
29
|
+
data.merge! extract_custom_fields(data)
|
30
|
+
|
31
|
+
tags = ['request']
|
32
|
+
tags.push('exception') if payload[:exception]
|
33
|
+
LogStasher.build_logstash_event(data, tags)
|
34
|
+
end
|
35
|
+
|
36
|
+
def request_context
|
37
|
+
LogStasher.request_context
|
38
|
+
end
|
39
|
+
|
40
|
+
def runtimes(event)
|
41
|
+
if event.duration
|
42
|
+
{ duration: event.duration.to_f.round(2) }
|
43
|
+
else
|
44
|
+
{ }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def extract_sql(data)
|
49
|
+
{ sql: data[:sql].squeeze(' ') }
|
50
|
+
end
|
51
|
+
|
52
|
+
def extract_custom_fields(data)
|
53
|
+
custom_fields = (!LogStasher.custom_fields.empty? && data.extract!(*LogStasher.custom_fields)) || {}
|
54
|
+
LogStasher.custom_fields.clear
|
55
|
+
custom_fields
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
2
|
+
require 'active_support/log_subscriber'
|
3
|
+
|
4
|
+
module LogStasher
|
5
|
+
module ActiveSupport
|
6
|
+
class LogSubscriber < ::ActiveSupport::LogSubscriber
|
7
|
+
def process_action(event)
|
8
|
+
payload = event.payload
|
9
|
+
|
10
|
+
data = extract_request(payload)
|
11
|
+
data.merge! extract_status(payload)
|
12
|
+
data.merge! runtimes(event)
|
13
|
+
data.merge! location(event)
|
14
|
+
data.merge! extract_exception(payload)
|
15
|
+
data.merge! extract_custom_fields(payload)
|
16
|
+
|
17
|
+
tags = ['request']
|
18
|
+
tags.push('exception') if payload[:exception]
|
19
|
+
logger << LogStasher.build_logstash_event(data, tags).to_json + "\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
def redirect_to(event)
|
23
|
+
Thread.current[:logstasher_location] = event.payload[:location]
|
24
|
+
end
|
25
|
+
|
26
|
+
def logger
|
27
|
+
LogStasher.logger
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def extract_request(payload)
|
33
|
+
{
|
34
|
+
method: payload[:method],
|
35
|
+
path: extract_path(payload),
|
36
|
+
format: extract_format(payload),
|
37
|
+
controller: payload[:params]['controller'],
|
38
|
+
action: payload[:params]['action']
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def extract_path(payload)
|
43
|
+
payload[:path].split("?").first
|
44
|
+
end
|
45
|
+
|
46
|
+
def extract_format(payload)
|
47
|
+
if ::ActionPack::VERSION::MAJOR == 3 && ::ActionPack::VERSION::MINOR == 0
|
48
|
+
payload[:formats].first
|
49
|
+
else
|
50
|
+
payload[:format]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def extract_status(payload)
|
55
|
+
if payload[:status]
|
56
|
+
{ :status => payload[:status].to_i }
|
57
|
+
else
|
58
|
+
{ :status => 0 }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def runtimes(event)
|
63
|
+
{
|
64
|
+
:duration => event.duration,
|
65
|
+
:view => event.payload[:view_runtime],
|
66
|
+
:db => event.payload[:db_runtime]
|
67
|
+
}.inject({}) do |runtimes, (name, runtime)|
|
68
|
+
runtimes[name] = runtime.to_f.round(2) if runtime
|
69
|
+
runtimes
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def location(event)
|
74
|
+
if location = Thread.current[:logstasher_location]
|
75
|
+
Thread.current[:logstasher_location] = nil
|
76
|
+
{ :location => location }
|
77
|
+
else
|
78
|
+
{}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Monkey patching to enable exception logging
|
83
|
+
def extract_exception(payload)
|
84
|
+
if payload[:exception]
|
85
|
+
exception, message = payload[:exception]
|
86
|
+
status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception)
|
87
|
+
if LogStasher.backtrace
|
88
|
+
backtrace = $!.backtrace.join("\n")
|
89
|
+
else
|
90
|
+
backtrace = $!.backtrace.first
|
91
|
+
end
|
92
|
+
message = "#{exception}\n#{message}\n#{backtrace}"
|
93
|
+
{ :status => status, :error => message }
|
94
|
+
else
|
95
|
+
{}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def extract_custom_fields(payload)
|
100
|
+
custom_fields = (!LogStasher.custom_fields.empty? && payload.extract!(*LogStasher.custom_fields)) || {}
|
101
|
+
LogStasher.custom_fields.clear
|
102
|
+
custom_fields
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
2
|
+
require 'active_support/log_subscriber'
|
3
|
+
|
4
|
+
module LogStasher
|
5
|
+
module ActiveSupport
|
6
|
+
class MailerLogSubscriber < ::ActiveSupport::LogSubscriber
|
7
|
+
MAILER_FIELDS = [:mailer, :action, :message_id, :from, :to]
|
8
|
+
|
9
|
+
def deliver(event)
|
10
|
+
process_event(event, ['mailer', 'deliver'])
|
11
|
+
end
|
12
|
+
|
13
|
+
def receive(event)
|
14
|
+
process_event(event, ['mailer', 'receive'])
|
15
|
+
end
|
16
|
+
|
17
|
+
def process(event)
|
18
|
+
process_event(event, ['mailer', 'process'])
|
19
|
+
end
|
20
|
+
|
21
|
+
def logger
|
22
|
+
LogStasher.logger
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def process_event(event, tags)
|
28
|
+
data = LogStasher.request_context.merge(extract_metadata(event.payload))
|
29
|
+
logger << LogStasher.build_logstash_event(data, tags).to_json + "\n"
|
30
|
+
end
|
31
|
+
|
32
|
+
def extract_metadata(payload)
|
33
|
+
payload.slice(*MAILER_FIELDS)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'delayed_job'
|
2
|
+
module LogStasher
|
3
|
+
module Delayed
|
4
|
+
class Plugin < ::Delayed::Plugin
|
5
|
+
callbacks do |lifecycle|
|
6
|
+
lifecycle.before(:invoke_job) do |job, *args, &block|
|
7
|
+
::LogStasher.request_context[:request_id] = job.id
|
8
|
+
# perhaps handler#object.first_line and method_name would be interesting too (in store??)
|
9
|
+
end
|
10
|
+
lifecycle.after(:invoke_job) do |job, *args, &block|
|
11
|
+
::LogStasher.request_context[:request_id] = nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module LogStasher
|
2
|
+
module ActionController
|
3
|
+
module Instrumentation
|
4
|
+
def process_action(*args)
|
5
|
+
add_custom_fields_to_store
|
6
|
+
LogStasher.clear_request_context
|
7
|
+
LogStasher.add_default_fields_to_request_context(request)
|
8
|
+
|
9
|
+
super(*args)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# this method is called from within super of process_action.
|
15
|
+
def append_info_to_payload(payload) #:nodoc:
|
16
|
+
LogStasher.add_default_fields_to_payload(payload, request)
|
17
|
+
if self.respond_to?(:logstasher_add_custom_fields_to_request_context)
|
18
|
+
logstasher_add_custom_fields_to_request_context(LogStasher.request_context)
|
19
|
+
end
|
20
|
+
|
21
|
+
if self.respond_to?(:logtasher_add_custom_fields_to_payload)
|
22
|
+
before_keys = payload.keys.clone
|
23
|
+
logtasher_add_custom_fields_to_payload(payload)
|
24
|
+
after_keys = payload.keys
|
25
|
+
# Store all extra keys added to payload hash in payload itself. This is a thread safe way
|
26
|
+
LogStasher.custom_fields += after_keys - before_keys
|
27
|
+
end
|
28
|
+
|
29
|
+
payload[:status] = response.status
|
30
|
+
super(payload)
|
31
|
+
|
32
|
+
LogStasher.store.each do |key, value|
|
33
|
+
payload[key] = value
|
34
|
+
end
|
35
|
+
|
36
|
+
LogStasher.request_context.each do |key, value|
|
37
|
+
payload[key] = value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_custom_fields_to_store
|
42
|
+
LogStasher.store[:ip] = request.remote_ip
|
43
|
+
LogStasher.store[:route] = "#{request.params[:controller]}##{request.params[:action]}"
|
44
|
+
LogStasher.request_context[:request_id] = request.env['action_dispatch.request_id']
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module ActionController
|
2
2
|
module Instrumentation
|
3
|
+
alias :orig_process_action :process_action
|
3
4
|
def process_action(*args)
|
4
5
|
raw_payload = {
|
5
6
|
:controller => self.class.name,
|
@@ -44,6 +45,7 @@ module ActionController
|
|
44
45
|
result
|
45
46
|
end
|
46
47
|
end
|
48
|
+
alias :logstasher_process_action :process_action
|
47
49
|
|
48
50
|
end
|
49
51
|
end
|
data/lib/logstasher/railtie.rb
CHANGED
@@ -4,11 +4,18 @@ require 'action_controller/log_subscriber'
|
|
4
4
|
|
5
5
|
module LogStasher
|
6
6
|
class Railtie < Rails::Railtie
|
7
|
-
config.logstasher = ActiveSupport::OrderedOptions.new
|
7
|
+
config.logstasher = ::ActiveSupport::OrderedOptions.new
|
8
8
|
config.logstasher.enabled = false
|
9
9
|
|
10
10
|
initializer :logstasher, :before => :load_config_initializers do |app|
|
11
|
-
|
11
|
+
app.config.action_dispatch.rack_cache[:verbose] = false if app.config.action_dispatch.rack_cache
|
12
|
+
LogStasher.setup_before(app.config.logstasher) if app.config.logstasher.enabled
|
13
|
+
end
|
14
|
+
|
15
|
+
initializer :logstasher do
|
16
|
+
config.after_initialize do
|
17
|
+
LogStasher.setup(config.logstasher) if config.logstasher.enabled
|
18
|
+
end
|
12
19
|
end
|
13
20
|
end
|
14
21
|
end
|
data/lib/logstasher/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstasher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shadab Ahmed
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logstash-event
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: delayed_job
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 4.0.2
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 4.0.2
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: request_store
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +66,20 @@ dependencies:
|
|
52
66
|
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: activerecord
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: rspec
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,8 +130,13 @@ extensions: []
|
|
102
130
|
extra_rdoc_files: []
|
103
131
|
files:
|
104
132
|
- lib/logstasher.rb
|
133
|
+
- lib/logstasher/action_view/log_subscriber.rb
|
134
|
+
- lib/logstasher/active_record/log_subscriber.rb
|
135
|
+
- lib/logstasher/active_support/log_subscriber.rb
|
136
|
+
- lib/logstasher/active_support/mailer_log_subscriber.rb
|
137
|
+
- lib/logstasher/delayed/plugin.rb
|
105
138
|
- lib/logstasher/device/redis.rb
|
106
|
-
- lib/logstasher/
|
139
|
+
- lib/logstasher/rails_ext/action_controller/base.rb
|
107
140
|
- lib/logstasher/rails_ext/action_controller/metal/instrumentation.rb
|
108
141
|
- lib/logstasher/rails_ext/rack/logger.rb
|
109
142
|
- lib/logstasher/railtie.rb
|
@@ -1,132 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/class/attribute'
|
2
|
-
require 'active_support/log_subscriber'
|
3
|
-
|
4
|
-
module LogStasher
|
5
|
-
class RequestLogSubscriber < ActiveSupport::LogSubscriber
|
6
|
-
def process_action(event)
|
7
|
-
payload = event.payload
|
8
|
-
|
9
|
-
data = extract_request(payload)
|
10
|
-
data.merge! extract_status(payload)
|
11
|
-
data.merge! runtimes(event)
|
12
|
-
data.merge! location(event)
|
13
|
-
data.merge! extract_exception(payload)
|
14
|
-
data.merge! extract_custom_fields(payload)
|
15
|
-
|
16
|
-
tags = ['request']
|
17
|
-
tags.push('exception') if payload[:exception]
|
18
|
-
|
19
|
-
LogStasher.logger << LogStasher.build_logstash_event(data, tags).to_json + "\n"
|
20
|
-
end
|
21
|
-
|
22
|
-
def redirect_to(event)
|
23
|
-
Thread.current[:logstasher_location] = event.payload[:location]
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def extract_request(payload)
|
29
|
-
{
|
30
|
-
:method => payload[:method],
|
31
|
-
:path => extract_path(payload),
|
32
|
-
:format => extract_format(payload),
|
33
|
-
:controller => payload[:params]['controller'],
|
34
|
-
:action => payload[:params]['action']
|
35
|
-
}
|
36
|
-
end
|
37
|
-
|
38
|
-
def extract_path(payload)
|
39
|
-
payload[:path].split("?").first
|
40
|
-
end
|
41
|
-
|
42
|
-
def extract_format(payload)
|
43
|
-
if ::ActionPack::VERSION::MAJOR == 3 && ::ActionPack::VERSION::MINOR == 0
|
44
|
-
payload[:formats].first
|
45
|
-
else
|
46
|
-
payload[:format]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def extract_status(payload)
|
51
|
-
if payload[:status]
|
52
|
-
{ :status => payload[:status].to_i }
|
53
|
-
else
|
54
|
-
{ :status => 0 }
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def runtimes(event)
|
59
|
-
{
|
60
|
-
:duration => event.duration,
|
61
|
-
:view => event.payload[:view_runtime],
|
62
|
-
:db => event.payload[:db_runtime]
|
63
|
-
}.inject({}) do |runtimes, (name, runtime)|
|
64
|
-
runtimes[name] = runtime.to_f.round(2) if runtime
|
65
|
-
runtimes
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def location(event)
|
70
|
-
if location = Thread.current[:logstasher_location]
|
71
|
-
Thread.current[:logstasher_location] = nil
|
72
|
-
{ :location => location }
|
73
|
-
else
|
74
|
-
{}
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# Monkey patching to enable exception logging
|
79
|
-
def extract_exception(payload)
|
80
|
-
if payload[:exception]
|
81
|
-
exception, message = payload[:exception]
|
82
|
-
status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception)
|
83
|
-
if LogStasher.backtrace
|
84
|
-
backtrace = $!.backtrace.join("\n")
|
85
|
-
else
|
86
|
-
backtrace = $!.backtrace.first
|
87
|
-
end
|
88
|
-
message = "#{exception}\n#{message}\n#{backtrace}"
|
89
|
-
{ :status => status, :error => message }
|
90
|
-
else
|
91
|
-
{}
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def extract_custom_fields(payload)
|
96
|
-
custom_fields = (!LogStasher.custom_fields.empty? && payload.extract!(*LogStasher.custom_fields)) || {}
|
97
|
-
LogStasher.custom_fields.clear
|
98
|
-
custom_fields
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
class MailerLogSubscriber < ActiveSupport::LogSubscriber
|
103
|
-
MAILER_FIELDS = [:mailer, :action, :message_id, :from, :to]
|
104
|
-
|
105
|
-
def deliver(event)
|
106
|
-
process_event(event, ['mailer', 'deliver'])
|
107
|
-
end
|
108
|
-
|
109
|
-
def receive(event)
|
110
|
-
process_event(event, ['mailer', 'receive'])
|
111
|
-
end
|
112
|
-
|
113
|
-
def process(event)
|
114
|
-
process_event(event, ['mailer', 'process'])
|
115
|
-
end
|
116
|
-
|
117
|
-
def logger
|
118
|
-
LogStasher.logger
|
119
|
-
end
|
120
|
-
|
121
|
-
private
|
122
|
-
|
123
|
-
def process_event(event, tags)
|
124
|
-
data = LogStasher.request_context.merge(extract_metadata(event.payload))
|
125
|
-
logger << LogStasher.build_logstash_event(data, tags).to_json + "\n"
|
126
|
-
end
|
127
|
-
|
128
|
-
def extract_metadata(payload)
|
129
|
-
payload.slice(*MAILER_FIELDS)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|