lograge 0.3.6 → 0.14.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/LICENSE.txt +21 -0
- data/lib/lograge/formatters/cee.rb +2 -0
- data/lib/lograge/formatters/graylog2.rb +8 -14
- data/lib/lograge/formatters/helpers/method_and_path.rb +14 -0
- data/lib/lograge/formatters/json.rb +2 -0
- data/lib/lograge/formatters/key_value.rb +17 -14
- data/lib/lograge/formatters/key_value_deep.rb +42 -0
- data/lib/lograge/formatters/l2met.rb +29 -8
- data/lib/lograge/formatters/lines.rb +2 -0
- data/lib/lograge/formatters/logstash.rb +5 -1
- data/lib/lograge/formatters/ltsv.rb +4 -3
- data/lib/lograge/formatters/raw.rb +2 -0
- data/lib/lograge/log_subscribers/action_cable.rb +34 -0
- data/lib/lograge/log_subscribers/action_controller.rb +75 -0
- data/lib/lograge/log_subscribers/base.rb +81 -0
- data/lib/lograge/ordered_options.rb +12 -0
- data/lib/lograge/rails_ext/action_cable/channel/base.rb +25 -0
- data/lib/lograge/rails_ext/action_cable/connection/base.rb +21 -0
- data/lib/lograge/rails_ext/action_cable/server/base.rb +10 -0
- data/lib/lograge/rails_ext/rack/logger.rb +9 -4
- data/lib/lograge/railtie.rb +7 -1
- data/lib/lograge/silent_logger.rb +13 -0
- data/lib/lograge/version.rb +3 -1
- data/lib/lograge.rb +74 -13
- metadata +58 -31
- data/lib/lograge/log_subscriber.rb +0 -116
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0d989dce1202da74220c6ac7926c3ef413502644e6f456589a334278ea357a4d
|
4
|
+
data.tar.gz: be68c46645948d5cc157a475b8820f50453fecaf9cc5e0f23bc842ec432eaa48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 273878d74ebdf36f2e703f6c4f0c70e6e17633f13dfc82bc7297ee5b209bb640a09da601768d16d4ca839bb22dfad7f0b8ee832676e4d94d4a96a90b1b5bfadc
|
7
|
+
data.tar.gz: c8503e3b547652a44076a858d0d566b1c75a273ef3efc6357398f7d5c41be7b656cf09687f96c1fe2437d16e4d8c8a657bfb7665055dab16e3a05230adf80e40
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) Mathias Meyer
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
@@ -1,21 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Lograge
|
2
4
|
module Formatters
|
3
5
|
class Graylog2
|
4
|
-
|
5
|
-
# Cloning because we don't want to mess with the original when mutating keys.
|
6
|
-
data_clone = data.clone
|
7
|
-
|
8
|
-
base = {
|
9
|
-
short_message: short_message(data_clone)
|
10
|
-
}
|
6
|
+
include Lograge::Formatters::Helpers::MethodAndPath
|
11
7
|
|
8
|
+
def call(data)
|
12
9
|
# Add underscore to every key to follow GELF additional field syntax.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
data_clone.merge(base)
|
10
|
+
data.transform_keys { |k| underscore_prefix(k) }.merge(
|
11
|
+
short_message: short_message(data)
|
12
|
+
)
|
19
13
|
end
|
20
14
|
|
21
15
|
def underscore_prefix(key)
|
@@ -23,7 +17,7 @@ module Lograge
|
|
23
17
|
end
|
24
18
|
|
25
19
|
def short_message(data)
|
26
|
-
"[#{data[:status]}]
|
20
|
+
"[#{data[:status]}]#{method_and_path_string(data)}(#{data[:controller]}##{data[:action]})"
|
27
21
|
end
|
28
22
|
end
|
29
23
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lograge
|
4
|
+
module Formatters
|
5
|
+
module Helpers
|
6
|
+
module MethodAndPath
|
7
|
+
def method_and_path_string(data)
|
8
|
+
method_and_path = [data[:method], data[:path]].compact
|
9
|
+
method_and_path.any?(&:present?) ? " #{method_and_path.join(' ')} " : ' '
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,29 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Lograge
|
2
4
|
module Formatters
|
3
5
|
class KeyValue
|
4
6
|
def call(data)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
event.join(' ')
|
7
|
+
fields_to_display(data)
|
8
|
+
.map { |key| format(key, data[key]) }
|
9
|
+
.join(' ')
|
9
10
|
end
|
10
11
|
|
12
|
+
protected
|
13
|
+
|
11
14
|
def fields_to_display(data)
|
12
15
|
data.keys
|
13
16
|
end
|
14
17
|
|
15
18
|
def format(key, value)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
"#{key}=#{parse_value(key, value)}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_value(key, value)
|
23
|
+
# Exactly preserve the previous output
|
24
|
+
# Parsing this can be ambigious if the error messages contains
|
25
|
+
# a single quote
|
26
|
+
return "'#{value}'" if key == :error
|
27
|
+
return Kernel.format('%.2f', value) if value.is_a? Float
|
25
28
|
|
26
|
-
|
29
|
+
value
|
27
30
|
end
|
28
31
|
end
|
29
32
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lograge
|
4
|
+
module Formatters
|
5
|
+
class KeyValueDeep < KeyValue
|
6
|
+
def call(data)
|
7
|
+
super flatten_keys(data)
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def flatten_keys(data, prefix = '')
|
13
|
+
return flatten_object(data, prefix) if [Hash, Array].include? data.class
|
14
|
+
|
15
|
+
data
|
16
|
+
end
|
17
|
+
|
18
|
+
def flatten_object(data, prefix)
|
19
|
+
result = {}
|
20
|
+
loop_on_object(data) do |key, value|
|
21
|
+
key = "#{prefix}_#{key}" unless prefix.empty?
|
22
|
+
if [Hash, Array].include? value.class
|
23
|
+
result.merge!(flatten_keys(value, key))
|
24
|
+
else
|
25
|
+
result[key] = value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
def loop_on_object(data, &block)
|
32
|
+
if data.instance_of? Array
|
33
|
+
data.each_with_index do |value, index|
|
34
|
+
yield index, value
|
35
|
+
end
|
36
|
+
return
|
37
|
+
end
|
38
|
+
data.each(&block)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,27 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'lograge/formatters/key_value'
|
2
4
|
|
3
5
|
module Lograge
|
4
6
|
module Formatters
|
5
7
|
class L2met < KeyValue
|
6
|
-
L2MET_FIELDS = [
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
L2MET_FIELDS = %i[
|
9
|
+
method
|
10
|
+
path
|
11
|
+
format
|
12
|
+
source
|
13
|
+
status
|
14
|
+
error
|
15
|
+
duration
|
16
|
+
view
|
17
|
+
db
|
18
|
+
location
|
19
|
+
].freeze
|
20
|
+
|
21
|
+
UNWANTED_FIELDS = %i[
|
22
|
+
controller
|
23
|
+
action
|
24
|
+
].freeze
|
10
25
|
|
11
26
|
def call(data)
|
12
27
|
super(modify_payload(data))
|
13
28
|
end
|
14
29
|
|
30
|
+
protected
|
31
|
+
|
32
|
+
def fields_to_display(data)
|
33
|
+
L2MET_FIELDS + additional_fields(data)
|
34
|
+
end
|
35
|
+
|
36
|
+
def additional_fields(data)
|
37
|
+
(data.keys - L2MET_FIELDS) - UNWANTED_FIELDS
|
38
|
+
end
|
39
|
+
|
15
40
|
def format(key, value)
|
16
41
|
key = "measure#page.#{key}" if value.is_a?(Float)
|
17
42
|
|
18
43
|
super(key, value)
|
19
44
|
end
|
20
45
|
|
21
|
-
def fields_to_display(data)
|
22
|
-
L2MET_FIELDS + (data.keys - L2MET_FIELDS) - [:controller, :action]
|
23
|
-
end
|
24
|
-
|
25
46
|
def modify_payload(data)
|
26
47
|
data[:source] = source_field(data) if data[:controller] && data[:action]
|
27
48
|
|
@@ -1,11 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Lograge
|
2
4
|
module Formatters
|
3
5
|
class Logstash
|
6
|
+
include Lograge::Formatters::Helpers::MethodAndPath
|
7
|
+
|
4
8
|
def call(data)
|
5
9
|
load_dependencies
|
6
10
|
event = LogStash::Event.new(data)
|
7
11
|
|
8
|
-
event['message'] = "[#{data[:status]}]
|
12
|
+
event['message'] = "[#{data[:status]}]#{method_and_path_string(data)}(#{data[:controller]}##{data[:action]})"
|
9
13
|
event.to_json
|
10
14
|
end
|
11
15
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Lograge
|
2
4
|
module Formatters
|
3
5
|
class LTSV
|
@@ -18,9 +20,8 @@ module Lograge
|
|
18
20
|
# Parsing this can be ambigious if the error messages contains
|
19
21
|
# a single quote
|
20
22
|
value = "'#{escape value}'"
|
21
|
-
|
22
|
-
|
23
|
-
value = Kernel.format('%.2f', value) if value.is_a? Float
|
23
|
+
elsif value.is_a? Float
|
24
|
+
value = Kernel.format('%.2f', value)
|
24
25
|
end
|
25
26
|
|
26
27
|
"#{key}:#{value}"
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lograge
|
4
|
+
module LogSubscribers
|
5
|
+
class ActionCable < Base
|
6
|
+
%i[perform_action subscribe unsubscribe connect disconnect].each do |method_name|
|
7
|
+
define_method(method_name) do |event|
|
8
|
+
process_main_event(event)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def initial_data(payload)
|
15
|
+
{
|
16
|
+
method: nil,
|
17
|
+
path: nil,
|
18
|
+
format: nil,
|
19
|
+
params: payload[:data],
|
20
|
+
controller: payload[:channel_class] || payload[:connection_class],
|
21
|
+
action: payload[:action]
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_status
|
26
|
+
200
|
27
|
+
end
|
28
|
+
|
29
|
+
def extract_runtimes(event, _payload)
|
30
|
+
{ duration: event.duration.to_f.round(2) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lograge
|
4
|
+
module LogSubscribers
|
5
|
+
class ActionController < Base
|
6
|
+
def process_action(event)
|
7
|
+
process_main_event(event)
|
8
|
+
end
|
9
|
+
|
10
|
+
def redirect_to(event)
|
11
|
+
RequestStore.store[:lograge_location] = event.payload[:location]
|
12
|
+
end
|
13
|
+
|
14
|
+
def unpermitted_parameters(event)
|
15
|
+
RequestStore.store[:lograge_unpermitted_params] ||= []
|
16
|
+
RequestStore.store[:lograge_unpermitted_params].concat(event.payload[:keys])
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def initial_data(payload)
|
22
|
+
{
|
23
|
+
method: payload[:method],
|
24
|
+
path: extract_path(payload),
|
25
|
+
format: extract_format(payload),
|
26
|
+
controller: payload[:controller],
|
27
|
+
action: payload[:action]
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def extract_path(payload)
|
32
|
+
path = payload[:path]
|
33
|
+
strip_query_string(path)
|
34
|
+
end
|
35
|
+
|
36
|
+
def strip_query_string(path)
|
37
|
+
index = path.index('?')
|
38
|
+
index ? path[0, index] : path
|
39
|
+
end
|
40
|
+
|
41
|
+
if ::ActionPack::VERSION::MAJOR == 3 && ::ActionPack::VERSION::MINOR.zero?
|
42
|
+
def extract_format(payload)
|
43
|
+
payload[:formats].first
|
44
|
+
end
|
45
|
+
else
|
46
|
+
def extract_format(payload)
|
47
|
+
payload[:format]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def extract_runtimes(event, payload)
|
52
|
+
data = { duration: event.duration.to_f.round(2) }
|
53
|
+
data[:view] = payload[:view_runtime].to_f.round(2) if payload.key?(:view_runtime)
|
54
|
+
data[:db] = payload[:db_runtime].to_f.round(2) if payload.key?(:db_runtime)
|
55
|
+
data
|
56
|
+
end
|
57
|
+
|
58
|
+
def extract_location
|
59
|
+
location = RequestStore.store[:lograge_location]
|
60
|
+
return {} unless location
|
61
|
+
|
62
|
+
RequestStore.store[:lograge_location] = nil
|
63
|
+
{ location: strip_query_string(location) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def extract_unpermitted_params
|
67
|
+
unpermitted_params = RequestStore.store[:lograge_unpermitted_params]
|
68
|
+
return {} unless unpermitted_params
|
69
|
+
|
70
|
+
RequestStore.store[:lograge_unpermitted_params] = nil
|
71
|
+
{ unpermitted_params: unpermitted_params }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'action_pack'
|
5
|
+
require 'active_support'
|
6
|
+
require 'active_support/core_ext/class/attribute'
|
7
|
+
require 'active_support/log_subscriber'
|
8
|
+
require 'request_store'
|
9
|
+
|
10
|
+
module Lograge
|
11
|
+
module LogSubscribers
|
12
|
+
class Base < ActiveSupport::LogSubscriber
|
13
|
+
def logger
|
14
|
+
Lograge.logger.presence || super
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def process_main_event(event)
|
20
|
+
return if Lograge.ignore?(event)
|
21
|
+
|
22
|
+
payload = event.payload
|
23
|
+
data = extract_request(event, payload)
|
24
|
+
data = before_format(data, payload)
|
25
|
+
formatted_message = Lograge.formatter.call(data)
|
26
|
+
logger.send(Lograge.log_level, formatted_message)
|
27
|
+
end
|
28
|
+
|
29
|
+
def extract_request(event, payload)
|
30
|
+
data = initial_data(payload)
|
31
|
+
data.merge!(extract_status(payload))
|
32
|
+
data.merge!(extract_allocations(event))
|
33
|
+
data.merge!(extract_runtimes(event, payload))
|
34
|
+
data.merge!(extract_location)
|
35
|
+
data.merge!(extract_unpermitted_params)
|
36
|
+
data.merge!(custom_options(event))
|
37
|
+
end
|
38
|
+
|
39
|
+
%i[initial_data extract_status extract_runtimes
|
40
|
+
extract_location extract_unpermitted_params].each do |method_name|
|
41
|
+
define_method(method_name) { |*_arg| {} }
|
42
|
+
end
|
43
|
+
|
44
|
+
def extract_status(payload)
|
45
|
+
if (status = payload[:status])
|
46
|
+
{ status: status.to_i }
|
47
|
+
elsif (error = payload[:exception])
|
48
|
+
exception, message = error
|
49
|
+
{ status: get_error_status_code(exception), error: "#{exception}: #{message}" }
|
50
|
+
else
|
51
|
+
{ status: default_status }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def default_status
|
56
|
+
0
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_error_status_code(exception_class_name)
|
60
|
+
ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
|
61
|
+
end
|
62
|
+
|
63
|
+
def extract_allocations(event)
|
64
|
+
if (allocations = (event.respond_to?(:allocations) && event.allocations))
|
65
|
+
{ allocations: allocations }
|
66
|
+
else
|
67
|
+
{}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def custom_options(event)
|
72
|
+
options = Lograge.custom_options(event) || {}
|
73
|
+
options.merge event.payload[:custom_payload] || {}
|
74
|
+
end
|
75
|
+
|
76
|
+
def before_format(data, payload)
|
77
|
+
Lograge.before_format(data, payload)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/ordered_options'
|
5
|
+
|
6
|
+
module Lograge
|
7
|
+
class OrderedOptions < ActiveSupport::OrderedOptions
|
8
|
+
def custom_payload(&block)
|
9
|
+
self.custom_payload_method = block
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lograge
|
4
|
+
module ActionCable
|
5
|
+
module ChannelInstrumentation
|
6
|
+
def subscribe_to_channel
|
7
|
+
ActiveSupport::Notifications.instrument('subscribe.action_cable', notification_payload('subscribe')) { super }
|
8
|
+
end
|
9
|
+
|
10
|
+
def unsubscribe_from_channel
|
11
|
+
ActiveSupport::Notifications.instrument('unsubscribe.action_cable', notification_payload('unsubscribe')) do
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def notification_payload(method_name)
|
19
|
+
{ channel_class: self.class.name, action: method_name }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
ActionCable::Channel::Base.prepend(Lograge::ActionCable::ChannelInstrumentation)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lograge
|
4
|
+
module ActionCable
|
5
|
+
module ConnectionInstrumentation
|
6
|
+
def handle_open
|
7
|
+
ActiveSupport::Notifications.instrument('connect.action_cable', notification_payload('connect')) { super }
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle_close
|
11
|
+
ActiveSupport::Notifications.instrument('disconnect.action_cable', notification_payload('disconnect')) { super }
|
12
|
+
end
|
13
|
+
|
14
|
+
def notification_payload(method_name)
|
15
|
+
{ connection_class: self.class.name, action: method_name, data: request.params }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
ActionCable::Connection::Base.prepend(Lograge::ActionCable::ConnectionInstrumentation)
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
1
4
|
require 'active_support/concern'
|
2
5
|
require 'rails/rack/logger'
|
3
6
|
|
@@ -9,17 +12,19 @@ module Rails
|
|
9
12
|
# that say:
|
10
13
|
# Started GET / for 192.168.2.1...
|
11
14
|
class Logger
|
12
|
-
# Overwrites Rails
|
15
|
+
# Overwrites Rails code that logs new requests
|
13
16
|
def call_app(*args)
|
14
17
|
env = args.last
|
15
|
-
@app.call(env)
|
18
|
+
status, headers, body = @app.call(env)
|
19
|
+
# needs to have same return type as the Rails builtins being overridden, see https://github.com/roidrage/lograge/pull/333
|
20
|
+
# https://github.com/rails/rails/blob/be9d34b9bcb448b265114ebc28bef1a5b5e4c272/railties/lib/rails/rack/logger.rb#L37
|
21
|
+
[status, headers, ::Rack::BodyProxy.new(body) {}] # rubocop:disable Lint/EmptyBlock
|
16
22
|
ensure
|
17
23
|
ActiveSupport::LogSubscriber.flush_all!
|
18
24
|
end
|
19
25
|
|
20
26
|
# Overwrites Rails 3.0/3.1 code that logs new requests
|
21
|
-
def before_dispatch(_env)
|
22
|
-
end
|
27
|
+
def before_dispatch(_env); end
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
data/lib/lograge/railtie.rb
CHANGED
@@ -1,12 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rails/railtie'
|
2
4
|
require 'action_view/log_subscriber'
|
3
5
|
require 'action_controller/log_subscriber'
|
4
6
|
|
5
7
|
module Lograge
|
6
8
|
class Railtie < Rails::Railtie
|
7
|
-
config.lograge =
|
9
|
+
config.lograge = Lograge::OrderedOptions.new
|
8
10
|
config.lograge.enabled = false
|
9
11
|
|
12
|
+
initializer :deprecator do |app|
|
13
|
+
app.deprecators[:lograge] = Lograge.deprecator if app.respond_to?(:deprecators)
|
14
|
+
end
|
15
|
+
|
10
16
|
config.after_initialize do |app|
|
11
17
|
Lograge.setup(app) if app.config.lograge.enabled
|
12
18
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'delegate'
|
4
|
+
|
5
|
+
module Lograge
|
6
|
+
class SilentLogger < SimpleDelegator
|
7
|
+
%i[debug info warn error fatal unknown].each do |method_name|
|
8
|
+
# rubocop:disable Lint/EmptyBlock
|
9
|
+
define_method(method_name) { |*_args| }
|
10
|
+
# rubocop:enable Lint/EmptyBlock
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/lograge/version.rb
CHANGED
data/lib/lograge.rb
CHANGED
@@ -1,19 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'lograge/version'
|
4
|
+
require 'lograge/formatters/helpers/method_and_path'
|
2
5
|
require 'lograge/formatters/cee'
|
3
6
|
require 'lograge/formatters/json'
|
4
7
|
require 'lograge/formatters/graylog2'
|
5
8
|
require 'lograge/formatters/key_value'
|
9
|
+
require 'lograge/formatters/key_value_deep'
|
6
10
|
require 'lograge/formatters/l2met'
|
7
11
|
require 'lograge/formatters/lines'
|
8
12
|
require 'lograge/formatters/logstash'
|
9
13
|
require 'lograge/formatters/ltsv'
|
10
14
|
require 'lograge/formatters/raw'
|
11
|
-
require 'lograge/
|
15
|
+
require 'lograge/log_subscribers/base'
|
16
|
+
require 'lograge/log_subscribers/action_cable'
|
17
|
+
require 'lograge/log_subscribers/action_controller'
|
18
|
+
require 'lograge/silent_logger'
|
19
|
+
require 'lograge/ordered_options'
|
20
|
+
require 'active_support'
|
12
21
|
require 'active_support/core_ext/module/attribute_accessors'
|
13
22
|
require 'active_support/core_ext/string/inflections'
|
14
|
-
require 'active_support/ordered_options'
|
15
23
|
|
16
|
-
# rubocop:disable ModuleLength
|
24
|
+
# rubocop:disable Metrics/ModuleLength
|
17
25
|
module Lograge
|
18
26
|
module_function
|
19
27
|
|
@@ -51,7 +59,7 @@ module Lograge
|
|
51
59
|
# Set conditions for events that should be ignored
|
52
60
|
#
|
53
61
|
# Currently supported formats are:
|
54
|
-
# - A single string representing a controller action, e.g. '
|
62
|
+
# - A single string representing a controller action, e.g. 'UsersController#sign_in'
|
55
63
|
# - An array of strings representing controller actions
|
56
64
|
# - An object that responds to call with an event argument and returns
|
57
65
|
# true iff the event should be ignored.
|
@@ -62,11 +70,15 @@ module Lograge
|
|
62
70
|
|
63
71
|
def ignore_actions(actions)
|
64
72
|
ignore(lambda do |event|
|
65
|
-
params = event.payload
|
66
|
-
Array(actions).include?("#{params
|
73
|
+
params = event.payload
|
74
|
+
Array(actions).include?("#{controller_field(params)}##{params[:action]}")
|
67
75
|
end)
|
68
76
|
end
|
69
77
|
|
78
|
+
def controller_field(params)
|
79
|
+
params[:controller] || params[:channel_class] || params[:connection_class]
|
80
|
+
end
|
81
|
+
|
70
82
|
def ignore_tests
|
71
83
|
@ignore_tests ||= []
|
72
84
|
end
|
@@ -108,10 +120,8 @@ module Lograge
|
|
108
120
|
def unsubscribe(component, subscriber)
|
109
121
|
events = subscriber.public_methods(false).reject { |method| method.to_s == 'call' }
|
110
122
|
events.each do |event|
|
111
|
-
|
112
|
-
if listener.instance_variable_get('@delegate') == subscriber
|
113
|
-
ActiveSupport::Notifications.unsubscribe listener
|
114
|
-
end
|
123
|
+
Lograge.notification_listeners_for("#{event}.#{component}").each do |listener|
|
124
|
+
ActiveSupport::Notifications.unsubscribe listener if listener.instance_variable_get('@delegate') == subscriber
|
115
125
|
end
|
116
126
|
end
|
117
127
|
end
|
@@ -122,7 +132,10 @@ module Lograge
|
|
122
132
|
keep_original_rails_log
|
123
133
|
|
124
134
|
attach_to_action_controller
|
135
|
+
attach_to_action_cable if defined?(ActionCable)
|
136
|
+
|
125
137
|
set_lograge_log_options
|
138
|
+
setup_custom_payload
|
126
139
|
support_deprecated_config # TODO: Remove with version 1.0
|
127
140
|
set_formatter
|
128
141
|
set_ignores
|
@@ -138,7 +151,36 @@ module Lograge
|
|
138
151
|
end
|
139
152
|
|
140
153
|
def attach_to_action_controller
|
141
|
-
Lograge::
|
154
|
+
Lograge::LogSubscribers::ActionController.attach_to :action_controller
|
155
|
+
end
|
156
|
+
|
157
|
+
def attach_to_action_cable
|
158
|
+
require 'lograge/rails_ext/action_cable/channel/base'
|
159
|
+
require 'lograge/rails_ext/action_cable/connection/base'
|
160
|
+
|
161
|
+
Lograge::LogSubscribers::ActionCable.attach_to :action_cable
|
162
|
+
end
|
163
|
+
|
164
|
+
def setup_custom_payload
|
165
|
+
return unless lograge_config.custom_payload_method.respond_to?(:call)
|
166
|
+
|
167
|
+
base_classes = Array(lograge_config.base_controller_class)
|
168
|
+
base_classes.map! { |klass| klass.try(:constantize) }
|
169
|
+
base_classes << ActionController::Base if base_classes.empty?
|
170
|
+
|
171
|
+
base_classes.each do |base_class|
|
172
|
+
extend_base_class(base_class)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def extend_base_class(klass)
|
177
|
+
append_payload_method = klass.instance_method(:append_info_to_payload)
|
178
|
+
custom_payload_method = lograge_config.custom_payload_method
|
179
|
+
|
180
|
+
klass.send(:define_method, :append_info_to_payload) do |payload|
|
181
|
+
append_payload_method.bind(self).call(payload)
|
182
|
+
payload[:custom_payload] = custom_payload_method.call(self)
|
183
|
+
end
|
142
184
|
end
|
143
185
|
|
144
186
|
def set_lograge_log_options
|
@@ -156,11 +198,14 @@ module Lograge
|
|
156
198
|
return if lograge_config.keep_original_rails_log
|
157
199
|
|
158
200
|
require 'lograge/rails_ext/rack/logger'
|
201
|
+
|
202
|
+
require 'lograge/rails_ext/action_cable/server/base' if defined?(ActionCable)
|
203
|
+
|
159
204
|
Lograge.remove_existing_log_subscriptions
|
160
205
|
end
|
161
206
|
|
162
207
|
def rack_cache_hashlike?(app)
|
163
|
-
app.config.action_dispatch.rack_cache
|
208
|
+
app.config.action_dispatch.rack_cache&.respond_to?(:[]=)
|
164
209
|
end
|
165
210
|
private_class_method :rack_cache_hashlike?
|
166
211
|
|
@@ -171,7 +216,7 @@ module Lograge
|
|
171
216
|
|
172
217
|
legacy_log_format = lograge_config.log_format
|
173
218
|
warning = 'config.lograge.log_format is deprecated. Use config.lograge.formatter instead.'
|
174
|
-
|
219
|
+
deprecator.warn(warning, caller)
|
175
220
|
legacy_log_format = :key_value if legacy_log_format == :lograge
|
176
221
|
lograge_config.formatter = "Lograge::Formatters::#{legacy_log_format.to_s.classify}".constantize.new
|
177
222
|
end
|
@@ -179,6 +224,22 @@ module Lograge
|
|
179
224
|
def lograge_config
|
180
225
|
application.config.lograge
|
181
226
|
end
|
227
|
+
|
228
|
+
def deprecator
|
229
|
+
@deprecator ||= ActiveSupport::Deprecation.new('1.0', 'Lograge')
|
230
|
+
end
|
231
|
+
|
232
|
+
if ::ActiveSupport::VERSION::MAJOR >= 8 ||
|
233
|
+
(::ActiveSupport::VERSION::MAJOR >= 7 && ::ActiveSupport::VERSION::MINOR >= 1)
|
234
|
+
def notification_listeners_for(name)
|
235
|
+
ActiveSupport::Notifications.notifier.all_listeners_for(name)
|
236
|
+
end
|
237
|
+
else
|
238
|
+
def notification_listeners_for(name)
|
239
|
+
ActiveSupport::Notifications.notifier.listeners_for(name)
|
240
|
+
end
|
241
|
+
end
|
182
242
|
end
|
243
|
+
# rubocop:enable Metrics/ModuleLength
|
183
244
|
|
184
245
|
require 'lograge/railtie' if defined?(Rails)
|
metadata
CHANGED
@@ -1,127 +1,155 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lograge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mathias Meyer
|
8
8
|
- Ben Lovell
|
9
|
-
|
9
|
+
- Michael Bianco
|
10
|
+
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date:
|
13
|
+
date: 2023-10-10 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: rspec
|
16
17
|
requirement: !ruby/object:Gem::Requirement
|
17
18
|
requirements:
|
18
|
-
- - "
|
19
|
+
- - "~>"
|
19
20
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
21
|
+
version: '3.1'
|
21
22
|
type: :development
|
22
23
|
prerelease: false
|
23
24
|
version_requirements: !ruby/object:Gem::Requirement
|
24
25
|
requirements:
|
25
|
-
- - "
|
26
|
+
- - "~>"
|
26
27
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
28
|
+
version: '3.1'
|
28
29
|
- !ruby/object:Gem::Dependency
|
29
30
|
name: rubocop
|
30
31
|
requirement: !ruby/object:Gem::Requirement
|
31
32
|
requirements:
|
32
|
-
- -
|
33
|
+
- - "~>"
|
33
34
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
35
|
+
version: '1.23'
|
35
36
|
type: :development
|
36
37
|
prerelease: false
|
37
38
|
version_requirements: !ruby/object:Gem::Requirement
|
38
39
|
requirements:
|
39
|
-
- -
|
40
|
+
- - "~>"
|
40
41
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
42
|
+
version: '1.23'
|
42
43
|
- !ruby/object:Gem::Dependency
|
43
|
-
name:
|
44
|
+
name: simplecov
|
44
45
|
requirement: !ruby/object:Gem::Requirement
|
45
46
|
requirements:
|
46
|
-
- -
|
47
|
+
- - "~>"
|
47
48
|
- !ruby/object:Gem::Version
|
48
|
-
version:
|
49
|
+
version: '0.21'
|
49
50
|
type: :development
|
50
51
|
prerelease: false
|
51
52
|
version_requirements: !ruby/object:Gem::Requirement
|
52
53
|
requirements:
|
53
|
-
- -
|
54
|
+
- - "~>"
|
54
55
|
- !ruby/object:Gem::Version
|
55
|
-
version:
|
56
|
+
version: '0.21'
|
56
57
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
58
|
+
name: actionpack
|
58
59
|
requirement: !ruby/object:Gem::Requirement
|
59
60
|
requirements:
|
60
61
|
- - ">="
|
61
62
|
- !ruby/object:Gem::Version
|
62
|
-
version: '
|
63
|
+
version: '4'
|
63
64
|
type: :runtime
|
64
65
|
prerelease: false
|
65
66
|
version_requirements: !ruby/object:Gem::Requirement
|
66
67
|
requirements:
|
67
68
|
- - ">="
|
68
69
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
70
|
+
version: '4'
|
70
71
|
- !ruby/object:Gem::Dependency
|
71
|
-
name:
|
72
|
+
name: activesupport
|
72
73
|
requirement: !ruby/object:Gem::Requirement
|
73
74
|
requirements:
|
74
75
|
- - ">="
|
75
76
|
- !ruby/object:Gem::Version
|
76
|
-
version: '
|
77
|
+
version: '4'
|
77
78
|
type: :runtime
|
78
79
|
prerelease: false
|
79
80
|
version_requirements: !ruby/object:Gem::Requirement
|
80
81
|
requirements:
|
81
82
|
- - ">="
|
82
83
|
- !ruby/object:Gem::Version
|
83
|
-
version: '
|
84
|
+
version: '4'
|
84
85
|
- !ruby/object:Gem::Dependency
|
85
86
|
name: railties
|
86
87
|
requirement: !ruby/object:Gem::Requirement
|
87
88
|
requirements:
|
88
89
|
- - ">="
|
89
90
|
- !ruby/object:Gem::Version
|
90
|
-
version: '
|
91
|
+
version: '4'
|
91
92
|
type: :runtime
|
92
93
|
prerelease: false
|
93
94
|
version_requirements: !ruby/object:Gem::Requirement
|
94
95
|
requirements:
|
95
96
|
- - ">="
|
96
97
|
- !ruby/object:Gem::Version
|
97
|
-
version: '
|
98
|
+
version: '4'
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: request_store
|
101
|
+
requirement: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - "~>"
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '1.0'
|
106
|
+
type: :runtime
|
107
|
+
prerelease: false
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - "~>"
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '1.0'
|
98
113
|
description: Tame Rails' multi-line logging into a single line per request
|
99
114
|
email:
|
100
115
|
- meyer@paperplanes.de
|
101
116
|
- benjamin.lovell@gmail.com
|
117
|
+
- mike@mikebian.co
|
102
118
|
executables: []
|
103
119
|
extensions: []
|
104
120
|
extra_rdoc_files: []
|
105
121
|
files:
|
122
|
+
- LICENSE.txt
|
106
123
|
- lib/lograge.rb
|
107
124
|
- lib/lograge/formatters/cee.rb
|
108
125
|
- lib/lograge/formatters/graylog2.rb
|
126
|
+
- lib/lograge/formatters/helpers/method_and_path.rb
|
109
127
|
- lib/lograge/formatters/json.rb
|
110
128
|
- lib/lograge/formatters/key_value.rb
|
129
|
+
- lib/lograge/formatters/key_value_deep.rb
|
111
130
|
- lib/lograge/formatters/l2met.rb
|
112
131
|
- lib/lograge/formatters/lines.rb
|
113
132
|
- lib/lograge/formatters/logstash.rb
|
114
133
|
- lib/lograge/formatters/ltsv.rb
|
115
134
|
- lib/lograge/formatters/raw.rb
|
116
|
-
- lib/lograge/
|
135
|
+
- lib/lograge/log_subscribers/action_cable.rb
|
136
|
+
- lib/lograge/log_subscribers/action_controller.rb
|
137
|
+
- lib/lograge/log_subscribers/base.rb
|
138
|
+
- lib/lograge/ordered_options.rb
|
139
|
+
- lib/lograge/rails_ext/action_cable/channel/base.rb
|
140
|
+
- lib/lograge/rails_ext/action_cable/connection/base.rb
|
141
|
+
- lib/lograge/rails_ext/action_cable/server/base.rb
|
117
142
|
- lib/lograge/rails_ext/rack/logger.rb
|
118
143
|
- lib/lograge/railtie.rb
|
144
|
+
- lib/lograge/silent_logger.rb
|
119
145
|
- lib/lograge/version.rb
|
120
146
|
homepage: https://github.com/roidrage/lograge
|
121
147
|
licenses:
|
122
148
|
- MIT
|
123
|
-
metadata:
|
124
|
-
|
149
|
+
metadata:
|
150
|
+
rubygems_mfa_required: 'true'
|
151
|
+
changelog_uri: https://github.com/roidrage/lograge/blob/master/CHANGELOG.md
|
152
|
+
post_install_message:
|
125
153
|
rdoc_options: []
|
126
154
|
require_paths:
|
127
155
|
- lib
|
@@ -129,16 +157,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
129
157
|
requirements:
|
130
158
|
- - ">="
|
131
159
|
- !ruby/object:Gem::Version
|
132
|
-
version: '
|
160
|
+
version: '2.5'
|
133
161
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
162
|
requirements:
|
135
163
|
- - ">="
|
136
164
|
- !ruby/object:Gem::Version
|
137
165
|
version: '0'
|
138
166
|
requirements: []
|
139
|
-
|
140
|
-
|
141
|
-
signing_key:
|
167
|
+
rubygems_version: 3.4.10
|
168
|
+
signing_key:
|
142
169
|
specification_version: 4
|
143
170
|
summary: Tame Rails' multi-line logging into a single line per request
|
144
171
|
test_files: []
|
@@ -1,116 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'action_pack'
|
3
|
-
require 'active_support/core_ext/class/attribute'
|
4
|
-
require 'active_support/log_subscriber'
|
5
|
-
|
6
|
-
module Lograge
|
7
|
-
class RequestLogSubscriber < ActiveSupport::LogSubscriber
|
8
|
-
def process_action(event)
|
9
|
-
return if Lograge.ignore?(event)
|
10
|
-
|
11
|
-
payload = event.payload
|
12
|
-
data = extract_request(event, payload)
|
13
|
-
data = before_format(data, payload)
|
14
|
-
formatted_message = Lograge.formatter.call(data)
|
15
|
-
logger.send(Lograge.log_level, formatted_message)
|
16
|
-
end
|
17
|
-
|
18
|
-
def redirect_to(event)
|
19
|
-
Thread.current[:lograge_location] = event.payload[:location]
|
20
|
-
end
|
21
|
-
|
22
|
-
def unpermitted_parameters(event)
|
23
|
-
Thread.current[:lograge_unpermitted_params] ||= []
|
24
|
-
Thread.current[:lograge_unpermitted_params].concat(event.payload[:keys])
|
25
|
-
end
|
26
|
-
|
27
|
-
def logger
|
28
|
-
Lograge.logger.presence || super
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def extract_request(event, payload)
|
34
|
-
payload = event.payload
|
35
|
-
data = initial_data(payload)
|
36
|
-
data.merge!(extract_status(payload))
|
37
|
-
data.merge!(extract_runtimes(event, payload))
|
38
|
-
data.merge!(extract_location)
|
39
|
-
data.merge!(extract_unpermitted_params)
|
40
|
-
data.merge!(custom_options(event))
|
41
|
-
end
|
42
|
-
|
43
|
-
def initial_data(payload)
|
44
|
-
{
|
45
|
-
method: payload[:method],
|
46
|
-
path: extract_path(payload),
|
47
|
-
format: extract_format(payload),
|
48
|
-
controller: payload[:params]['controller'],
|
49
|
-
action: payload[:params]['action']
|
50
|
-
}
|
51
|
-
end
|
52
|
-
|
53
|
-
def extract_path(payload)
|
54
|
-
path = payload[:path]
|
55
|
-
index = path.index('?')
|
56
|
-
index ? path[0, index] : path
|
57
|
-
end
|
58
|
-
|
59
|
-
if ::ActionPack::VERSION::MAJOR == 3 && ::ActionPack::VERSION::MINOR == 0
|
60
|
-
def extract_format(payload)
|
61
|
-
payload[:formats].first
|
62
|
-
end
|
63
|
-
else
|
64
|
-
def extract_format(payload)
|
65
|
-
payload[:format]
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def extract_status(payload)
|
70
|
-
if (status = payload[:status])
|
71
|
-
{ status: status.to_i }
|
72
|
-
elsif (error = payload[:exception])
|
73
|
-
exception, message = error
|
74
|
-
{ status: get_error_status_code(exception), error: "#{exception}: #{message}" }
|
75
|
-
else
|
76
|
-
{ status: 0 }
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def get_error_status_code(exception)
|
81
|
-
status = ActionDispatch::ExceptionWrapper.rescue_responses[exception]
|
82
|
-
Rack::Utils.status_code(status)
|
83
|
-
end
|
84
|
-
|
85
|
-
def custom_options(event)
|
86
|
-
Lograge.custom_options(event) || {}
|
87
|
-
end
|
88
|
-
|
89
|
-
def before_format(data, payload)
|
90
|
-
Lograge.before_format(data, payload)
|
91
|
-
end
|
92
|
-
|
93
|
-
def extract_runtimes(event, payload)
|
94
|
-
data = { duration: event.duration.to_f.round(2) }
|
95
|
-
data[:view] = payload[:view_runtime].to_f.round(2) if payload.key?(:view_runtime)
|
96
|
-
data[:db] = payload[:db_runtime].to_f.round(2) if payload.key?(:db_runtime)
|
97
|
-
data
|
98
|
-
end
|
99
|
-
|
100
|
-
def extract_location
|
101
|
-
location = Thread.current[:lograge_location]
|
102
|
-
return {} unless location
|
103
|
-
|
104
|
-
Thread.current[:lograge_location] = nil
|
105
|
-
{ location: location }
|
106
|
-
end
|
107
|
-
|
108
|
-
def extract_unpermitted_params
|
109
|
-
unpermitted_params = Thread.current[:lograge_unpermitted_params]
|
110
|
-
return {} unless unpermitted_params
|
111
|
-
|
112
|
-
Thread.current[:lograge_unpermitted_params] = nil
|
113
|
-
{ unpermitted_params: unpermitted_params }
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|