lumberjack_capture_device 1.2.1 → 1.2.2
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 +11 -0
- data/VERSION +1 -1
- data/lib/lumberjack/capture_device/include_log_entry_matcher.rb +29 -17
- data/lib/lumberjack/capture_device.rb +70 -24
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9147e66264c0eeebb01f7c04df1b6e18ab64bc4db3337e968d6cd1d2201fef7f
|
4
|
+
data.tar.gz: f01bf2e332024e9ef26ef703b374956e5f17c6bb4f351cb4518b1591b62dd992
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e5ae9f94313a18f793b299998c9760aaa8d7bf5d8f462f48b4519f83c8844893ff894e5b570e31b15d55dc1ad9d25ee723529dc72e51db83d5060a4bcf1597c
|
7
|
+
data.tar.gz: 06a11ff5e4c5f3afed7cda12fa2f5f9bf94369f6c5b382d7118622136b7f1507d67c1e68ca472c6c38d1bf38cd3aa6db66f4859a145f78b9b69a8f9f4024a634
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## 1.2.2
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
- Improved failure message on RSpec matcher.
|
12
|
+
|
13
|
+
### Added
|
14
|
+
|
15
|
+
- `Lumberjack::CaptureDevice` now acts as an enumerable object.
|
16
|
+
- Exposed helper methods for formatting log entries.
|
17
|
+
|
7
18
|
## 1.2.1
|
8
19
|
|
9
20
|
### Changed
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.2.
|
1
|
+
1.2.2
|
@@ -16,7 +16,7 @@ class Lumberjack::CaptureDevice::IncludeLogEntryMatcher
|
|
16
16
|
|
17
17
|
def failure_message
|
18
18
|
if valid_captured_logger?
|
19
|
-
formatted_failure_message(@captured_logger, @expected_hash
|
19
|
+
formatted_failure_message(@captured_logger, @expected_hash)
|
20
20
|
else
|
21
21
|
wrong_object_type_message(@captured_logger)
|
22
22
|
end
|
@@ -24,7 +24,7 @@ class Lumberjack::CaptureDevice::IncludeLogEntryMatcher
|
|
24
24
|
|
25
25
|
def failure_message_when_negated
|
26
26
|
if valid_captured_logger?
|
27
|
-
|
27
|
+
formatted_negated_failure_message(@captured_logger, @expected_hash)
|
28
28
|
else
|
29
29
|
wrong_object_type_message(@captured_logger)
|
30
30
|
end
|
@@ -44,23 +44,35 @@ class Lumberjack::CaptureDevice::IncludeLogEntryMatcher
|
|
44
44
|
"Expected a Lumberjack::CaptureDevice object, but received a #{captured_logger.class}."
|
45
45
|
end
|
46
46
|
|
47
|
-
def formatted_failure_message(captured_logger, expected_hash
|
48
|
-
|
49
|
-
|
50
|
-
"
|
51
|
-
|
47
|
+
def formatted_failure_message(captured_logger, expected_hash)
|
48
|
+
message = +"expected logs to include entry:\n" \
|
49
|
+
"#{Lumberjack::CaptureDevice.formatted_expectation(expected_hash, indent: 2)}\n\n" \
|
50
|
+
"Captured #{captured_logger.length} log #{(captured_logger.length == 1) ? "entry" : "entries"}"
|
51
|
+
|
52
|
+
if captured_logger.length > 0
|
53
|
+
message << "\n----------------------\n"
|
54
|
+
captured_logger.each do |entry|
|
55
|
+
message << "#{Lumberjack::CaptureDevice.formatted_entry(entry)}\n"
|
56
|
+
end
|
57
|
+
end
|
52
58
|
|
59
|
+
closest_match = captured_logger.closest_match(**expected_hash)
|
53
60
|
if closest_match
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
message = "#{message}\n\nClosest match found:" \
|
62
|
+
"#{Lumberjack::CaptureDevice.formatted_expectation(closest_match, indent: 2)}"
|
63
|
+
end
|
64
|
+
|
65
|
+
message
|
66
|
+
end
|
67
|
+
|
68
|
+
def formatted_negated_failure_message(captured_logger, expected_hash)
|
69
|
+
message = "expected logs not to include entry:\n" \
|
70
|
+
"#{Lumberjack::CaptureDevice.formatted_expectation(expected_hash, indent: 2)}"
|
71
|
+
|
72
|
+
match = captured_logger.match(**expected_hash)
|
73
|
+
if match
|
74
|
+
message = "#{message}\n\nFound entry:\n" \
|
75
|
+
"#{Lumberjack::CaptureDevice.formatted_expectation(match, indent: 2)}"
|
64
76
|
end
|
65
77
|
|
66
78
|
message
|
@@ -8,8 +8,9 @@ module Lumberjack
|
|
8
8
|
class CaptureDevice < Lumberjack::Device
|
9
9
|
VERSION = File.read(File.join(__dir__, "..", "..", "VERSION"))
|
10
10
|
|
11
|
-
|
11
|
+
include Enumerable
|
12
12
|
|
13
|
+
attr_reader :buffer
|
13
14
|
class << self
|
14
15
|
# Capture the entries written by the logger within a block. Within the block all log
|
15
16
|
# entries will be written to a CaptureDevice rather than to the normal output for
|
@@ -48,18 +49,51 @@ module Lumberjack
|
|
48
49
|
device
|
49
50
|
end
|
50
51
|
|
51
|
-
|
52
|
+
# Helper method to format a log entry for display.
|
53
|
+
#
|
54
|
+
# @param entry [Lumberjack::LogEntry] The log entry to format.
|
55
|
+
# @param indent [Integer] The indentation to prefix on every line.
|
56
|
+
# @return [String] The formatted log entry.
|
57
|
+
def formatted_entry(entry, indent: 0)
|
58
|
+
indent_str = " " * indent
|
59
|
+
timestamp = entry.time.strftime("%Y-%m-%d %H:%M:%S")
|
60
|
+
formatted = +"#{indent_str}#{timestamp} #{entry.severity_label}: #{entry.message}"
|
61
|
+
formatted << "\n#{indent_str} progname: #{entry.progname}" if entry.progname.to_s != ""
|
62
|
+
if entry.tags && !entry.tags.empty?
|
63
|
+
Lumberjack::Utils.flatten_tags(entry.tags).to_a.sort_by(&:first).each do |name, value|
|
64
|
+
formatted << "\n#{indent_str} #{name}: #{value}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
formatted
|
68
|
+
end
|
69
|
+
|
70
|
+
# Format a log entry or expectation hash into a more human readable format.
|
71
|
+
#
|
72
|
+
# @param expectation [Hash, Lumberjack::LogEntry] The expectation or log entry to format.
|
73
|
+
# @return [String] A formatted string representation of the expectation or log entry.
|
74
|
+
def formatted_expectation(expectation, indent: 0)
|
75
|
+
if expectation.is_a?(Lumberjack::LogEntry)
|
76
|
+
expectation = {
|
77
|
+
"level" => expectation.severity_label,
|
78
|
+
"message" => expectation.message,
|
79
|
+
"progname" => expectation.progname,
|
80
|
+
"tags" => expectation.tags
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
52
84
|
expectation = expectation.transform_keys(&:to_s).compact
|
85
|
+
|
53
86
|
message = []
|
54
|
-
|
55
|
-
message << "
|
56
|
-
message << "
|
87
|
+
indent_str = " " * indent
|
88
|
+
message << "#{indent_str}level: #{expectation["level"].inspect}" if expectation.include?("level")
|
89
|
+
message << "#{indent_str}message: #{expectation["message"].inspect}" if expectation.include?("message")
|
90
|
+
message << "#{indent_str}progname: #{expectation["progname"].inspect}" if expectation.include?("progname")
|
57
91
|
if expectation["tags"].is_a?(Hash) && !expectation["tags"].empty?
|
58
92
|
tags = Lumberjack::Utils.flatten_tags(expectation["tags"])
|
59
93
|
prefix = "tags: "
|
60
|
-
tags.each do |name, value|
|
94
|
+
tags.sort_by(&:first).each do |name, value|
|
61
95
|
message << "#{prefix} #{name}: #{value.inspect}"
|
62
|
-
prefix = " "
|
96
|
+
prefix = "#{indent_str} "
|
63
97
|
end
|
64
98
|
end
|
65
99
|
message.join("\n")
|
@@ -107,7 +141,7 @@ module Lumberjack
|
|
107
141
|
# @option args [String] :progname The program name to match against the log entries.
|
108
142
|
# @return [Boolean] True if any entries match the specified filters, false otherwise.
|
109
143
|
def include?(args)
|
110
|
-
|
144
|
+
!!match(**args)
|
111
145
|
end
|
112
146
|
|
113
147
|
# Return all the captured entries that match the specified filters. These filters are
|
@@ -120,8 +154,8 @@ module Lumberjack
|
|
120
154
|
# `{foo: {bar: "value"}}`).
|
121
155
|
# @param limit [Integer, nil] The maximum number of entries to return. If nil, all matching entries
|
122
156
|
# will be returned.
|
123
|
-
# @return [Array<Lumberjack::
|
124
|
-
def extract(message: nil, level: nil, tags: nil,
|
157
|
+
# @return [Array<Lumberjack::LogEntry>] An array of log entries that match the specified filters.
|
158
|
+
def extract(message: nil, level: nil, tags: nil, progname: nil, limit: nil)
|
125
159
|
matches = []
|
126
160
|
|
127
161
|
if level
|
@@ -139,6 +173,17 @@ module Lumberjack
|
|
139
173
|
matches
|
140
174
|
end
|
141
175
|
|
176
|
+
# Return the first entry that matches the specified filters.
|
177
|
+
#
|
178
|
+
# @param message [String, Regexp, nil] The message to match against the log entries.
|
179
|
+
# @param level [String, Symbol, Integer, nil] The log level to match against the log entries.
|
180
|
+
# @param tags [Hash, nil] A hash of tag names to values to match against the log entries.
|
181
|
+
# @param progname [String, nil] The program name to match against the log entries.
|
182
|
+
# @return [Lumberjack::LogEntry, nil] The log entry that most closely matches the filters, or nil if no entry meets minimum criteria.
|
183
|
+
def match(message: nil, level: nil, tags: nil, progname: nil)
|
184
|
+
extract(message: message, level: level, tags: tags, progname: progname, limit: 1).first
|
185
|
+
end
|
186
|
+
|
142
187
|
# Return the log entry that most closely matches the specified filters. This method
|
143
188
|
# uses fuzzy matching logic to find the best match when no exact match exists.
|
144
189
|
# The matching score is calculated based on how many criteria are met and how closely
|
@@ -148,10 +193,13 @@ module Lumberjack
|
|
148
193
|
# @param level [String, Symbol, Integer, nil] The log level to match against the log entries.
|
149
194
|
# @param tags [Hash, nil] A hash of tag names to values to match against the log entries.
|
150
195
|
# @param progname [String, nil] The program name to match against the log entries.
|
151
|
-
# @return [Lumberjack::
|
196
|
+
# @return [Lumberjack::LogEntry, nil] The log entry that most closely matches the filters, or nil if no entry meets minimum criteria.
|
152
197
|
def closest_match(message: nil, level: nil, tags: nil, progname: nil)
|
153
198
|
return nil if @buffer.empty?
|
154
199
|
|
200
|
+
exact_match = match(message: message, level: level, tags: tags, progname: progname)
|
201
|
+
return exact_match if exact_match
|
202
|
+
|
155
203
|
# Normalize level filter
|
156
204
|
if level
|
157
205
|
level = (level.is_a?(Integer) ? level : Lumberjack::Severity.label_to_level(level))
|
@@ -174,7 +222,7 @@ module Lumberjack
|
|
174
222
|
def inspect
|
175
223
|
message = +"<##{self.class.name} #{@buffer.size} #{(@buffer.size == 1) ? "entry" : "entries"} captured:"
|
176
224
|
@buffer.each do |entry|
|
177
|
-
message << "\n #{formatted_entry(entry)}"
|
225
|
+
message << "\n #{Lumberjack::CaptureDevice.formatted_entry(entry)}"
|
178
226
|
end
|
179
227
|
message << "\n>"
|
180
228
|
message
|
@@ -184,6 +232,16 @@ module Lumberjack
|
|
184
232
|
"<##{self.class.name} #{@buffer.size} #{(@buffer.size == 1) ? "entry" : "entries"} captured>"
|
185
233
|
end
|
186
234
|
|
235
|
+
def length
|
236
|
+
@buffer.length
|
237
|
+
end
|
238
|
+
|
239
|
+
alias_method :size, :length
|
240
|
+
|
241
|
+
def each(&block)
|
242
|
+
@buffer.each(&block)
|
243
|
+
end
|
244
|
+
|
187
245
|
private
|
188
246
|
|
189
247
|
def matched?(entry, message_filter, level_filter, tags_filter, progname_filter)
|
@@ -243,18 +301,6 @@ module Lumberjack
|
|
243
301
|
hash
|
244
302
|
end
|
245
303
|
end
|
246
|
-
|
247
|
-
def formatted_entry(entry)
|
248
|
-
timestamp = entry.time.strftime("%Y-%m-%d %H:%M:%S")
|
249
|
-
formatted = +"#{timestamp} #{entry.severity_label}: #{entry.message}"
|
250
|
-
formatted << "\n progname: #{entry.progname}" if entry.progname.to_s != ""
|
251
|
-
if entry.tags && !entry.tags.empty?
|
252
|
-
Lumberjack::Utils.flatten_tags(entry.tags).to_a.sort_by(&:first).each do |name, value|
|
253
|
-
formatted << "\n #{name}: #{value}"
|
254
|
-
end
|
255
|
-
end
|
256
|
-
formatted
|
257
|
-
end
|
258
304
|
end
|
259
305
|
end
|
260
306
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lumberjack_capture_device
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Durand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lumberjack
|