dry-logger 1.0.0.rc2 → 1.0.1
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 +27 -2
- data/lib/dry/logger/backends/core.rb +38 -0
- data/lib/dry/logger/backends/proxy.rb +65 -0
- data/lib/dry/logger/backends/stream.rb +6 -11
- data/lib/dry/logger/clock.rb +47 -0
- data/lib/dry/logger/constants.rb +55 -3
- data/lib/dry/logger/dispatcher.rb +81 -12
- data/lib/dry/logger/entry.rb +27 -33
- data/lib/dry/logger/formatters/colors.rb +84 -0
- data/lib/dry/logger/formatters/json.rb +27 -1
- data/lib/dry/logger/formatters/rack.rb +10 -2
- data/lib/dry/logger/formatters/string.rb +93 -26
- data/lib/dry/logger/formatters/structured.rb +16 -5
- data/lib/dry/logger/formatters/template.rb +92 -0
- data/lib/dry/logger/global.rb +123 -0
- data/lib/dry/logger/version.rb +1 -1
- data/lib/dry/logger.rb +45 -61
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e066ca44b228d611e0170f99488de6fa110d6ad2bdfea5de5e5f9e7513143019
|
4
|
+
data.tar.gz: d563a0fa78660c91e0757a66194269cfc565075d5a6f69356ebd1aec2cb18d6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f856780a1ef1fd89828a835c27f7c33b1fd4c5e518c5be8d9251c503d60e75f73b0a8b30e9dbeffdfea90dcc05bf9848fd31fb7ce972eba4b96c63bef6320165
|
7
|
+
data.tar.gz: 835f8a12cb10da5a459d4a8cc0b32f8e0c29afff000db89a1014c3686709bf6cd074e344ebcf6a4378c285f024c481df483527a8ec7e92b8fe79aad360628d4a
|
data/CHANGELOG.md
CHANGED
@@ -1,13 +1,38 @@
|
|
1
1
|
<!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
|
2
2
|
|
3
|
-
## 1.0.
|
3
|
+
## 1.0.1 2022-11-23
|
4
|
+
|
5
|
+
|
6
|
+
### Fixed
|
7
|
+
|
8
|
+
- Support for `log_if` in proxied loggers (via 81115320b490034ddf9dfe4f3775322b9271e0cd) (@solnic)
|
9
|
+
- Support exceptions and payloads in proxied loggers (via 93b3fd59ebbdc7e63620eb064694d58455df831f) (@solnic)
|
10
|
+
|
11
|
+
|
12
|
+
[Compare v1.0.0...v1.0.1](https://github.com/dry-rb/dry-logger/compare/v1.0.0...v1.0.1)
|
13
|
+
|
14
|
+
## 1.0.0 2022-11-17
|
4
15
|
|
5
16
|
This is a port of the original Hanami logger from hanami-utils extended with support for logging
|
6
|
-
dispatchers that can log to different destinations.
|
17
|
+
dispatchers that can log to different destinations and plenty more.
|
7
18
|
|
8
19
|
|
9
20
|
### Added
|
10
21
|
|
22
|
+
- Support arbitrary logging backends through proxy (via #12) (@solnic)
|
23
|
+
- Support for conditional logging when using arbitrary logging backends (via #13) (@solnic)
|
24
|
+
- Support for registering templates via `Dry::Logger.register_template` (via #14) (@solnic)
|
25
|
+
- Support for payload keys as template tokens (via #14) (@solnic)
|
26
|
+
- Support for payload value formatter methods, ie if there's `:verb` token your formatter can implement `format_verb(value)` (via #14) (@solnic)
|
27
|
+
- Support block-based setup (via #16) (@solnic)
|
28
|
+
- Support for defining cherry-picked keys from the payload in string templates (via #17) (@solnic)
|
29
|
+
- Support for `%<payload>s` template token. It will be replaced by a formatted payload, excluding any key that you specified explicitly in the template (via #17) (@solnic)
|
30
|
+
- Support for colorized output using color tags in templates (via #18) (@solnic)
|
31
|
+
- Support for `colorize: true` logger option which enables severity coloring in string formatter (via #18) (@solnic)
|
32
|
+
- `:details` template: `"[%<progname>s] [%<severity>s] [%<time>s] %<message>s %<payload>s"` (@solnic)
|
33
|
+
- A new option `on_crash` for setting up a logger-crash handling proc (via #21) (@solnic)
|
34
|
+
- Handle logger crashes by default using a simple `$stdout` logger (via #21) (@solnic)
|
35
|
+
- Support for regular logger backends that don't support `log?` predicate (@solnic)
|
11
36
|
- Support for providing a string template for log entries via `template` option (via #7) (@solnic)
|
12
37
|
- `:rack` string log formatter which inlines request info and displays params at the end (@solnic)
|
13
38
|
- Conditional log dispatch via `#log_if` backend's predicate (via #9) (@solnic)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/logger/constants"
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
module Logger
|
7
|
+
module Backends
|
8
|
+
module Core
|
9
|
+
# Return a proc used by the log? predicate
|
10
|
+
#
|
11
|
+
# @since 1.0.0
|
12
|
+
# @api private
|
13
|
+
attr_reader :log_if
|
14
|
+
|
15
|
+
# Set a predicate proc that checks if an entry should be logged by a given backend
|
16
|
+
#
|
17
|
+
# The predicate will receive {Entry} as its argument and should return true/false
|
18
|
+
#
|
19
|
+
# @param [Proc, #to_proc] spec A proc-like object
|
20
|
+
# @since 1.0.0
|
21
|
+
# @api public
|
22
|
+
def log_if=(spec)
|
23
|
+
@log_if = spec&.to_proc
|
24
|
+
end
|
25
|
+
|
26
|
+
# @since 1.0.0
|
27
|
+
# @api private
|
28
|
+
def log?(entry)
|
29
|
+
if log_if
|
30
|
+
log_if.call(entry)
|
31
|
+
else
|
32
|
+
true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
|
5
|
+
require "dry/logger/constants"
|
6
|
+
require "dry/logger/backends/core"
|
7
|
+
|
8
|
+
module Dry
|
9
|
+
module Logger
|
10
|
+
module Backends
|
11
|
+
# Logger proxy is used for regular loggers that don't work with log entries
|
12
|
+
#
|
13
|
+
# @since 1.0.0
|
14
|
+
# @api private
|
15
|
+
class Proxy < SimpleDelegator
|
16
|
+
include Core
|
17
|
+
|
18
|
+
LOG_METHODS.each do |method|
|
19
|
+
define_method(method) do |entry|
|
20
|
+
if entry.exception?
|
21
|
+
if __supports_payload__?(method)
|
22
|
+
__getobj__.public_send(method, entry.exception, **entry.payload.except(:exception))
|
23
|
+
else
|
24
|
+
__getobj__.public_send(method, entry.exception)
|
25
|
+
end
|
26
|
+
elsif __supports_payload__?(method)
|
27
|
+
if entry.message
|
28
|
+
__getobj__.public_send(method, entry.message, **entry.payload)
|
29
|
+
else
|
30
|
+
__getobj__.public_send(method, **entry.payload)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
__getobj__.public_send(method, entry.message)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# @since 1.0.0
|
39
|
+
# @api private
|
40
|
+
def log?(entry)
|
41
|
+
if log_if
|
42
|
+
log_if.call(entry)
|
43
|
+
else
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# @since 1.0.0
|
51
|
+
# @api private
|
52
|
+
def __supports_payload__?(method)
|
53
|
+
__supported_methods__[method] ||= __getobj__.method(method)
|
54
|
+
.parameters.last&.first.equal?(:keyrest)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @since 1.0.0
|
58
|
+
# @api private
|
59
|
+
def __supported_methods__
|
60
|
+
@__supported_methods__ ||= {}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -3,11 +3,14 @@
|
|
3
3
|
require "logger"
|
4
4
|
|
5
5
|
require "dry/logger/constants"
|
6
|
+
require "dry/logger/backends/core"
|
6
7
|
|
7
8
|
module Dry
|
8
9
|
module Logger
|
9
10
|
module Backends
|
10
11
|
class Stream < ::Logger
|
12
|
+
include Core
|
13
|
+
|
11
14
|
# @since 0.1.0
|
12
15
|
# @api private
|
13
16
|
attr_reader :stream
|
@@ -16,10 +19,6 @@ module Dry
|
|
16
19
|
# @api private
|
17
20
|
attr_reader :level
|
18
21
|
|
19
|
-
# @since 0.1.0
|
20
|
-
# @api public
|
21
|
-
attr_accessor :log_if
|
22
|
-
|
23
22
|
# @since 0.1.0
|
24
23
|
# @api private
|
25
24
|
def initialize(stream:, formatter:, level: DEFAULT_LEVEL, progname: nil, log_if: nil)
|
@@ -33,13 +32,9 @@ module Dry
|
|
33
32
|
end
|
34
33
|
|
35
34
|
# @since 1.0.0
|
36
|
-
# @api
|
37
|
-
def
|
38
|
-
|
39
|
-
log_if.call(entry)
|
40
|
-
else
|
41
|
-
true
|
42
|
-
end
|
35
|
+
# @api public
|
36
|
+
def inspect
|
37
|
+
%(#<#{self.class} stream=#{stream} level=#{level} log_if=#{log_if}>)
|
43
38
|
end
|
44
39
|
end
|
45
40
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module Logger
|
5
|
+
# @since 1.0.0
|
6
|
+
# @api private
|
7
|
+
class Clock
|
8
|
+
# @since 1.0.0
|
9
|
+
# @api private
|
10
|
+
attr_reader :unit
|
11
|
+
|
12
|
+
# @since 1.0.0
|
13
|
+
# @api private
|
14
|
+
def initialize(unit: :nanosecond)
|
15
|
+
@unit = unit
|
16
|
+
end
|
17
|
+
|
18
|
+
# @since 1.0.0
|
19
|
+
# @api private
|
20
|
+
def now
|
21
|
+
Time.now
|
22
|
+
end
|
23
|
+
|
24
|
+
# @since 1.0.0
|
25
|
+
# @api private
|
26
|
+
def now_utc
|
27
|
+
now.getutc
|
28
|
+
end
|
29
|
+
|
30
|
+
# @since 1.0.0
|
31
|
+
# @api private
|
32
|
+
def measure
|
33
|
+
start = current
|
34
|
+
result = yield
|
35
|
+
[result, current - start]
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# @since 1.0.0
|
41
|
+
# @api private
|
42
|
+
def current
|
43
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, unit)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/dry/logger/constants.rb
CHANGED
@@ -4,22 +4,67 @@ require "logger"
|
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
module Logger
|
7
|
-
|
7
|
+
# @since 1.0.0
|
8
|
+
# @api private
|
9
|
+
NEW_LINE = $/ # rubocop:disable Style/SpecialGlobalVars
|
10
|
+
|
11
|
+
# @since 1.0.0
|
12
|
+
# @api private
|
13
|
+
SEPARATOR = " "
|
14
|
+
|
15
|
+
# @since 1.0.0
|
16
|
+
# @api private
|
17
|
+
TAB = SEPARATOR * 2
|
18
|
+
|
19
|
+
# @since 1.0.0
|
20
|
+
# @api private
|
21
|
+
EMPTY_ARRAY = [].freeze
|
8
22
|
|
23
|
+
# @since 1.0.0
|
24
|
+
# @api private
|
25
|
+
EMPTY_HASH = {}.freeze
|
26
|
+
|
27
|
+
# @since 1.0.0
|
28
|
+
# @api private
|
29
|
+
LOG_METHODS = %i[debug info warn error fatal unknown].freeze
|
30
|
+
|
31
|
+
# @since 1.0.0
|
32
|
+
# @api private
|
9
33
|
BACKEND_METHODS = %i[close].freeze
|
10
34
|
|
35
|
+
# @since 1.0.0
|
36
|
+
# @api private
|
11
37
|
DEBUG = ::Logger::DEBUG
|
38
|
+
|
39
|
+
# @since 1.0.0
|
40
|
+
# @api private
|
12
41
|
INFO = ::Logger::INFO
|
42
|
+
|
43
|
+
# @since 1.0.0
|
44
|
+
# @api private
|
13
45
|
WARN = ::Logger::WARN
|
46
|
+
|
47
|
+
# @since 1.0.0
|
48
|
+
# @api private
|
14
49
|
ERROR = ::Logger::ERROR
|
50
|
+
|
51
|
+
# @since 1.0.0
|
52
|
+
# @api private
|
15
53
|
FATAL = ::Logger::FATAL
|
54
|
+
|
55
|
+
# @since 1.0.0
|
56
|
+
# @api private
|
16
57
|
UNKNOWN = ::Logger::UNKNOWN
|
17
58
|
|
59
|
+
# @since 1.0.0
|
60
|
+
# @api private
|
18
61
|
LEVEL_RANGE = (DEBUG..UNKNOWN).freeze
|
19
62
|
|
63
|
+
# @since 1.0.0
|
64
|
+
# @api private
|
20
65
|
DEFAULT_LEVEL = INFO
|
21
66
|
|
22
|
-
# @since
|
67
|
+
# @since 1.0.0
|
23
68
|
# @api private
|
24
69
|
LEVELS = Hash
|
25
70
|
.new { |levels, key|
|
@@ -35,9 +80,16 @@ module Dry
|
|
35
80
|
)
|
36
81
|
.freeze
|
37
82
|
|
38
|
-
|
83
|
+
# @since 1.0.0
|
84
|
+
# @api private
|
85
|
+
DEFAULT_OPTS = {level: DEFAULT_LEVEL, formatter: nil, progname: nil, log_if: nil}.freeze
|
39
86
|
|
87
|
+
# @since 1.0.0
|
88
|
+
# @api private
|
40
89
|
BACKEND_OPT_KEYS = DEFAULT_OPTS.keys.freeze
|
90
|
+
|
91
|
+
# @since 1.0.0
|
92
|
+
# @api private
|
41
93
|
FORMATTER_OPT_KEYS = %i[filter].freeze
|
42
94
|
end
|
43
95
|
end
|
@@ -4,6 +4,7 @@ require "logger"
|
|
4
4
|
require "pathname"
|
5
5
|
|
6
6
|
require "dry/logger/constants"
|
7
|
+
require "dry/logger/backends/proxy"
|
7
8
|
require "dry/logger/entry"
|
8
9
|
|
9
10
|
module Dry
|
@@ -37,21 +38,48 @@ module Dry
|
|
37
38
|
# @api private
|
38
39
|
attr_reader :options
|
39
40
|
|
41
|
+
# @since 1.0.0
|
42
|
+
# @api private
|
43
|
+
attr_reader :clock
|
44
|
+
|
45
|
+
# @since 1.0.0
|
46
|
+
# @api private
|
47
|
+
attr_reader :on_crash
|
48
|
+
|
40
49
|
# @since 1.0.0
|
41
50
|
# @api private
|
42
51
|
attr_reader :mutex
|
43
52
|
|
53
|
+
# @since 1.0.0
|
54
|
+
# @api private
|
55
|
+
CRASH_LOGGER = ::Logger.new($stdout).tap { |logger|
|
56
|
+
logger.formatter = -> (_, _, _, message) { "#{message}#{NEW_LINE}" }
|
57
|
+
logger.level = FATAL
|
58
|
+
}.freeze
|
59
|
+
|
60
|
+
# @since 1.0.0
|
61
|
+
# @api private
|
62
|
+
ON_CRASH = -> (progname:, exception:, message:, payload:) {
|
63
|
+
CRASH_LOGGER.fatal(Logger.templates[:crash] % {
|
64
|
+
severity: "FATAL",
|
65
|
+
progname: progname,
|
66
|
+
time: Time.now,
|
67
|
+
log_entry: [message, payload].map(&:to_s).reject(&:empty?).join(SEPARATOR),
|
68
|
+
exception: exception.class,
|
69
|
+
message: exception.message,
|
70
|
+
backtrace: TAB + exception.backtrace.join(NEW_LINE + TAB)
|
71
|
+
})
|
72
|
+
}
|
73
|
+
|
44
74
|
# Set up a dispatcher
|
45
75
|
#
|
46
76
|
# @since 1.0.0
|
47
|
-
#
|
48
|
-
# @param [String, Symbol] id The dispatcher id, can be used as progname in log entries
|
49
|
-
# @param [Hash] options Options that can be used for both the backend and formatter
|
77
|
+
# @api private
|
50
78
|
#
|
51
79
|
# @return [Dispatcher]
|
52
|
-
# @api public
|
53
80
|
def self.setup(id, **options)
|
54
81
|
dispatcher = new(id, **DEFAULT_OPTS, **options)
|
82
|
+
yield(dispatcher) if block_given?
|
55
83
|
dispatcher.add_backend if dispatcher.backends.empty?
|
56
84
|
dispatcher
|
57
85
|
end
|
@@ -64,12 +92,17 @@ module Dry
|
|
64
92
|
|
65
93
|
# @since 1.0.0
|
66
94
|
# @api private
|
67
|
-
def initialize(
|
95
|
+
def initialize(
|
96
|
+
id, backends: [], tags: [], context: self.class.default_context, **options
|
97
|
+
)
|
68
98
|
@id = id
|
69
99
|
@backends = backends
|
70
100
|
@options = {**options, progname: id}
|
71
101
|
@mutex = Mutex.new
|
72
102
|
@context = context
|
103
|
+
@tags = tags
|
104
|
+
@clock = Clock.new(**(options[:clock] || EMPTY_HASH))
|
105
|
+
@on_crash = options[:on_crash] || ON_CRASH
|
73
106
|
end
|
74
107
|
|
75
108
|
# Log an entry with UNKNOWN severity
|
@@ -143,8 +176,25 @@ module Dry
|
|
143
176
|
|
144
177
|
# Pass logging to all configured backends
|
145
178
|
#
|
179
|
+
# @example logging a message
|
180
|
+
# logger.log(:info, "Hello World")
|
181
|
+
#
|
182
|
+
# @example logging payload
|
183
|
+
# logger.log(:info, verb: "GET", path: "/users")
|
184
|
+
#
|
185
|
+
# @example logging message and payload
|
186
|
+
# logger.log(:info, "User index request", verb: "GET", path: "/users")
|
187
|
+
#
|
188
|
+
# @example logging exception
|
189
|
+
# begin
|
190
|
+
# # things that may raise
|
191
|
+
# rescue => e
|
192
|
+
# logger.log(:error, e)
|
193
|
+
# raise e
|
194
|
+
# end
|
195
|
+
#
|
146
196
|
# @param [Symbol] severity The log severity name
|
147
|
-
# @param [String
|
197
|
+
# @param [String] message Optional message
|
148
198
|
# @param [Hash] payload Optional log entry payload
|
149
199
|
#
|
150
200
|
# @since 1.0.0
|
@@ -155,17 +205,24 @@ module Dry
|
|
155
205
|
when Hash then log(severity, nil, **message)
|
156
206
|
else
|
157
207
|
entry = Entry.new(
|
208
|
+
clock: clock,
|
158
209
|
progname: id,
|
159
210
|
severity: severity,
|
211
|
+
tags: @tags,
|
160
212
|
message: message,
|
161
213
|
payload: {**context, **payload}
|
162
214
|
)
|
163
215
|
|
164
216
|
each_backend do |backend|
|
165
|
-
backend.__send__(severity, entry) if
|
217
|
+
backend.__send__(severity, entry) if backend.log?(entry)
|
218
|
+
rescue StandardError => e
|
219
|
+
on_crash.(progname: id, exception: e, message: message, payload: payload)
|
166
220
|
end
|
167
221
|
end
|
168
222
|
|
223
|
+
true
|
224
|
+
rescue StandardError => e
|
225
|
+
on_crash.(progname: id, exception: e, message: message, payload: payload)
|
169
226
|
true
|
170
227
|
end
|
171
228
|
|
@@ -182,11 +239,11 @@ module Dry
|
|
182
239
|
#
|
183
240
|
# @since 1.0.0
|
184
241
|
# @api public
|
185
|
-
def tagged(
|
186
|
-
|
242
|
+
def tagged(*tags)
|
243
|
+
@tags.concat(tags)
|
187
244
|
yield
|
188
245
|
ensure
|
189
|
-
|
246
|
+
@tags = []
|
190
247
|
end
|
191
248
|
|
192
249
|
# Add a new backend to an existing dispatcher
|
@@ -200,15 +257,27 @@ module Dry
|
|
200
257
|
# @return [Dispatcher]
|
201
258
|
# @api public
|
202
259
|
def add_backend(instance = nil, **backend_options)
|
203
|
-
backend =
|
260
|
+
backend =
|
261
|
+
case (instance ||= Dry::Logger.new(**options, **backend_options))
|
262
|
+
when Backends::Stream then instance
|
263
|
+
else Backends::Proxy.new(instance)
|
264
|
+
end
|
265
|
+
|
204
266
|
yield(backend) if block_given?
|
267
|
+
|
205
268
|
backends << backend
|
206
269
|
self
|
207
270
|
end
|
208
271
|
|
272
|
+
# @since 1.0.0
|
273
|
+
# @api public
|
274
|
+
def inspect
|
275
|
+
%(#<#{self.class} id=#{id} options=#{options} backends=#{backends}>)
|
276
|
+
end
|
277
|
+
|
209
278
|
# @since 1.0.0
|
210
279
|
# @api private
|
211
|
-
def each_backend(
|
280
|
+
def each_backend(&block)
|
212
281
|
mutex.synchronize do
|
213
282
|
backends.each(&block)
|
214
283
|
end
|
data/lib/dry/logger/entry.rb
CHANGED
@@ -10,14 +10,6 @@ module Dry
|
|
10
10
|
class Entry
|
11
11
|
include Enumerable
|
12
12
|
|
13
|
-
# @since 1.0.0
|
14
|
-
# @api private
|
15
|
-
EMPTY_PAYLOAD = {}.freeze
|
16
|
-
|
17
|
-
# @since 1.0.0
|
18
|
-
# @api private
|
19
|
-
EMPTY_BACKTRACE = [].freeze
|
20
|
-
|
21
13
|
# @since 1.0.0
|
22
14
|
# @api public
|
23
15
|
attr_reader :progname
|
@@ -28,16 +20,19 @@ module Dry
|
|
28
20
|
|
29
21
|
# @since 1.0.0
|
30
22
|
# @api public
|
31
|
-
attr_reader :
|
23
|
+
attr_reader :tags
|
32
24
|
|
33
25
|
# @since 1.0.0
|
34
26
|
# @api public
|
35
|
-
attr_reader :
|
27
|
+
attr_reader :level
|
36
28
|
|
37
29
|
# @since 1.0.0
|
38
30
|
# @api public
|
39
31
|
attr_reader :message
|
40
|
-
|
32
|
+
|
33
|
+
# @since 1.0.0
|
34
|
+
# @api public
|
35
|
+
attr_reader :exception
|
41
36
|
|
42
37
|
# @since 1.0.0
|
43
38
|
# @api public
|
@@ -45,14 +40,23 @@ module Dry
|
|
45
40
|
|
46
41
|
# @since 1.0.0
|
47
42
|
# @api private
|
48
|
-
|
43
|
+
attr_reader :clock
|
44
|
+
|
45
|
+
# @since 1.0.0
|
46
|
+
# @api private
|
47
|
+
# rubocop:disable Metrics/ParameterLists
|
48
|
+
def initialize(clock:, progname:, severity:, tags: EMPTY_ARRAY, message: nil,
|
49
|
+
payload: EMPTY_HASH)
|
50
|
+
@clock = clock
|
49
51
|
@progname = progname
|
50
|
-
@severity = severity.to_s
|
52
|
+
@severity = severity.to_s
|
53
|
+
@tags = tags
|
51
54
|
@level = LEVELS.fetch(severity.to_s)
|
52
|
-
@
|
53
|
-
@
|
55
|
+
@message = message unless message.is_a?(Exception)
|
56
|
+
@exception = message if message.is_a?(Exception)
|
54
57
|
@payload = build_payload(payload)
|
55
58
|
end
|
59
|
+
# rubocop:enable Metrics/ParameterLists
|
56
60
|
|
57
61
|
# @since 1.0.0
|
58
62
|
# @api public
|
@@ -99,7 +103,7 @@ module Dry
|
|
99
103
|
# @since 1.0.0
|
100
104
|
# @api public
|
101
105
|
def exception?
|
102
|
-
|
106
|
+
!exception.nil?
|
103
107
|
end
|
104
108
|
|
105
109
|
# @since 1.0.0
|
@@ -109,28 +113,21 @@ module Dry
|
|
109
113
|
end
|
110
114
|
|
111
115
|
# @since 1.0.0
|
112
|
-
# @api
|
113
|
-
def
|
114
|
-
|
116
|
+
# @api public
|
117
|
+
def tag?(value)
|
118
|
+
tags.include?(value)
|
115
119
|
end
|
116
120
|
|
117
121
|
# @since 1.0.0
|
118
122
|
# @api private
|
119
123
|
def meta
|
120
|
-
@meta ||= {progname: progname, severity: severity, time:
|
124
|
+
@meta ||= {progname: progname, severity: severity, time: clock.now}
|
121
125
|
end
|
122
126
|
|
123
127
|
# @since 1.0.0
|
124
128
|
# @api private
|
125
|
-
def
|
126
|
-
@
|
127
|
-
end
|
128
|
-
|
129
|
-
# @since 1.0.0
|
130
|
-
# @api private
|
131
|
-
def as_json
|
132
|
-
# TODO: why are we enforcing UTC in JSON but not in String?
|
133
|
-
@as_json ||= to_h.merge(message: message, time: utc_time).compact
|
129
|
+
def to_h
|
130
|
+
@to_h ||= meta.merge(message: message, **payload)
|
134
131
|
end
|
135
132
|
|
136
133
|
# @since 1.0.0
|
@@ -146,10 +143,7 @@ module Dry
|
|
146
143
|
# @api private
|
147
144
|
def build_payload(payload)
|
148
145
|
if exception?
|
149
|
-
{
|
150
|
-
backtrace: exception.backtrace || EMPTY_BACKTRACE,
|
151
|
-
error: exception.class,
|
152
|
-
**payload}
|
146
|
+
{exception: exception, **payload}
|
153
147
|
else
|
154
148
|
payload
|
155
149
|
end
|