lumberjack_capture_device 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a0dc972c9f7b08468a2c96f2535637fa81bb1ef826123c9f6c582f81fee3b0cd
4
+ data.tar.gz: 8548fda4d9fcecd7791b948e8922b9394abe0e4fbadd0668a1cb8d15053941e9
5
+ SHA512:
6
+ metadata.gz: c9d4da5e4da9081d9cd900467b1baa96b7316726fe28c080c1efeb06eaa64f96bc5797fe0fe0a4595c96ddc66105cfe63d30384546718ae690dc3166cff6a871
7
+ data.tar.gz: d50a5ad769cabe38705f3a9c169e6f7203be84130d2dc008109ca06b704afc176731b46c0d709a2c3085550bf07d1d4763a5012dd214bbfb274c7db3d7a0c311
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## 1.0.0
2
+
3
+ * Initial release.
data/MIT_LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2021 Brian Durand
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,55 @@
1
+ [![Continuous Integration](https://github.com/bdurand/lumberjack_capture_device/actions/workflows/continuous_integration.yml/badge.svg)](https://github.com/bdurand/lumberjack_capture_device/actions/workflows/continuous_integration.yml)
2
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
3
+
4
+ # Lumberjack Capture Device
5
+
6
+ This is a plugin device for the [lumberjack gem](https://github.com/bdurand/lumberjack) that enables capturing log messages in a test suite so that assertions can be made against them. It provides and easy and stable method of testing that specific log messages are being sent to a logger.
7
+
8
+ Using mocks and stubs on a logger to test that it receives messages can make for a brittle test suite since there can a wide variety of code writing messages to logs and your test suite may have a higher log level turned on causing it skip messages at a lower level.
9
+
10
+ For instance, this rspec code can break if any of the code called by the `do_something` writes a different info log message:
11
+
12
+ ```ruby
13
+ do_something
14
+ expect(Rail.logger).to receive(:info).with("Something happened")
15
+ ```
16
+
17
+ It will also break if the test suite logger has the log level set to `warn` or higher since it will then skip all info and debug messages.
18
+
19
+ ## Usage
20
+
21
+ You can call the `Lumberjack::CaptureDevice.capture` method to override a logger so that it will capture log entries within a block to an in memory buffer. This method will yield the capturing log device as well as return it as the result of the method. The log level will also be temporarily set to debug within the block, so you can capture all log messages without having to change the log level for the entire test suite.
22
+
23
+ You can use the `include?` method on the log device to determine if specific log entries were made. This would be the equivalent code to the above rspec test, but without the brittleness of mocking method calls:
24
+
25
+ ```ruby
26
+ Lumberjack::CaptureDevice.capture(Rails.logger) do |logs|
27
+ do_something
28
+ expect(logs).to include(level: :info, message: "Something happened")
29
+ end
30
+ ```
31
+
32
+ You can also write that same test as:
33
+
34
+ ```ruby
35
+ logs = Lumberjack::CaptureDevice.capture(Rails.logger) { do_something }
36
+ expect(logs).to include(level: :info, message: "Something happened")
37
+ ```
38
+
39
+ For MiniTest, you could assert:
40
+
41
+ ```ruby
42
+ logs = Lumberjack::CaptureDevice.capture(Rails.logger) { do_something }
43
+ assert(logs.include?(level: :info, message: "Something happened"))
44
+ ```
45
+
46
+
47
+ You can filter the logs on level, message, and tags. The level option can take either a label (i.e. `:warn`) or a constant (i.e. `Logger::WARN`). The message filter can be either an exact string, or a regular expression or any matcher supported by your test library. The tags argument can match tags with a Hash mapping tag names to the matcher.
48
+
49
+ ```ruby
50
+ expect(logs).to include(level: :info, message: /something/i)
51
+ expect(logs).to include(level: Logger::INFO, tags: {foo: "bar"})
52
+ expect(logs).to include(tags: {foo: anything, count: {one: 1}})
53
+ ```
54
+
55
+ You can also use the `Lumberjack::CaptureDevice#extract` method with the same arguments as used by `include?` to grab all lines that match the filters. And finally, you can access all the log entries with `Lumberjack::CaptureDevice#buffer`.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lumberjack"
4
+
5
+ module Lumberjack
6
+ # Lumberjack device for capturing log entries into memory to allow them to be inspected
7
+ # for testing purposes.
8
+ class CaptureDevice < Lumberjack::Device
9
+ attr_reader :buffer
10
+
11
+ class << self
12
+ # Capture the entries written by the logger within a block. Within the block all log
13
+ # entries will be written to a CaptureDevice rather than to the normal output for
14
+ # the logger. In addition, all formatters will be removed and the log level will be set
15
+ # to debug. The device being written to be both yielded to the block as well as returned
16
+ # by the method call.
17
+ def capture(logger)
18
+ device = new
19
+ save_device = logger.device
20
+ save_level = logger.level
21
+ save_formatter = logger.formatter
22
+ begin
23
+ logger.device = device
24
+ logger.level = :debug
25
+ logger.formatter = Lumberjack::Formatter.empty
26
+ yield device
27
+ ensure
28
+ logger.device = save_device
29
+ logger.level = save_level
30
+ logger.formatter = save_formatter
31
+ end
32
+ device
33
+ end
34
+ end
35
+
36
+ def initialize
37
+ @buffer = []
38
+ end
39
+
40
+ def write(entry)
41
+ @buffer << entry
42
+ end
43
+
44
+ # Clear all entries that have been written to the buffer.
45
+ def clear
46
+ @buffer.clear
47
+ end
48
+
49
+ # Return true if the captured log entries match the specified level, message, and tags.
50
+ #
51
+ # For level, you can specified either a numeric constant (i.e. `Logger::WARN`) or a symbol
52
+ # (i.e. `:warn`).
53
+ #
54
+ # For message you can specify a string to perform an exact match or a regular expression
55
+ # to perform a partial or pattern match. You can also supply any matcher value available
56
+ # in your test library (i.e. in rspec you could use `anything` or `instance_of(Error)`, etc.).
57
+ #
58
+ # For tags, you can specify a hash of tag names to values to match. You can use
59
+ # regular expression or matchers as the values here as well. Tags can also be nested to match
60
+ # nested tags.
61
+ #
62
+ # Example:
63
+ #
64
+ # ```
65
+ # logs.include(level: :warn, message: /something happened/, tags: {duration: instance_of(Float)})
66
+ # ```
67
+ def include?(message: nil, level: nil, tags: nil)
68
+ !extract(message: message, level: level, tags: tags, limit: 1).empty?
69
+ end
70
+
71
+ # Return all the captured entries that match the specified filters. These filters are
72
+ # the same as described in the `include?` method.
73
+ def extract(message: nil, level: nil, tags: nil, limit: nil)
74
+ matches = []
75
+ if level
76
+ # Normalize the level filter to numeric values.
77
+ level = (level.is_a?(Integer) ? level : Lumberjack::Severity.label_to_level(level))
78
+ end
79
+ @buffer.each do |entry|
80
+ if matched?(entry, message, level, tags)
81
+ matches << entry
82
+ break if limit && matches.size >= limit
83
+ end
84
+ end
85
+ matches
86
+ end
87
+
88
+ private
89
+
90
+ def matched?(entry, message_filter, level_filter, tags_filter)
91
+ match?(entry.message, message_filter) && match?(entry.severity, level_filter) && match_tags?(entry.tags, tags_filter)
92
+ end
93
+
94
+ def match?(value, filter)
95
+ return true unless filter
96
+ filter === value
97
+ end
98
+
99
+ def match_tags?(tags, filter)
100
+ return true unless filter
101
+ return false unless tags
102
+ filter.all? do |name, value_filter|
103
+ name = name.to_s
104
+ tag_values = tags[name]
105
+ if tag_values.is_a?(Hash)
106
+ if value_filter.is_a?(Hash)
107
+ match_tags?(Lumberjack::Tags.stringify_keys(tag_values), value_filter)
108
+ else
109
+ false
110
+ end
111
+ elsif tag_values || tags.include?(name)
112
+ match?(tag_values, value_filter)
113
+ else
114
+ false
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,32 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "lumberjack_capture_device"
3
+ spec.version = File.read(File.join(__dir__, "VERSION")).strip
4
+ spec.authors = ["Brian Durand"]
5
+ spec.email = ["bbdurand@gmail.com"]
6
+
7
+ spec.summary = "Testing device for the lumberjack gem that can be used for asserting messages have been logged in a test suite."
8
+ spec.homepage = "https://github.com/bdurand/lumberjack_capture_device"
9
+ spec.license = "MIT"
10
+
11
+ # Specify which files should be added to the gem when it is released.
12
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
13
+ ignore_files = %w[
14
+ .
15
+ Appraisals
16
+ Gemfile
17
+ Gemfile.lock
18
+ Rakefile
19
+ gemfiles/
20
+ spec/
21
+ ]
22
+ spec.files = Dir.chdir(__dir__) do
23
+ `git ls-files -z`.split("\x0").reject { |f| ignore_files.any? { |path| f.start_with?(path) } }
24
+ end
25
+
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.required_ruby_version = ">= 2.4.0"
29
+
30
+ spec.add_dependency "lumberjack", ">=1.1.0"
31
+ spec.add_development_dependency "bundler"
32
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lumberjack_capture_device
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Brian Durand
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-02-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lumberjack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description:
42
+ email:
43
+ - bbdurand@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - CHANGELOG.md
49
+ - MIT_LICENSE.txt
50
+ - README.md
51
+ - VERSION
52
+ - lib/lumberjack_capture_device.rb
53
+ - lumberjack_capture_device.gemspec
54
+ homepage: https://github.com/bdurand/lumberjack_capture_device
55
+ licenses:
56
+ - MIT
57
+ metadata: {}
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 2.4.0
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubygems_version: 3.0.3
74
+ signing_key:
75
+ specification_version: 4
76
+ summary: Testing device for the lumberjack gem that can be used for asserting messages
77
+ have been logged in a test suite.
78
+ test_files: []