logstasher 1.2.0 → 2.0.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 +5 -5
- data/lib/logstasher.rb +37 -37
- data/lib/logstasher/action_view/log_subscriber.rb +6 -7
- data/lib/logstasher/active_job/log_subscriber.rb +83 -83
- data/lib/logstasher/active_record/log_subscriber.rb +5 -6
- data/lib/logstasher/active_support/log_subscriber.rb +15 -16
- data/lib/logstasher/active_support/mailer_log_subscriber.rb +4 -4
- data/lib/logstasher/custom_fields.rb +1 -1
- data/lib/logstasher/device/redis.rb +5 -6
- data/lib/logstasher/event.rb +32 -0
- data/lib/logstasher/rails_ext/action_controller/base.rb +4 -4
- data/lib/logstasher/rails_ext/action_controller/metal/instrumentation.rb +16 -12
- data/lib/logstasher/rails_ext/rack/logger.rb +1 -2
- data/lib/logstasher/railtie.rb +28 -5
- data/lib/logstasher/version.rb +1 -1
- metadata +28 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e438a36935fc002e2de28f362171174d01908e321a432a45c0b6d5ba607593ff
|
4
|
+
data.tar.gz: 2076d9f4e694686bafc239e90f3c426feee7fcc74a9904352700704b1c8d2bd5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b8face2936949f9cf382336ef8e88da96ff848ea8f088f70eeedba7d6e76f923cb206b06b9cbb10b03ad28dda22cea70415d1686f662617a8175c9f6b7b2aa2
|
7
|
+
data.tar.gz: 7aa9af505594a1109b438c85a5196cfa5d46ac9591c53a4d3425790ed40d02f812c067a760d387b222bebbce8bae74585437d2a2e47cc8baa92e908d24c9aaee
|
data/lib/logstasher.rb
CHANGED
@@ -6,6 +6,7 @@ require 'logstasher/action_view/log_subscriber' if defined?(ActionView)
|
|
6
6
|
require 'logstasher/active_job/log_subscriber' if defined?(ActiveJob)
|
7
7
|
require 'logstasher/rails_ext/action_controller/base'
|
8
8
|
require 'logstasher/custom_fields'
|
9
|
+
require 'logstasher/event'
|
9
10
|
require 'request_store'
|
10
11
|
require 'active_support/core_ext/module/attribute_accessors'
|
11
12
|
require 'active_support/core_ext/string/inflections'
|
@@ -17,7 +18,8 @@ module LogStasher
|
|
17
18
|
REQUEST_CONTEXT_KEY = :logstasher_request_context
|
18
19
|
|
19
20
|
attr_accessor :logger, :logger_path, :enabled, :log_controller_parameters, :source, :backtrace,
|
20
|
-
|
21
|
+
:controller_monkey_patch, :field_renaming
|
22
|
+
|
21
23
|
# Setting the default to 'unknown' to define the default behaviour
|
22
24
|
@source = 'unknown'
|
23
25
|
# By default log the backtrace of exceptions
|
@@ -26,27 +28,25 @@ module LogStasher
|
|
26
28
|
def remove_existing_log_subscriptions
|
27
29
|
::ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber|
|
28
30
|
case subscriber.class.name
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
31
|
+
when 'ActionView::LogSubscriber'
|
32
|
+
unsubscribe(:action_view, subscriber)
|
33
|
+
when 'ActionController::LogSubscriber'
|
34
|
+
unsubscribe(:action_controller, subscriber)
|
35
|
+
when 'ActionMailer::LogSubscriber'
|
36
|
+
unsubscribe(:action_mailer, subscriber)
|
37
|
+
when 'ActiveRecord::LogSubscriber'
|
38
|
+
unsubscribe(:active_record, subscriber)
|
39
|
+
when 'ActiveJob::Logging::LogSubscriber'
|
40
|
+
unsubscribe(:active_job, subscriber)
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
42
44
|
|
43
45
|
def unsubscribe(component, subscriber)
|
44
|
-
events = subscriber.public_methods(false).reject{ |method| method.to_s == 'call' }
|
46
|
+
events = subscriber.public_methods(false).reject { |method| method.to_s == 'call' }
|
45
47
|
events.each do |event|
|
46
48
|
::ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
|
47
|
-
if listener.instance_variable_get('@delegate') == subscriber
|
48
|
-
::ActiveSupport::Notifications.unsubscribe listener
|
49
|
-
end
|
49
|
+
::ActiveSupport::Notifications.unsubscribe listener if listener.instance_variable_get('@delegate') == subscriber
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
@@ -56,14 +56,14 @@ module LogStasher
|
|
56
56
|
payload[:route] = "#{request.params[:controller]}##{request.params[:action]}"
|
57
57
|
payload[:request_id] = request.env['action_dispatch.request_id']
|
58
58
|
LogStasher::CustomFields.add(:ip, :route, :request_id)
|
59
|
-
if
|
59
|
+
if log_controller_parameters
|
60
60
|
payload[:parameters] = payload[:params].except(*::ActionController::LogSubscriber::INTERNAL_PARAMS)
|
61
61
|
LogStasher::CustomFields.add(:parameters)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
65
|
def add_custom_fields(&block)
|
66
|
-
wrapped_block =
|
66
|
+
wrapped_block = proc do |fields|
|
67
67
|
LogStasher::CustomFields.add(*LogStasher.store.keys)
|
68
68
|
instance_exec(fields, &block)
|
69
69
|
end
|
@@ -72,7 +72,7 @@ module LogStasher
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def add_custom_fields_to_request_context(&block)
|
75
|
-
wrapped_block =
|
75
|
+
wrapped_block = proc do |fields|
|
76
76
|
instance_exec(fields, &block)
|
77
77
|
LogStasher::CustomFields.add(*fields.keys)
|
78
78
|
end
|
@@ -100,27 +100,27 @@ module LogStasher
|
|
100
100
|
|
101
101
|
def setup(config)
|
102
102
|
# Path instrumentation class to insert our hook
|
103
|
-
if (!
|
103
|
+
if (!config.controller_monkey_patch && config.controller_monkey_patch != false) || config.controller_monkey_patch == true
|
104
104
|
require 'logstasher/rails_ext/action_controller/metal/instrumentation'
|
105
105
|
end
|
106
|
-
|
106
|
+
suppress_app_logs(config)
|
107
107
|
self.logger_path = config.logger_path || "#{Rails.root}/log/logstash_#{Rails.env}.log"
|
108
|
-
self.logger = config.logger || new_logger(
|
109
|
-
|
108
|
+
self.logger = config.logger || new_logger(logger_path)
|
109
|
+
logger.level = config.log_level || Logger::WARN
|
110
110
|
self.source = config.source unless config.source.nil?
|
111
|
-
self.log_controller_parameters = !!
|
112
|
-
self.backtrace = !!
|
113
|
-
|
114
|
-
|
111
|
+
self.log_controller_parameters = !!config.log_controller_parameters
|
112
|
+
self.backtrace = !!config.backtrace unless config.backtrace.nil?
|
113
|
+
set_data_for_rake
|
114
|
+
set_data_for_console
|
115
115
|
self.field_renaming = Hash(config.field_renaming)
|
116
116
|
end
|
117
117
|
|
118
118
|
def set_data_for_rake
|
119
|
-
|
119
|
+
request_context['request_id'] = ::Rake.application.top_level_tasks if called_as_rake?
|
120
120
|
end
|
121
121
|
|
122
122
|
def set_data_for_console
|
123
|
-
|
123
|
+
request_context['request_id'] = Process.pid.to_s if called_as_console?
|
124
124
|
end
|
125
125
|
|
126
126
|
def called_as_rake?
|
@@ -132,7 +132,7 @@ module LogStasher
|
|
132
132
|
end
|
133
133
|
|
134
134
|
def has_active_job?
|
135
|
-
|
135
|
+
defined?(ActiveJob)
|
136
136
|
end
|
137
137
|
|
138
138
|
def suppress_app_logs(config)
|
@@ -158,10 +158,10 @@ module LogStasher
|
|
158
158
|
# LogStasher.info("message", tags:["tag1", "tag2"])
|
159
159
|
# LogStasher.info("message", timing:1234)
|
160
160
|
# LogStasher.info(custom1:"yes", custom2:"no")
|
161
|
-
def log(severity, message, additional_fields={})
|
162
|
-
if
|
161
|
+
def log(severity, message, additional_fields = {})
|
162
|
+
if logger && logger.send("#{severity}?")
|
163
163
|
|
164
|
-
data = {'level' => severity}
|
164
|
+
data = { 'level' => severity }
|
165
165
|
if message.respond_to?(:to_hash)
|
166
166
|
data.merge!(message.to_hash)
|
167
167
|
else
|
@@ -172,16 +172,16 @@ module LogStasher
|
|
172
172
|
tags = Array(additional_fields.delete(:tags) || 'log')
|
173
173
|
|
174
174
|
data.merge!(additional_fields)
|
175
|
-
|
175
|
+
logger << build_logstash_event(data, tags).to_json + "\n"
|
176
176
|
|
177
177
|
end
|
178
178
|
end
|
179
179
|
|
180
180
|
def build_logstash_event(data, tags)
|
181
181
|
field_renaming.each do |old_name, new_name|
|
182
|
-
|
182
|
+
data[new_name] = data.delete(old_name) if data.key?(old_name)
|
183
183
|
end
|
184
|
-
|
184
|
+
Event.new(data.merge('source' => source, 'tags' => tags))
|
185
185
|
end
|
186
186
|
|
187
187
|
def store
|
@@ -204,7 +204,7 @@ module LogStasher
|
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
207
|
-
%w
|
207
|
+
%w[fatal error warn info debug unknown].each do |severity|
|
208
208
|
eval <<-EOM, nil, __FILE__, __LINE__ + 1
|
209
209
|
def #{severity}(message=nil, additional_fields={})
|
210
210
|
self.log(:#{severity}, message, additional_fields)
|
@@ -213,7 +213,7 @@ module LogStasher
|
|
213
213
|
end
|
214
214
|
|
215
215
|
def enabled?
|
216
|
-
|
216
|
+
enabled || false
|
217
217
|
end
|
218
218
|
|
219
219
|
private
|
@@ -10,8 +10,8 @@ module LogStasher
|
|
10
10
|
def render_template(event)
|
11
11
|
logstash_event(event)
|
12
12
|
end
|
13
|
-
alias
|
14
|
-
alias
|
13
|
+
alias render_partial render_template
|
14
|
+
alias render_collection render_template
|
15
15
|
|
16
16
|
def logger
|
17
17
|
LogStasher.logger
|
@@ -35,7 +35,7 @@ module LogStasher
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def extract_data(data)
|
38
|
-
{
|
38
|
+
{ identifier: from_rails_root(data[:identifier]) }
|
39
39
|
end
|
40
40
|
|
41
41
|
def request_context
|
@@ -49,16 +49,15 @@ module LogStasher
|
|
49
49
|
def event_data(event)
|
50
50
|
{
|
51
51
|
name: event.name,
|
52
|
-
transaction_id: event.transaction_id
|
52
|
+
transaction_id: event.transaction_id
|
53
53
|
}
|
54
54
|
end
|
55
55
|
|
56
56
|
def runtimes(event)
|
57
57
|
{
|
58
|
-
duration: event.duration
|
59
|
-
}.
|
58
|
+
duration: event.duration
|
59
|
+
}.each_with_object({}) do |(name, runtime), runtimes|
|
60
60
|
runtimes[name] = runtime.to_f.round(2) if runtime
|
61
|
-
runtimes
|
62
61
|
end
|
63
62
|
end
|
64
63
|
end
|
@@ -4,89 +4,89 @@ begin
|
|
4
4
|
rescue LoadError
|
5
5
|
end
|
6
6
|
|
7
|
-
|
8
|
-
module
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
7
|
+
if defined?(::ActiveJob::Logging::LogSubscriber)
|
8
|
+
module LogStasher
|
9
|
+
module ActiveJob
|
10
|
+
class LogSubscriber < ::ActiveJob::Logging::LogSubscriber
|
11
|
+
def enqueue(event)
|
12
|
+
process_event(event, 'enqueue')
|
13
|
+
end
|
14
|
+
|
15
|
+
def enqueue_at(event)
|
16
|
+
process_event(event, 'enqueue_at')
|
17
|
+
end
|
18
|
+
|
19
|
+
def perform(event)
|
20
|
+
process_event(event, 'perform')
|
21
|
+
|
22
|
+
# Revert the request id back, in the event that the inline adapter is being used or a
|
23
|
+
# perform_now was used.
|
24
|
+
LogStasher.request_context[:request_id] = Thread.current[:old_request_id]
|
25
|
+
Thread.current[:old_request_id] = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def perform_start(event)
|
29
|
+
# Use the job_id as the request id, so that any custom logging done for a job
|
30
|
+
# shares a request id, and has the job id in each log line.
|
31
|
+
#
|
32
|
+
# It's not being set when the job is enqueued, so enqueuing a job will have it's default
|
33
|
+
# request_id. In a lot of cases, it will be because of a web request.
|
34
|
+
#
|
35
|
+
# Hang onto the old request id, so we can revert after the job is done being performed.
|
36
|
+
Thread.current[:old_request_id] = LogStasher.request_context[:request_id]
|
37
|
+
LogStasher.request_context[:request_id] = event.payload[:job].job_id
|
38
|
+
|
39
|
+
process_event(event, 'perform_start')
|
40
|
+
end
|
41
|
+
|
42
|
+
def logger
|
43
|
+
LogStasher.logger
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def process_event(event, type)
|
49
|
+
data = extract_metadata(event)
|
50
|
+
data.merge! extract_exception(event)
|
51
|
+
data.merge! extract_scheduled_at(event) if type == 'enqueue_at'
|
52
|
+
data.merge! extract_duration(event) if type == 'perform'
|
53
|
+
data.merge! request_context
|
54
|
+
|
55
|
+
tags = ['job', type]
|
56
|
+
tags.push('exception') if data[:exception]
|
57
|
+
logger << LogStasher.build_logstash_event(data, tags).to_json + "\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
def extract_metadata(event)
|
61
|
+
{
|
62
|
+
job_id: event.payload[:job].job_id,
|
63
|
+
queue_name: queue_name(event),
|
64
|
+
job_class: event.payload[:job].class.to_s,
|
65
|
+
job_args: args_info(event.payload[:job])
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def extract_duration(event)
|
70
|
+
{ duration: event.duration.to_f.round(2) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def extract_exception(event)
|
74
|
+
event.payload.slice(:exception)
|
75
|
+
end
|
76
|
+
|
77
|
+
def extract_scheduled_at(event)
|
78
|
+
{ scheduled_at: scheduled_at(event) }
|
79
|
+
end
|
80
|
+
|
81
|
+
def request_context
|
82
|
+
LogStasher.request_context
|
83
|
+
end
|
84
|
+
|
85
|
+
# The default args_info makes a string. We need objects to turn into JSON.
|
86
|
+
def args_info(job)
|
87
|
+
job.arguments.map { |arg| arg.try(:to_global_id).try(:to_s) || arg }
|
88
|
+
end
|
58
89
|
end
|
59
|
-
|
60
|
-
def extract_metadata(event)
|
61
|
-
{
|
62
|
-
:job_id => event.payload[:job].job_id,
|
63
|
-
:queue_name => queue_name(event),
|
64
|
-
:job_class => event.payload[:job].class.to_s,
|
65
|
-
:job_args => args_info(event.payload[:job]),
|
66
|
-
}
|
67
|
-
end
|
68
|
-
|
69
|
-
def extract_duration(event)
|
70
|
-
{ :duration => event.duration.to_f.round(2) }
|
71
|
-
end
|
72
|
-
|
73
|
-
def extract_exception(event)
|
74
|
-
event.payload.slice(:exception)
|
75
|
-
end
|
76
|
-
|
77
|
-
def extract_scheduled_at(event)
|
78
|
-
{ :scheduled_at => scheduled_at(event) }
|
79
|
-
end
|
80
|
-
|
81
|
-
def request_context
|
82
|
-
LogStasher.request_context
|
83
|
-
end
|
84
|
-
|
85
|
-
# The default args_info makes a string. We need objects to turn into JSON.
|
86
|
-
def args_info(job)
|
87
|
-
job.arguments.map { |arg| arg.try(:to_global_id).try(:to_s) || arg }
|
88
|
-
end
|
89
|
-
|
90
90
|
end
|
91
91
|
end
|
92
|
-
end
|
92
|
+
end
|
@@ -9,11 +9,9 @@ module LogStasher
|
|
9
9
|
|
10
10
|
def identity(event)
|
11
11
|
lsevent = logstash_event(event)
|
12
|
-
if logger && lsevent
|
13
|
-
logger << lsevent.to_json + "\n"
|
14
|
-
end
|
12
|
+
logger << lsevent.to_json + "\n" if logger && lsevent
|
15
13
|
end
|
16
|
-
alias
|
14
|
+
alias sql identity
|
17
15
|
|
18
16
|
def logger
|
19
17
|
LogStasher.logger
|
@@ -22,6 +20,7 @@ module LogStasher
|
|
22
20
|
private
|
23
21
|
|
24
22
|
def logstash_event(event)
|
23
|
+
self.class.runtime += event.duration
|
25
24
|
data = event.payload
|
26
25
|
|
27
26
|
return if 'SCHEMA' == data[:name]
|
@@ -32,7 +31,7 @@ module LogStasher
|
|
32
31
|
data.merge! LogStasher.store
|
33
32
|
data.merge! extract_custom_fields(data)
|
34
33
|
|
35
|
-
tags = [
|
34
|
+
tags = ['request']
|
36
35
|
tags.push('exception') if data[:exception]
|
37
36
|
LogStasher.build_logstash_event(data, tags)
|
38
37
|
end
|
@@ -45,7 +44,7 @@ module LogStasher
|
|
45
44
|
if event.duration
|
46
45
|
{ duration: event.duration.to_f.round(2) }
|
47
46
|
else
|
48
|
-
{
|
47
|
+
{}
|
49
48
|
end
|
50
49
|
end
|
51
50
|
|
@@ -44,7 +44,7 @@ module LogStasher
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def extract_path(payload)
|
47
|
-
payload[:path].split(
|
47
|
+
payload[:path].split('?').first
|
48
48
|
end
|
49
49
|
|
50
50
|
def extract_format(payload)
|
@@ -57,27 +57,26 @@ module LogStasher
|
|
57
57
|
|
58
58
|
def extract_status(payload)
|
59
59
|
if payload[:status]
|
60
|
-
{ :
|
60
|
+
{ status: payload[:status].to_i }
|
61
61
|
else
|
62
|
-
{ :
|
62
|
+
{ status: 0 }
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
66
|
def runtimes(event)
|
67
67
|
{
|
68
|
-
:
|
69
|
-
:
|
70
|
-
:
|
71
|
-
}.
|
68
|
+
duration: event.duration,
|
69
|
+
view: event.payload[:view_runtime],
|
70
|
+
db: event.payload[:db_runtime]
|
71
|
+
}.each_with_object({}) do |(name, runtime), runtimes|
|
72
72
|
runtimes[name] = runtime.to_f.round(2) if runtime
|
73
|
-
runtimes
|
74
73
|
end
|
75
74
|
end
|
76
75
|
|
77
|
-
def location(
|
76
|
+
def location(_event)
|
78
77
|
if location = Thread.current[:logstasher_location]
|
79
78
|
Thread.current[:logstasher_location] = nil
|
80
|
-
{ :
|
79
|
+
{ location: location }
|
81
80
|
else
|
82
81
|
{}
|
83
82
|
end
|
@@ -88,13 +87,13 @@ module LogStasher
|
|
88
87
|
if payload[:exception]
|
89
88
|
exception, message = payload[:exception]
|
90
89
|
status = ::ActionDispatch::ExceptionWrapper.status_code_for_exception(exception)
|
91
|
-
if LogStasher.backtrace
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
90
|
+
backtrace = if LogStasher.backtrace
|
91
|
+
$!.backtrace.join("\n")
|
92
|
+
else
|
93
|
+
$!.backtrace.first
|
94
|
+
end
|
96
95
|
message = "#{exception}\n#{message}\n#{backtrace}"
|
97
|
-
{ :
|
96
|
+
{ status: status, error: message }
|
98
97
|
else
|
99
98
|
{}
|
100
99
|
end
|
@@ -4,18 +4,18 @@ require 'active_support/log_subscriber'
|
|
4
4
|
module LogStasher
|
5
5
|
module ActiveSupport
|
6
6
|
class MailerLogSubscriber < ::ActiveSupport::LogSubscriber
|
7
|
-
MAILER_FIELDS = [
|
7
|
+
MAILER_FIELDS = %i[mailer action message_id from to].freeze
|
8
8
|
|
9
9
|
def deliver(event)
|
10
|
-
process_event(event, [
|
10
|
+
process_event(event, %w[mailer deliver])
|
11
11
|
end
|
12
12
|
|
13
13
|
def receive(event)
|
14
|
-
process_event(event, [
|
14
|
+
process_event(event, %w[mailer receive])
|
15
15
|
end
|
16
16
|
|
17
17
|
def process(event)
|
18
|
-
process_event(event, [
|
18
|
+
process_event(event, %w[mailer process])
|
19
19
|
end
|
20
20
|
|
21
21
|
def logger
|
@@ -3,7 +3,6 @@ require 'redis'
|
|
3
3
|
module LogStasher
|
4
4
|
module Device
|
5
5
|
class Redis
|
6
|
-
|
7
6
|
attr_reader :options, :redis
|
8
7
|
|
9
8
|
def initialize(options = {})
|
@@ -23,7 +22,7 @@ module LogStasher
|
|
23
22
|
def redis_options
|
24
23
|
unless @redis_options
|
25
24
|
default_keys = default_options.keys
|
26
|
-
@redis_options = options.select { |k,
|
25
|
+
@redis_options = options.select { |k, _v| !default_keys.include?(k) }
|
27
26
|
end
|
28
27
|
|
29
28
|
@redis_options
|
@@ -36,7 +35,7 @@ module LogStasher
|
|
36
35
|
when 'channel'
|
37
36
|
redis.publish(key, log)
|
38
37
|
else
|
39
|
-
|
38
|
+
raise "Unknown data type #{data_type}"
|
40
39
|
end
|
41
40
|
end
|
42
41
|
|
@@ -51,12 +50,12 @@ module LogStasher
|
|
51
50
|
end
|
52
51
|
|
53
52
|
def default_options
|
54
|
-
|
53
|
+
{ key: 'logstash', data_type: 'list' }
|
55
54
|
end
|
56
55
|
|
57
56
|
def validate_options
|
58
|
-
unless [
|
59
|
-
|
57
|
+
unless %w[list channel].include?(options[:data_type])
|
58
|
+
raise 'Expected :data_type to be either "list" or "channel"'
|
60
59
|
end
|
61
60
|
end
|
62
61
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'time'
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
module LogStasher
|
6
|
+
class Event
|
7
|
+
def initialize(data = {})
|
8
|
+
@cancelled = false
|
9
|
+
|
10
|
+
@data = data
|
11
|
+
if data.include?('@timestamp')
|
12
|
+
t = data['@timestamp']
|
13
|
+
data['@timestamp'] = Time.parse(t).gmtime.iso8601(3) if t.is_a?(String)
|
14
|
+
else
|
15
|
+
data['@timestamp'] = ::Time.now.utc.iso8601(3)
|
16
|
+
end
|
17
|
+
data['@version'] = '1' unless @data.include?('@version')
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
to_json.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_json(*args)
|
25
|
+
@data.to_json(*args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](key)
|
29
|
+
@data[key]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -9,17 +9,17 @@ module LogStasher
|
|
9
9
|
super(*args)
|
10
10
|
LogStasher::CustomFields.clear
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
private
|
14
14
|
|
15
15
|
# this method is called from within super of process_action.
|
16
16
|
def append_info_to_payload(payload) #:nodoc:
|
17
17
|
LogStasher.add_default_fields_to_payload(payload, request)
|
18
|
-
if
|
18
|
+
if respond_to?(:logstasher_add_custom_fields_to_request_context)
|
19
19
|
logstasher_add_custom_fields_to_request_context(LogStasher.request_context)
|
20
20
|
end
|
21
21
|
|
22
|
-
if
|
22
|
+
if respond_to?(:logstasher_add_custom_fields_to_payload)
|
23
23
|
before_keys = payload.keys.clone
|
24
24
|
logstasher_add_custom_fields_to_payload(payload)
|
25
25
|
after_keys = payload.keys
|
@@ -38,7 +38,7 @@ module LogStasher
|
|
38
38
|
payload[key] = value
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
def add_custom_fields_to_store
|
43
43
|
LogStasher.store[:ip] = request.remote_ip
|
44
44
|
LogStasher.store[:route] = "#{request.params[:controller]}##{request.params[:action]}"
|
@@ -1,14 +1,18 @@
|
|
1
1
|
module ActionController
|
2
2
|
module Instrumentation
|
3
|
-
alias
|
3
|
+
alias orig_process_action process_action
|
4
4
|
def process_action(*args)
|
5
5
|
raw_payload = {
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
controller: self.class.name,
|
7
|
+
action: action_name,
|
8
|
+
params: request.filtered_parameters,
|
9
|
+
format: request.format.try(:ref),
|
10
|
+
method: request.method,
|
11
|
+
path: begin
|
12
|
+
request.fullpath
|
13
|
+
rescue StandardError
|
14
|
+
'unknown'
|
15
|
+
end
|
12
16
|
}
|
13
17
|
|
14
18
|
LogStasher.add_default_fields_to_payload(raw_payload, request)
|
@@ -16,14 +20,14 @@ module ActionController
|
|
16
20
|
LogStasher.clear_request_context
|
17
21
|
LogStasher.add_default_fields_to_request_context(request)
|
18
22
|
|
19
|
-
ActiveSupport::Notifications.instrument(
|
23
|
+
ActiveSupport::Notifications.instrument('start_processing.action_controller', raw_payload.dup)
|
20
24
|
|
21
|
-
ActiveSupport::Notifications.instrument(
|
22
|
-
if
|
25
|
+
ActiveSupport::Notifications.instrument('process_action.action_controller', raw_payload) do |payload|
|
26
|
+
if respond_to?(:logstasher_add_custom_fields_to_request_context)
|
23
27
|
logstasher_add_custom_fields_to_request_context(LogStasher.request_context)
|
24
28
|
end
|
25
29
|
|
26
|
-
if
|
30
|
+
if respond_to?(:logstasher_add_custom_fields_to_payload)
|
27
31
|
before_keys = raw_payload.keys.clone
|
28
32
|
logstasher_add_custom_fields_to_payload(raw_payload)
|
29
33
|
after_keys = raw_payload.keys
|
@@ -45,6 +49,6 @@ module ActionController
|
|
45
49
|
result
|
46
50
|
end
|
47
51
|
end
|
48
|
-
alias
|
52
|
+
alias logstasher_process_action process_action
|
49
53
|
end
|
50
54
|
end
|
data/lib/logstasher/railtie.rb
CHANGED
@@ -17,12 +17,12 @@ module LogStasher
|
|
17
17
|
|
18
18
|
# Try loading the config/logstasher.yml if present
|
19
19
|
env = Rails.env.to_sym || :development
|
20
|
-
config_file = File.expand_path
|
20
|
+
config_file = File.expand_path './config/logstasher.yml'
|
21
21
|
|
22
22
|
# Load and ERB templating of YAML files
|
23
|
-
LOGSTASHER = File.
|
23
|
+
LOGSTASHER = File.exist?(config_file) ? YAML.load(ERB.new(File.read(config_file)).result).symbolize_keys : nil
|
24
24
|
|
25
|
-
initializer :logstasher, :
|
25
|
+
initializer :logstasher, before: :load_config_initializers do |app|
|
26
26
|
if LOGSTASHER.present?
|
27
27
|
# process common configs
|
28
28
|
LogStasher.process_config(app.config.logstasher, LOGSTASHER)
|
@@ -30,7 +30,8 @@ module LogStasher
|
|
30
30
|
LogStasher.process_config(app.config.logstasher, LOGSTASHER[env].symbolize_keys) if LOGSTASHER.key? env
|
31
31
|
end
|
32
32
|
|
33
|
-
app.config.action_dispatch.rack_cache[:verbose] = false if app
|
33
|
+
app.config.action_dispatch.rack_cache[:verbose] = false if rack_cache_hashlike?(app)
|
34
|
+
|
34
35
|
LogStasher.setup_before(app.config.logstasher) if app.config.logstasher.enabled
|
35
36
|
end
|
36
37
|
|
@@ -39,6 +40,25 @@ module LogStasher
|
|
39
40
|
LogStasher.setup(config.logstasher) if config.logstasher.enabled
|
40
41
|
end
|
41
42
|
end
|
43
|
+
|
44
|
+
def rack_cache_hashlike?(app)
|
45
|
+
app.config.action_dispatch.rack_cache && app.config.action_dispatch.rack_cache.respond_to?(:[]=)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def default_source
|
50
|
+
case RUBY_PLATFORM
|
51
|
+
when /darwin/
|
52
|
+
# NOTE: MacOS Sierra and later are setting `.local`
|
53
|
+
# hostnames that even as real hostnames without the `.local` part,
|
54
|
+
# are still unresolvable. One reliable way to get an IP is to
|
55
|
+
# get all available IP address lists and use the first one.
|
56
|
+
# This will always be `127.0.0.1`.
|
57
|
+
address_info = Socket.ip_address_list.first
|
58
|
+
address_info && address_info.ip_address
|
59
|
+
else
|
60
|
+
IPSocket.getaddress(Socket.gethostname)
|
61
|
+
end
|
42
62
|
end
|
43
63
|
|
44
64
|
def process_config(config, yml_config)
|
@@ -54,10 +74,13 @@ module LogStasher
|
|
54
74
|
config.suppress_app_log = yml_config[:suppress_app_log] if yml_config.key? :suppress_app_log
|
55
75
|
|
56
76
|
# This line is optional, it allows you to set a custom value for the @source field of the log event
|
57
|
-
config.source = yml_config.key?(:source) ? yml_config[:source] :
|
77
|
+
config.source = yml_config.key?(:source) ? yml_config[:source] : default_source
|
58
78
|
|
59
79
|
config.backtrace = yml_config[:backtrace] if yml_config.key? :backtrace
|
60
80
|
config.logger_path = yml_config[:logger_path] if yml_config.key? :logger_path
|
61
81
|
config.log_level = yml_config[:log_level] if yml_config.key? :log_level
|
82
|
+
if yml_config.key? :log_controller_parameters
|
83
|
+
config.log_controller_parameters = yml_config[:log_controller_parameters]
|
84
|
+
end
|
62
85
|
end
|
63
86
|
end
|
data/lib/logstasher/version.rb
CHANGED
metadata
CHANGED
@@ -1,71 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstasher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shadab Ahmed
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-12-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: '5.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: '5.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: logstash-event
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 1.2.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 1.2.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: request_store
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: activerecord
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '5.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '5.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: bundler
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,28 +86,28 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '5.0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '5.0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: rspec
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
103
|
+
version: '2.14'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
110
|
+
version: '2.14'
|
111
111
|
description: Awesome rails logs
|
112
112
|
email:
|
113
113
|
- shadab.ansari@gmail.com
|
@@ -123,6 +123,7 @@ files:
|
|
123
123
|
- lib/logstasher/active_support/mailer_log_subscriber.rb
|
124
124
|
- lib/logstasher/custom_fields.rb
|
125
125
|
- lib/logstasher/device/redis.rb
|
126
|
+
- lib/logstasher/event.rb
|
126
127
|
- lib/logstasher/rails_ext/action_controller/base.rb
|
127
128
|
- lib/logstasher/rails_ext/action_controller/metal/instrumentation.rb
|
128
129
|
- lib/logstasher/rails_ext/rack/logger.rb
|
@@ -132,7 +133,7 @@ homepage: https://github.com/shadabahmed/logstasher
|
|
132
133
|
licenses:
|
133
134
|
- MIT
|
134
135
|
metadata: {}
|
135
|
-
post_install_message:
|
136
|
+
post_install_message:
|
136
137
|
rdoc_options: []
|
137
138
|
require_paths:
|
138
139
|
- lib
|
@@ -147,9 +148,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
148
|
- !ruby/object:Gem::Version
|
148
149
|
version: '0'
|
149
150
|
requirements: []
|
150
|
-
|
151
|
-
|
152
|
-
signing_key:
|
151
|
+
rubygems_version: 3.0.3
|
152
|
+
signing_key:
|
153
153
|
specification_version: 4
|
154
154
|
summary: Awesome rails logs
|
155
155
|
test_files: []
|