hanami-utils 2.0.0.alpha6 → 2.0.0.rc1
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/CHANGELOG.md +157 -1
- data/README.md +9 -18
- data/hanami-utils.gemspec +0 -1
- data/lib/hanami/utils/string.rb +1 -1
- data/lib/hanami/utils/version.rb +2 -4
- metadata +2 -8
- data/lib/hanami/interactor.rb +0 -619
- data/lib/hanami/logger/colorizer.rb +0 -105
- data/lib/hanami/logger/filter.rb +0 -144
- data/lib/hanami/logger/formatter.rb +0 -183
- data/lib/hanami/logger.rb +0 -362
- data/lib/hanami/utils/basic_object.rb +0 -141
@@ -1,105 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "logger"
|
4
|
-
require "hanami/utils/shell_color"
|
5
|
-
|
6
|
-
module Hanami
|
7
|
-
class Logger < ::Logger
|
8
|
-
# Null colorizer for logger streams that aren't a TTY (eg. files)
|
9
|
-
#
|
10
|
-
# @since 1.2.0
|
11
|
-
# @api private
|
12
|
-
class NullColorizer
|
13
|
-
# @since 1.2.0
|
14
|
-
# @api private
|
15
|
-
def call(app, severity, datetime, _progname)
|
16
|
-
::Hash[
|
17
|
-
app: app,
|
18
|
-
severity: severity,
|
19
|
-
time: datetime,
|
20
|
-
]
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# Hanami::Logger Default Colorizer
|
25
|
-
#
|
26
|
-
# This colorizer takes in parts of the log message and returns them with
|
27
|
-
# proper shellcode to colorize when displayed to a tty.
|
28
|
-
#
|
29
|
-
# @since 1.2.0
|
30
|
-
# @api private
|
31
|
-
class Colorizer < NullColorizer
|
32
|
-
def initialize(colors: COLORS)
|
33
|
-
@colors = colors
|
34
|
-
end
|
35
|
-
|
36
|
-
# Colorize the inputs
|
37
|
-
#
|
38
|
-
# @param app [#to_s] the app name
|
39
|
-
# @param severity [#to_s] log severity
|
40
|
-
# @param datetime [#to_s] timestamp
|
41
|
-
# @param _progname [#to_s] program name - ignored, accepted for
|
42
|
-
# compatibility with Ruby's Logger
|
43
|
-
#
|
44
|
-
# @return [::Hash] an Hash containing the keys `:app`, `:severity`, and `:time`
|
45
|
-
def call(app, severity, datetime, _progname)
|
46
|
-
::Hash[
|
47
|
-
app: app(app),
|
48
|
-
severity: severity(severity),
|
49
|
-
time: datetime(datetime),
|
50
|
-
]
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
|
-
|
55
|
-
# The colors defined for the three parts of the log message
|
56
|
-
#
|
57
|
-
# @since 1.2.0
|
58
|
-
# @api private
|
59
|
-
COLORS = ::Hash[
|
60
|
-
app: :blue,
|
61
|
-
datetime: :cyan,
|
62
|
-
].freeze
|
63
|
-
|
64
|
-
# @since 1.2.0
|
65
|
-
# @api private
|
66
|
-
LEVELS = ::Hash[
|
67
|
-
Hanami::Logger::DEBUG => :cyan,
|
68
|
-
Hanami::Logger::INFO => :magenta,
|
69
|
-
Hanami::Logger::WARN => :yellow,
|
70
|
-
Hanami::Logger::ERROR => :red,
|
71
|
-
Hanami::Logger::FATAL => :red,
|
72
|
-
Hanami::Logger::UNKNOWN => :blue,
|
73
|
-
].freeze
|
74
|
-
|
75
|
-
attr_reader :colors
|
76
|
-
|
77
|
-
# @since 1.2.0
|
78
|
-
# @api private
|
79
|
-
def app(input)
|
80
|
-
colorize(input, color: colors.fetch(:app, nil))
|
81
|
-
end
|
82
|
-
|
83
|
-
# @since 1.2.0
|
84
|
-
# @api private
|
85
|
-
def severity(input)
|
86
|
-
color = LEVELS.fetch(Hanami::Logger.level(input), :gray)
|
87
|
-
colorize(input, color: color)
|
88
|
-
end
|
89
|
-
|
90
|
-
# @since 1.2.0
|
91
|
-
# @api private
|
92
|
-
def datetime(input)
|
93
|
-
colorize(input, color: colors.fetch(:datetime, nil))
|
94
|
-
end
|
95
|
-
|
96
|
-
# @since 1.2.0
|
97
|
-
# @api private
|
98
|
-
def colorize(message, color:)
|
99
|
-
return message if color.nil?
|
100
|
-
|
101
|
-
Hanami::Utils::ShellColor.call(message, color: color)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
data/lib/hanami/logger/filter.rb
DELETED
@@ -1,144 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "logger"
|
4
|
-
|
5
|
-
module Hanami
|
6
|
-
class Logger < ::Logger
|
7
|
-
# Filtering logic
|
8
|
-
#
|
9
|
-
# @since 1.1.0
|
10
|
-
# @api private
|
11
|
-
class Filter
|
12
|
-
# @since 1.3.7
|
13
|
-
# @api private
|
14
|
-
FILTERED_VALUE = "[FILTERED]"
|
15
|
-
|
16
|
-
def initialize(filters = [], mask: FILTERED_VALUE)
|
17
|
-
@filters = filters
|
18
|
-
@mask = mask
|
19
|
-
end
|
20
|
-
|
21
|
-
# @since 1.1.0
|
22
|
-
# @api private
|
23
|
-
def call(params)
|
24
|
-
_filter(_copy_params(params))
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
# @since 1.1.0
|
30
|
-
# @api private
|
31
|
-
attr_reader :filters
|
32
|
-
|
33
|
-
# @since 1.3.7
|
34
|
-
# @api private
|
35
|
-
attr_reader :mask
|
36
|
-
|
37
|
-
# This is a simple deep merge to merge the original input
|
38
|
-
# with the filtered hash which contains '[FILTERED]' string.
|
39
|
-
#
|
40
|
-
# It only deep-merges if the conflict values are both hashes.
|
41
|
-
#
|
42
|
-
# @since 1.3.7
|
43
|
-
# @api private
|
44
|
-
def _deep_merge(original_hash, filtered_hash)
|
45
|
-
original_hash.merge(filtered_hash) do |_key, original_item, filtered_item|
|
46
|
-
if original_item.is_a?(Hash) && filtered_item.is_a?(Hash)
|
47
|
-
_deep_merge(original_item, filtered_item)
|
48
|
-
elsif filtered_item == FILTERED_VALUE
|
49
|
-
filtered_item
|
50
|
-
else
|
51
|
-
original_item
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# @since 1.1.0
|
57
|
-
# @api private
|
58
|
-
def _filtered_keys(hash)
|
59
|
-
_key_paths(hash).select { |key| filters.any? { |filter| key =~ %r{(\.|\A)#{filter}(\.|\z)} } }
|
60
|
-
end
|
61
|
-
|
62
|
-
# @since 1.1.0
|
63
|
-
# @api private
|
64
|
-
def _key_paths(hash, base = nil)
|
65
|
-
hash.inject([]) do |results, (k, v)|
|
66
|
-
results + (_key_paths?(v) ? _key_paths(v, _build_path(base, k)) : [_build_path(base, k)])
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# @since 1.1.0
|
71
|
-
# @api private
|
72
|
-
def _build_path(base, key)
|
73
|
-
[base, key.to_s].compact.join(".")
|
74
|
-
end
|
75
|
-
|
76
|
-
# @since 1.1.0
|
77
|
-
# @api private
|
78
|
-
def _actual_keys(hash, keys)
|
79
|
-
search_in = hash
|
80
|
-
|
81
|
-
keys.inject([]) do |res, key|
|
82
|
-
correct_key = search_in.key?(key.to_sym) ? key.to_sym : key
|
83
|
-
search_in = search_in[correct_key]
|
84
|
-
res + [correct_key]
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# Check if the given value can be iterated (`Enumerable`) and that isn't a `File`.
|
89
|
-
# This is useful to detect closed `Tempfiles`.
|
90
|
-
#
|
91
|
-
# @since 1.3.5
|
92
|
-
# @api private
|
93
|
-
#
|
94
|
-
# @see https://github.com/hanami/utils/pull/342
|
95
|
-
def _key_paths?(value)
|
96
|
-
value.is_a?(Enumerable) && !value.is_a?(File)
|
97
|
-
end
|
98
|
-
|
99
|
-
# @since 1.3.7
|
100
|
-
# @api private
|
101
|
-
def _deep_dup(hash)
|
102
|
-
hash.transform_values do |value|
|
103
|
-
if value.is_a?(Hash)
|
104
|
-
_deep_dup(value)
|
105
|
-
else
|
106
|
-
_key_paths?(value) ? value.dup : value
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
# @since 1.3.7
|
112
|
-
# @api private
|
113
|
-
def _copy_params(params)
|
114
|
-
case params
|
115
|
-
when Hash
|
116
|
-
_deep_dup(params)
|
117
|
-
when Array
|
118
|
-
params.map { |hash| _deep_dup(hash) }
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
# @since 1.3.7
|
123
|
-
# @api private
|
124
|
-
def _filter_hash(hash)
|
125
|
-
_filtered_keys(hash).each do |key|
|
126
|
-
*keys, last = _actual_keys(hash, key.split("."))
|
127
|
-
keys.inject(hash, :fetch)[last] = mask
|
128
|
-
end
|
129
|
-
hash
|
130
|
-
end
|
131
|
-
|
132
|
-
# @since 1.3.7
|
133
|
-
# @api private
|
134
|
-
def _filter(params)
|
135
|
-
case params
|
136
|
-
when Hash
|
137
|
-
_filter_hash(params)
|
138
|
-
when Array
|
139
|
-
params.map { |hash| _filter_hash(hash) }
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
@@ -1,183 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "set"
|
4
|
-
require "json"
|
5
|
-
require "logger"
|
6
|
-
require "hanami/utils/json"
|
7
|
-
require "hanami/utils/class_attribute"
|
8
|
-
require "hanami/utils/query_string"
|
9
|
-
|
10
|
-
module Hanami
|
11
|
-
class Logger < ::Logger
|
12
|
-
# Hanami::Logger default formatter.
|
13
|
-
# This formatter returns string in key=value format.
|
14
|
-
#
|
15
|
-
# @since 0.5.0
|
16
|
-
# @api private
|
17
|
-
#
|
18
|
-
# @see http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger/Formatter.html
|
19
|
-
class Formatter < ::Logger::Formatter
|
20
|
-
require "hanami/logger/filter"
|
21
|
-
require "hanami/logger/colorizer"
|
22
|
-
|
23
|
-
# @since 0.8.0
|
24
|
-
# @api private
|
25
|
-
SEPARATOR = " "
|
26
|
-
|
27
|
-
# @since 0.8.0
|
28
|
-
# @api private
|
29
|
-
NEW_LINE = $/
|
30
|
-
|
31
|
-
# @since 1.0.0
|
32
|
-
# @api private
|
33
|
-
RESERVED_KEYS = %i[app severity time].freeze
|
34
|
-
|
35
|
-
include Utils::ClassAttribute
|
36
|
-
|
37
|
-
class_attribute :subclasses
|
38
|
-
self.subclasses = Set.new
|
39
|
-
|
40
|
-
def self.fabricate(formatter, application_name, filters, colorizer)
|
41
|
-
fabricated_formatter = _formatter_instance(formatter)
|
42
|
-
|
43
|
-
fabricated_formatter.application_name = application_name
|
44
|
-
fabricated_formatter.filter = Filter.new(filters)
|
45
|
-
fabricated_formatter.colorizer = colorizer
|
46
|
-
|
47
|
-
fabricated_formatter
|
48
|
-
end
|
49
|
-
|
50
|
-
# @api private
|
51
|
-
def self.inherited(subclass)
|
52
|
-
super
|
53
|
-
subclasses << subclass
|
54
|
-
end
|
55
|
-
|
56
|
-
# @api private
|
57
|
-
def self.eligible?(name)
|
58
|
-
name == :default
|
59
|
-
end
|
60
|
-
|
61
|
-
# @api private
|
62
|
-
# @since 1.1.0
|
63
|
-
def self._formatter_instance(formatter)
|
64
|
-
case formatter
|
65
|
-
when Symbol
|
66
|
-
(subclasses.find { |s| s.eligible?(formatter) } || self).new
|
67
|
-
when nil
|
68
|
-
new
|
69
|
-
else
|
70
|
-
formatter
|
71
|
-
end
|
72
|
-
end
|
73
|
-
private_class_method :_formatter_instance
|
74
|
-
|
75
|
-
# @since 0.5.0
|
76
|
-
# @api private
|
77
|
-
attr_writer :application_name
|
78
|
-
|
79
|
-
# @since 1.0.0
|
80
|
-
# @api private
|
81
|
-
attr_reader :application_name
|
82
|
-
|
83
|
-
# @since 1.2.0
|
84
|
-
# @api private
|
85
|
-
attr_writer :filter
|
86
|
-
|
87
|
-
# @since 1.2.0
|
88
|
-
# @api private
|
89
|
-
attr_writer :colorizer
|
90
|
-
|
91
|
-
# @since 0.5.0
|
92
|
-
# @api private
|
93
|
-
#
|
94
|
-
# @see http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger/Formatter.html#method-i-call
|
95
|
-
def call(severity, time, progname, msg)
|
96
|
-
colorized = @colorizer.call(application_name, severity, time, progname)
|
97
|
-
colorized.merge!(_message_hash(msg))
|
98
|
-
|
99
|
-
_format(colorized)
|
100
|
-
end
|
101
|
-
|
102
|
-
private
|
103
|
-
|
104
|
-
# @since 0.8.0
|
105
|
-
# @api private
|
106
|
-
def _message_hash(message)
|
107
|
-
case message
|
108
|
-
when ::Hash
|
109
|
-
@filter.call(message)
|
110
|
-
when Exception
|
111
|
-
::Hash[
|
112
|
-
message: message.message,
|
113
|
-
backtrace: message.backtrace || [],
|
114
|
-
error: message.class
|
115
|
-
]
|
116
|
-
else
|
117
|
-
::Hash[message: message]
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
# @since 0.8.0
|
122
|
-
# @api private
|
123
|
-
def _format(hash)
|
124
|
-
"#{_line_front_matter(hash.delete(:app), hash.delete(:severity), hash.delete(:time))}#{SEPARATOR}#{_format_message(hash)}" # rubocop:disable Layout/LineLength
|
125
|
-
end
|
126
|
-
|
127
|
-
# @since 1.2.0
|
128
|
-
# @api private
|
129
|
-
def _line_front_matter(*args)
|
130
|
-
args.map { |string| "[#{string}]" }.join(SEPARATOR)
|
131
|
-
end
|
132
|
-
|
133
|
-
# @since 1.2.0
|
134
|
-
# @api private
|
135
|
-
def _format_message(hash)
|
136
|
-
if hash.key?(:error)
|
137
|
-
_format_error(hash)
|
138
|
-
elsif hash.key?(:params)
|
139
|
-
"#{hash.values.join(SEPARATOR)}#{NEW_LINE}"
|
140
|
-
else
|
141
|
-
"#{Utils::QueryString.call(hash[:message] || hash)}#{NEW_LINE}"
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
# @since 1.2.0
|
146
|
-
# @api private
|
147
|
-
def _format_error(hash)
|
148
|
-
result = [hash[:error], hash[:message]].compact.join(": ").concat(NEW_LINE)
|
149
|
-
hash[:backtrace].each do |line|
|
150
|
-
result << "from #{line}#{NEW_LINE}"
|
151
|
-
end
|
152
|
-
|
153
|
-
result
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
# Hanami::Logger JSON formatter.
|
158
|
-
# This formatter returns string in JSON format.
|
159
|
-
#
|
160
|
-
# @since 0.5.0
|
161
|
-
# @api private
|
162
|
-
class JSONFormatter < Formatter
|
163
|
-
# @api private
|
164
|
-
def self.eligible?(name)
|
165
|
-
name == :json
|
166
|
-
end
|
167
|
-
|
168
|
-
# @api private
|
169
|
-
def colorizer=(*)
|
170
|
-
@colorizer = NullColorizer.new
|
171
|
-
end
|
172
|
-
|
173
|
-
private
|
174
|
-
|
175
|
-
# @since 0.8.0
|
176
|
-
# @api private
|
177
|
-
def _format(hash)
|
178
|
-
hash[:time] = hash[:time].utc.iso8601
|
179
|
-
Hanami::Utils::Json.generate(hash) + NEW_LINE
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|