berkeley_library-logging 0.2.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 +7 -0
- data/.gitignore +388 -0
- data/.idea/inspectionProfiles/Project_Default.xml +17 -0
- data/.idea/logging.iml +139 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/.rubocop.yml +271 -0
- data/.ruby-version +1 -0
- data/.simplecov +4 -0
- data/.travis.yml +9 -0
- data/CHANGES.md +12 -0
- data/Dockerfile +57 -0
- data/Gemfile +3 -0
- data/Jenkinsfile +21 -0
- data/LICENSE.md +21 -0
- data/README.md +47 -0
- data/Rakefile +31 -0
- data/berkeley_library-logging.gemspec +47 -0
- data/docker-compose.yml +15 -0
- data/lib/berkeley_library/logging.rb +38 -0
- data/lib/berkeley_library/logging/configurator.rb +41 -0
- data/lib/berkeley_library/logging/env.rb +38 -0
- data/lib/berkeley_library/logging/events.rb +39 -0
- data/lib/berkeley_library/logging/formatters.rb +54 -0
- data/lib/berkeley_library/logging/logger.rb +12 -0
- data/lib/berkeley_library/logging/loggers.rb +79 -0
- data/lib/berkeley_library/logging/module_info.rb +16 -0
- data/lib/berkeley_library/logging/railtie.rb +15 -0
- data/lib/berkeley_library/logging/tagged_logging_extensions.rb +21 -0
- data/rakelib/.rubocop.yml +4 -0
- data/rakelib/bundle.rake +8 -0
- data/rakelib/coverage.rake +36 -0
- data/rakelib/gem.rake +56 -0
- data/rakelib/rubocop.rake +14 -0
- data/rakelib/spec.rake +31 -0
- data/spec/.rubocop.yml +27 -0
- data/spec/rails/ucblit/logging/configurator_spec.rb +101 -0
- data/spec/rails/ucblit/logging/env_spec.rb +25 -0
- data/spec/rails/ucblit/logging/formatters_spec.rb +44 -0
- data/spec/rails/ucblit/logging/loggers_spec.rb +117 -0
- data/spec/rails/ucblit/logging/railtie_spec.rb +46 -0
- data/spec/rails/ucblit/logging_spec.rb +132 -0
- data/spec/rails_helper.rb +15 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/standalone/ucblit/logging/configurator_spec.rb +103 -0
- data/spec/standalone/ucblit/logging/formatters_spec.rb +44 -0
- data/spec/standalone/ucblit/logging/loggers_spec.rb +278 -0
- data/spec/standalone/ucblit/logging_spec.rb +133 -0
- data/spec/standalone_helper.rb +25 -0
- metadata +363 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
module BerkeleyLibrary
|
4
|
+
module Logging
|
5
|
+
describe Railtie do
|
6
|
+
attr_reader :app
|
7
|
+
attr_reader :config
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
@app = Class.new(Rails::Application).new
|
11
|
+
allow(Rails).to receive(:application).and_return(app)
|
12
|
+
@config = app.config
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'initializer' do
|
16
|
+
attr_reader :logging_initializer
|
17
|
+
attr_reader :bootstrap_logger_initializer
|
18
|
+
|
19
|
+
before(:each) do
|
20
|
+
expected_file, _line = Module.const_source_location(BerkeleyLibrary::Logging::Railtie.name)
|
21
|
+
@logging_initializer = app.initializers.find do |init|
|
22
|
+
block = init.block
|
23
|
+
file, _line = block.source_location
|
24
|
+
file == expected_file
|
25
|
+
end
|
26
|
+
@bootstrap_logger_initializer = app.initializers.find { |init| init.name == :initialize_logger }
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'is added to the Rails application' do
|
30
|
+
expect(logging_initializer).not_to be_nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'runs before the bootstrap logger initializer' do
|
34
|
+
expect(logging_initializer.before).to eq(bootstrap_logger_initializer.name)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'sets the logger' do
|
38
|
+
logging_initializer.run(app)
|
39
|
+
bootstrap_logger_initializer.run(app)
|
40
|
+
|
41
|
+
expect(Rails.logger).to be_a(BerkeleyLibrary::Logging::Logger)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
module BerkeleyLibrary
|
4
|
+
describe Logging do
|
5
|
+
|
6
|
+
def logger_defined?
|
7
|
+
Logging.instance_variable_defined?(:@logger)
|
8
|
+
end
|
9
|
+
|
10
|
+
def reset_logger!
|
11
|
+
Logging.instance_variable_set(:@logger, @logging_logger_orig)
|
12
|
+
end
|
13
|
+
|
14
|
+
def undefine_logger!
|
15
|
+
Logging.send(:remove_instance_variable, :@logger) if logger_defined?
|
16
|
+
end
|
17
|
+
|
18
|
+
def new_mock_logger
|
19
|
+
mock_logger_class = Class.new do
|
20
|
+
def respond_to?(*args)
|
21
|
+
%i[debug info warn error].include?(args[0].to_sym) || super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
mock_logger_class.new
|
26
|
+
end
|
27
|
+
|
28
|
+
before(:each) do
|
29
|
+
@rails_logger_orig = Rails.logger
|
30
|
+
Rails.logger = new_mock_logger
|
31
|
+
|
32
|
+
if (@logger_was_defined = logger_defined?)
|
33
|
+
@logging_logger_orig = Logging.instance_variable_get(:@logger)
|
34
|
+
undefine_logger!
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
after(:each) do
|
39
|
+
@logger_was_defined ? reset_logger! : undefine_logger!
|
40
|
+
Rails.logger = @rails_logger_orig
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'class methods' do
|
44
|
+
describe :logger do
|
45
|
+
it 'returns the default logger' do
|
46
|
+
logger = Logging::Loggers.default_logger
|
47
|
+
expect(Logging.logger).to be(logger)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns a set logger' do
|
51
|
+
logger = new_mock_logger
|
52
|
+
Logging.logger = logger
|
53
|
+
expect(Logging.logger).to be(logger)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
describe :logger= do
|
59
|
+
it 'rejects a non-logger' do
|
60
|
+
original_logger = Logging.logger
|
61
|
+
expect { Logging.logger = Object.new }.to raise_error(ArgumentError)
|
62
|
+
expect(Logging.logger).to be(original_logger)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'can be reset to default with nil' do
|
66
|
+
default_logger = Logging::Loggers.default_logger
|
67
|
+
Logging.logger = new_mock_logger
|
68
|
+
Logging.logger = nil
|
69
|
+
expect(Logging.logger).to be(default_logger)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'included' do
|
75
|
+
attr_reader :logificator
|
76
|
+
|
77
|
+
before(:each) do
|
78
|
+
@logificator = Object.new
|
79
|
+
@logificator.singleton_class.include(Logging)
|
80
|
+
end
|
81
|
+
|
82
|
+
describe :logger do
|
83
|
+
it 'returns the default logger' do
|
84
|
+
logger = Logging::Loggers.default_logger
|
85
|
+
expect(logificator.logger).to be(logger)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns a set logger' do
|
89
|
+
logger = new_mock_logger
|
90
|
+
logificator.logger = logger
|
91
|
+
expect(logificator.logger).to be(logger)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'returns a logger set via the class method' do
|
95
|
+
logger = new_mock_logger
|
96
|
+
Logging.logger = logger
|
97
|
+
expect(logificator.logger).to be(logger)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe :logger= do
|
102
|
+
it 'sets the shared logger via the class method' do
|
103
|
+
logger = new_mock_logger
|
104
|
+
logificator.logger = logger
|
105
|
+
expect(Logging.logger).to be(logger)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'sets a shared logger accessible via another including class' do
|
109
|
+
logger = new_mock_logger
|
110
|
+
Object.new.tap do |logificator2|
|
111
|
+
logificator2.singleton_class.send(:include, Logging)
|
112
|
+
logificator2.logger = logger
|
113
|
+
end
|
114
|
+
expect(logificator.logger).to be(logger)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'rejects a non-logger' do
|
118
|
+
original_logger = logificator.logger
|
119
|
+
expect { logificator.logger = Object.new }.to raise_error(ArgumentError)
|
120
|
+
expect(logificator.logger).to be(original_logger)
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'can be reset to default with nil' do
|
124
|
+
default_logger = Logging::Loggers.default_logger
|
125
|
+
logificator.logger = new_mock_logger
|
126
|
+
logificator.logger = nil
|
127
|
+
expect(logificator.logger).to be(default_logger)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# ------------------------------------------------------------
|
2
|
+
# RSpec
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
# ------------------------------------------------------------
|
7
|
+
# Rails
|
8
|
+
|
9
|
+
require 'rails'
|
10
|
+
Rails.env = 'test'
|
11
|
+
|
12
|
+
# ------------------------------------------------------------
|
13
|
+
# Code under test
|
14
|
+
|
15
|
+
require 'berkeley_library/logging'
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# ------------------------------------------------------------
|
2
|
+
# SimpleCov
|
3
|
+
|
4
|
+
if ENV['COVERAGE']
|
5
|
+
require 'simplecov'
|
6
|
+
|
7
|
+
spec_root = File.realpath(__dir__)
|
8
|
+
spec_group_re = %r{(?<=^#{spec_root}/)[^/]+(?=/)}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.before(:each) do |example|
|
12
|
+
abs_path = File.realpath(example.metadata[:absolute_file_path])
|
13
|
+
match_data = spec_group_re.match(abs_path)
|
14
|
+
raise ArgumentError, "Unable to determine group for example at #{abs_path}" unless match_data
|
15
|
+
|
16
|
+
spec_group = match_data[0]
|
17
|
+
SimpleCov.command_name(spec_group)
|
18
|
+
SimpleCov.coverage_dir("artifacts/simplecov/#{spec_group}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# ------------------------------------------------------------
|
24
|
+
# RSpec
|
25
|
+
|
26
|
+
RSpec.configure do |config|
|
27
|
+
config.color = true
|
28
|
+
config.tty = true
|
29
|
+
config.formatter = :documentation
|
30
|
+
config.mock_with :rspec do |mocks|
|
31
|
+
mocks.verify_partial_doubles = true
|
32
|
+
end
|
33
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
34
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'standalone_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'lograge'
|
4
|
+
|
5
|
+
module BerkeleyLibrary
|
6
|
+
module Logging
|
7
|
+
describe Configurator do
|
8
|
+
describe :configure! do
|
9
|
+
attr_reader :config
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
@stdout_orig = $stdout
|
13
|
+
$stdout = StringIO.new
|
14
|
+
|
15
|
+
@config = OpenStruct.new
|
16
|
+
config.lograge = Lograge::OrderedOptions.new
|
17
|
+
end
|
18
|
+
|
19
|
+
after(:each) do
|
20
|
+
$stdout = @stdout_orig
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'sets the logger' do
|
24
|
+
Configurator.configure(config)
|
25
|
+
expect(config.logger).to be_a(Logging::Logger)
|
26
|
+
end
|
27
|
+
|
28
|
+
describe :configure_lograge! do
|
29
|
+
it 'enables Lograge' do
|
30
|
+
Configurator.configure(config)
|
31
|
+
lograge = config.lograge
|
32
|
+
expect(lograge.enabled).to eq(true)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'extracts request info from log events' do
|
36
|
+
Configurator.configure(config)
|
37
|
+
lograge = config.lograge
|
38
|
+
|
39
|
+
request_headers = {
|
40
|
+
'HTTP_REFERER' => 'value from HTTP_REFERER',
|
41
|
+
'action_dispatch.request_id' => 'value from action_dispatch.request_id',
|
42
|
+
'action_dispatch.remote_ip' => 'value from action_dispatch.remote_ip',
|
43
|
+
'REMOTE_ADDR' => 'value from REMOTE_ADDR',
|
44
|
+
'HTTP_X_FORWARDED_FOR' => 'value from HTTP_X_FORWARDED_FOR',
|
45
|
+
'HTTP_FORWARDED' => 'value from HTTP_FORWARDED'
|
46
|
+
}
|
47
|
+
|
48
|
+
expected_header_map = {
|
49
|
+
referer: 'HTTP_REFERER',
|
50
|
+
request_id: 'action_dispatch.request_id',
|
51
|
+
remote_ip: 'action_dispatch.remote_ip',
|
52
|
+
remote_addr: 'REMOTE_ADDR',
|
53
|
+
x_forwarded_for: 'HTTP_X_FORWARDED_FOR',
|
54
|
+
forwarded: 'HTTP_FORWARDED'
|
55
|
+
}
|
56
|
+
|
57
|
+
event = instance_double(ActiveSupport::Notifications::Event)
|
58
|
+
allow(event).to receive(:payload).and_return({ headers: request_headers })
|
59
|
+
|
60
|
+
custom_options = lograge.custom_options
|
61
|
+
data = custom_options.call(event)
|
62
|
+
expect(data).to be_a(Hash)
|
63
|
+
expect(data[:time]).to be_a(Time) # TODO: check for accuracy
|
64
|
+
expected_header_map.each { |xh, rh| expect(data[xh]).to eq(request_headers[rh]) }
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'formats Lograge data as a hash' do
|
68
|
+
Configurator.configure(config)
|
69
|
+
lograge = config.lograge
|
70
|
+
|
71
|
+
formatter = lograge.formatter
|
72
|
+
expect(formatter.call(nil)).to eq({ msg: 'Request', request: {} })
|
73
|
+
expect(formatter.call('elvis')).to eq({ msg: 'Request', request: { msg: 'elvis' } })
|
74
|
+
some_hash = { foo: 'bar' }
|
75
|
+
expect(formatter.call(some_hash)).to eq({ msg: 'Request', request: some_hash })
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'Webpacker' do
|
80
|
+
it 'works if Webpacker is not present' do
|
81
|
+
expect(Object.const_defined?(:Webpacker)).to eq(false) # just to be sure
|
82
|
+
expect { Configurator.configure(config) }.not_to raise_error
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'sets the Webpacker logger if Webpacker is present' do
|
86
|
+
module ::Webpacker
|
87
|
+
module Instance
|
88
|
+
class << self
|
89
|
+
attr_accessor :logger
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
Configurator.configure(config)
|
95
|
+
expect(Webpacker::Instance.logger).to eq(config.logger)
|
96
|
+
ensure
|
97
|
+
Object.send(:remove_const, :Webpacker) if defined?(Webpacker)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'standalone_helper'
|
2
|
+
require 'json'
|
3
|
+
require 'berkeley_library/logging'
|
4
|
+
|
5
|
+
module BerkeleyLibrary
|
6
|
+
module Logging
|
7
|
+
describe Formatters do
|
8
|
+
describe :new_json_formatter do
|
9
|
+
it 'supports tagged logging' do
|
10
|
+
out = StringIO.new
|
11
|
+
logger = Logger.new(out)
|
12
|
+
logger.formatter = Formatters.new_json_formatter
|
13
|
+
|
14
|
+
logger = ActiveSupport::TaggedLogging.new(logger)
|
15
|
+
|
16
|
+
expected_tag = 'hello'
|
17
|
+
expected_msg = 'this is a test'
|
18
|
+
|
19
|
+
logger.tagged(expected_tag) { logger.info(expected_msg) }
|
20
|
+
|
21
|
+
logged_json = JSON.parse(out.string)
|
22
|
+
expect(logged_json['msg']).to eq(expected_msg)
|
23
|
+
expect(logged_json['tags']).to eq([expected_tag])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe :ensure_hash do
|
28
|
+
it 'returns an empty hash for nil' do
|
29
|
+
expect(Formatters.ensure_hash(nil)).to eq({})
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'returns the original hash for a hash' do
|
33
|
+
original_hash = { a: 1, b: 2 }
|
34
|
+
expect(Formatters.ensure_hash(original_hash)).to equal(original_hash)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'wraps anything else in a hash' do
|
38
|
+
message = 'this is a message'
|
39
|
+
expect(Formatters.ensure_hash(message)).to eq({ msg: message })
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
require 'standalone_helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module BerkeleyLibrary
|
5
|
+
module Logging
|
6
|
+
describe Loggers do
|
7
|
+
attr_reader :out
|
8
|
+
|
9
|
+
# rubocop:disable Lint/ConstantDefinitionInBlock
|
10
|
+
before(:each) do
|
11
|
+
@out = StringIO.new
|
12
|
+
class ::TestError < StandardError; end
|
13
|
+
end
|
14
|
+
# rubocop:enable Lint/ConstantDefinitionInBlock
|
15
|
+
|
16
|
+
after(:each) do
|
17
|
+
Object.send(:remove_const, :TestError)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe :new_json_logger do
|
21
|
+
it 'supports tagged logging' do
|
22
|
+
logger = Loggers.new_json_logger(out)
|
23
|
+
logger = ActiveSupport::TaggedLogging.new(logger)
|
24
|
+
|
25
|
+
expected_tag = 'hello'
|
26
|
+
expected_msg = 'this is a test'
|
27
|
+
|
28
|
+
logger.tagged(expected_tag) { logger.info(expected_msg) }
|
29
|
+
|
30
|
+
logged_json = JSON.parse(out.string)
|
31
|
+
expect(logged_json['msg']).to eq(expected_msg)
|
32
|
+
expect(logged_json['tags']).to eq([expected_tag])
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'logs an error as a hash' do
|
36
|
+
msg = 'Help I am trapped in a unit test'
|
37
|
+
|
38
|
+
begin
|
39
|
+
raise TestError, msg
|
40
|
+
rescue TestError => e
|
41
|
+
ex = e
|
42
|
+
Loggers.new_json_logger(out).error(e)
|
43
|
+
end
|
44
|
+
|
45
|
+
logged_json = JSON.parse(out.string)
|
46
|
+
expect(logged_json['msg']).to eq(msg)
|
47
|
+
err_json = logged_json['err']
|
48
|
+
expect(err_json).to be_a(Hash)
|
49
|
+
expect(err_json['name']).to eq(TestError.name)
|
50
|
+
expect(err_json['message']).to eq(msg)
|
51
|
+
|
52
|
+
err_stack = err_json['stack']
|
53
|
+
backtrace = ex.backtrace
|
54
|
+
expect(backtrace).not_to be_nil # just to be sure
|
55
|
+
backtrace.each do |line|
|
56
|
+
expect(err_stack).to include(line)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe :default_logger do
|
62
|
+
it 'returns a readable $stdout logger' do
|
63
|
+
logger = Loggers.default_logger
|
64
|
+
expect(logger).to be_a(Logger)
|
65
|
+
expect(logger.formatter).to be_a(Ougai::Formatters::Readable)
|
66
|
+
|
67
|
+
logdev = logger.instance_variable_get(:@logdev)
|
68
|
+
expect(logdev).to be_a(::Logger::LogDevice)
|
69
|
+
expect(logdev.dev).to eq($stdout)
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'errors' do
|
73
|
+
it 'logs an error alone with cause and backtrace' do
|
74
|
+
msg = 'Help I am trapped in a unit test'
|
75
|
+
|
76
|
+
begin
|
77
|
+
raise TestError, msg
|
78
|
+
rescue TestError => e
|
79
|
+
ex = e
|
80
|
+
Loggers.new_readable_logger(out).error(e)
|
81
|
+
end
|
82
|
+
|
83
|
+
logged_txt = out.string
|
84
|
+
expect(logged_txt).to include(msg)
|
85
|
+
expect(logged_txt).to include(TestError.name)
|
86
|
+
backtrace = ex.backtrace
|
87
|
+
expect(backtrace).not_to be_nil # just to be sure
|
88
|
+
backtrace.each do |line|
|
89
|
+
expect(logged_txt).to include(line)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'messages with text and data' do
|
96
|
+
it 'logs an arbitrary hash in a reasonable way' do
|
97
|
+
out = StringIO.new
|
98
|
+
msg_txt = 'message text'
|
99
|
+
msg_h = {
|
100
|
+
foo: 'Foo',
|
101
|
+
bar: 'Bar',
|
102
|
+
baz: 'Baz'
|
103
|
+
}
|
104
|
+
Loggers.new_readable_logger(out).info(msg_txt, msg_h)
|
105
|
+
|
106
|
+
logged_txt = out.string
|
107
|
+
expect(logged_txt).to include(msg_txt)
|
108
|
+
msg_h.each do |k, v|
|
109
|
+
expect(logged_txt).to include(k.inspect)
|
110
|
+
expect(logged_txt).to include(v.inspect)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'logs something with #to_hash as a hash' do
|
115
|
+
out = StringIO.new
|
116
|
+
msg_txt = 'message text'
|
117
|
+
msg_h = {
|
118
|
+
foo: 'Foo',
|
119
|
+
bar: 'Bar',
|
120
|
+
baz: 'Baz'
|
121
|
+
}
|
122
|
+
msg_obj = Object.new
|
123
|
+
msg_obj.singleton_class.define_method(:to_hash) { msg_h }
|
124
|
+
|
125
|
+
Loggers.new_readable_logger(out).info(msg_txt, msg_obj)
|
126
|
+
|
127
|
+
logged_txt = out.string
|
128
|
+
expect(logged_txt).to include(msg_txt)
|
129
|
+
msg_h.each do |k, v|
|
130
|
+
expect(logged_txt).to include(k.inspect)
|
131
|
+
expect(logged_txt).to include(v.inspect)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'logs an error with cause and backtrace' do
|
136
|
+
msg_txt = 'message text'
|
137
|
+
ex_msg = 'Help I am trapped in a unit test'
|
138
|
+
|
139
|
+
begin
|
140
|
+
raise TestError, ex_msg
|
141
|
+
rescue TestError => e
|
142
|
+
ex = e
|
143
|
+
Loggers.new_readable_logger(out).error(msg_txt, e)
|
144
|
+
end
|
145
|
+
|
146
|
+
logged_txt = out.string
|
147
|
+
expect(logged_txt).to include(msg_txt)
|
148
|
+
expect(logged_txt).to include(ex_msg)
|
149
|
+
expect(logged_txt).to include(TestError.name)
|
150
|
+
backtrace = ex.backtrace
|
151
|
+
expect(backtrace).not_to be_nil # just to be sure
|
152
|
+
backtrace.each do |line|
|
153
|
+
expect(logged_txt).to include(line)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
describe 'messages with data and no text' do
|
160
|
+
it 'logs an arbitrary hash in a reasonable way' do
|
161
|
+
out = StringIO.new
|
162
|
+
msg_h = {
|
163
|
+
foo: 'Foo',
|
164
|
+
bar: 'Bar',
|
165
|
+
baz: 'Baz'
|
166
|
+
}
|
167
|
+
Loggers.new_readable_logger(out).info(msg_h)
|
168
|
+
logged_txt = out.string
|
169
|
+
msg_h.each do |k, v|
|
170
|
+
expect(logged_txt).to include(k.inspect)
|
171
|
+
expect(logged_txt).to include(v.inspect)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'logs something with #to_hash as a hash' do
|
176
|
+
out = StringIO.new
|
177
|
+
msg_h = {
|
178
|
+
foo: 'Foo',
|
179
|
+
bar: 'Bar',
|
180
|
+
baz: 'Baz'
|
181
|
+
}
|
182
|
+
msg_obj = Object.new
|
183
|
+
msg_obj.singleton_class.define_method(:to_hash) { msg_h }
|
184
|
+
|
185
|
+
Loggers.new_readable_logger(out).info(msg_obj)
|
186
|
+
|
187
|
+
logged_txt = out.string
|
188
|
+
msg_h.each do |k, v|
|
189
|
+
expect(logged_txt).to include(k.inspect)
|
190
|
+
expect(logged_txt).to include(v.inspect)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'logs an error with cause and backtrace' do
|
195
|
+
ex_msg = 'Help I am trapped in a unit test'
|
196
|
+
|
197
|
+
begin
|
198
|
+
raise TestError, ex_msg
|
199
|
+
rescue TestError => e
|
200
|
+
ex = e
|
201
|
+
Loggers.new_readable_logger(out).error(e)
|
202
|
+
end
|
203
|
+
|
204
|
+
logged_txt = out.string
|
205
|
+
expect(logged_txt).to include(ex_msg)
|
206
|
+
expect(logged_txt).to include(TestError.name)
|
207
|
+
backtrace = ex.backtrace
|
208
|
+
expect(backtrace).not_to be_nil # just to be sure
|
209
|
+
backtrace.each do |line|
|
210
|
+
expect(logged_txt).to include(line)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
describe :new_default_logger do
|
219
|
+
attr_reader :config
|
220
|
+
|
221
|
+
before(:each) do
|
222
|
+
@config = OpenStruct.new
|
223
|
+
end
|
224
|
+
|
225
|
+
after(:each) do
|
226
|
+
BerkeleyLibrary::Logging.instance_variable_set(:@env, nil)
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'returns a readable $stdout logger if given no config' do
|
230
|
+
logger = Loggers.new_default_logger
|
231
|
+
expect(logger).not_to be_nil
|
232
|
+
expect(logger).to be_a(Logger)
|
233
|
+
expect(logger.formatter).to be_a(Ougai::Formatters::Readable)
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'returns a file logger in test' do
|
237
|
+
BerkeleyLibrary::Logging.env = 'test'
|
238
|
+
logger = Loggers.new_default_logger(config)
|
239
|
+
expect(logger).not_to be_nil
|
240
|
+
logdev = logger.instance_variable_get(:@logdev)
|
241
|
+
expect(logdev.filename).to end_with('log/test.log')
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'returns a stdout logger in production' do
|
245
|
+
BerkeleyLibrary::Logging.env = 'production'
|
246
|
+
stdout_orig = $stdout
|
247
|
+
stdout_tmp = StringIO.new
|
248
|
+
begin
|
249
|
+
$stdout = stdout_tmp
|
250
|
+
logger = Loggers.new_default_logger(config)
|
251
|
+
ensure
|
252
|
+
$stdout = stdout_orig
|
253
|
+
end
|
254
|
+
expect(logger).not_to be_nil
|
255
|
+
logdev = logger.instance_variable_get(:@logdev)
|
256
|
+
expect(logdev.filename).to be_nil
|
257
|
+
expect(logdev.dev).to eq(stdout_tmp)
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'returns a stdout logger in development' do
|
261
|
+
BerkeleyLibrary::Logging.env = 'development'
|
262
|
+
logger = Loggers.new_default_logger(config)
|
263
|
+
expect(logger).not_to be_nil
|
264
|
+
logdev = logger.instance_variable_get(:@logdev)
|
265
|
+
expect(logdev.filename).to be_nil
|
266
|
+
expect(logdev.dev).to eq($stdout)
|
267
|
+
|
268
|
+
# TODO: come up with a succinct way to test broadcast to file
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'fails on an unsupported environment' do
|
272
|
+
BerkeleyLibrary::Logging.env = 'some-unsupported-environment'
|
273
|
+
expect { Loggers.new_default_logger(config) }.to raise_error(ArgumentError)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|