berkeley_library-logging 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|