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
data/rakelib/bundle.rake
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'colorize'
|
2
|
+
|
3
|
+
namespace :simplecov do
|
4
|
+
task :check_coverage do
|
5
|
+
ENV['COVERAGE'] ||= 'true'
|
6
|
+
Rake::Task['spec'].invoke
|
7
|
+
rescue SystemExit
|
8
|
+
puts 'Code coverage analysis aborted, probably due to a previous test failure'.colorize(:red)
|
9
|
+
raise
|
10
|
+
end
|
11
|
+
|
12
|
+
task :report do
|
13
|
+
require 'simplecov'
|
14
|
+
require 'simplecov-rcov'
|
15
|
+
require 'simplecov-console'
|
16
|
+
|
17
|
+
result_sets = Dir.glob('artifacts/simplecov/**/.resultset.json')
|
18
|
+
SimpleCov.collate(result_sets) do
|
19
|
+
minimum_coverage 100
|
20
|
+
coverage_dir 'artifacts'
|
21
|
+
|
22
|
+
if ENV['GENERATE_REPORTS']
|
23
|
+
formatters = [
|
24
|
+
SimpleCov::Formatter::Console,
|
25
|
+
SimpleCov::Formatter::RcovFormatter
|
26
|
+
]
|
27
|
+
formatter SimpleCov::Formatter::MultiFormatter.new(formatters)
|
28
|
+
else
|
29
|
+
formatter SimpleCov::Formatter::Console
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'Run all specs in spec directory, with coverage'
|
36
|
+
task coverage: %w[simplecov:check_coverage simplecov:report]
|
data/rakelib/gem.rake
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rubygems/gem_runner'
|
2
|
+
require 'berkeley_library/logging/module_info'
|
3
|
+
|
4
|
+
module BerkeleyLibrary
|
5
|
+
module Logging
|
6
|
+
class << self
|
7
|
+
def project_root
|
8
|
+
@project_root ||= File.expand_path('..', __dir__)
|
9
|
+
end
|
10
|
+
|
11
|
+
def artifacts_dir
|
12
|
+
return project_root unless ENV['CI']
|
13
|
+
|
14
|
+
@artifacts_dir ||= File.join(project_root, 'artifacts')
|
15
|
+
end
|
16
|
+
|
17
|
+
def gemspec_file
|
18
|
+
@gemspec_file ||= begin
|
19
|
+
gemspec_files = Dir.glob(File.expand_path('*.gemspec', project_root))
|
20
|
+
raise ArgumentError, "Too many .gemspecs: #{gemspec_files.join(', ')}" if gemspec_files.size > 1
|
21
|
+
raise ArgumentError, 'No .gemspec file found' if gemspec_files.empty?
|
22
|
+
|
23
|
+
gemspec_files[0]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def gemspec_basename
|
28
|
+
File.basename(gemspec_file)
|
29
|
+
end
|
30
|
+
|
31
|
+
def output_file
|
32
|
+
@output_file ||= begin
|
33
|
+
gem_name = File.basename(gemspec_file, '.*')
|
34
|
+
version = BerkeleyLibrary::Logging::ModuleInfo::VERSION
|
35
|
+
basename = "#{gem_name}-#{version}.gem"
|
36
|
+
File.join(artifacts_dir, basename)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def output_file_relative
|
41
|
+
return File.basename(output_file) unless ENV['CI']
|
42
|
+
|
43
|
+
@output_file_relative ||= begin
|
44
|
+
artifacts_dir_relative = File.basename(artifacts_dir)
|
45
|
+
File.join(artifacts_dir_relative, File.basename(output_file))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Build #{BerkeleyLibrary::Logging.gemspec_basename} as #{BerkeleyLibrary::Logging.output_file_relative}"
|
53
|
+
task :gem do
|
54
|
+
args = ['build', BerkeleyLibrary::Logging.gemspec_file, "--output=#{BerkeleyLibrary::Logging.output_file}"]
|
55
|
+
Gem::GemRunner.new.run(args)
|
56
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubocop'
|
2
|
+
require 'rubocop/rake_task'
|
3
|
+
|
4
|
+
desc 'Run RuboCop'
|
5
|
+
RuboCop::RakeTask.new(:rubocop) do |cop|
|
6
|
+
next unless ENV['GENERATE_REPORTS']
|
7
|
+
|
8
|
+
output = ENV['RUBOCOP_OUTPUT'] || 'artifacts/rubocop/index.html'
|
9
|
+
puts "Writing RuboCop inspection report to #{output}"
|
10
|
+
|
11
|
+
cop.verbose = false
|
12
|
+
cop.formatters = ['html']
|
13
|
+
cop.options = ['--out', output]
|
14
|
+
end
|
data/rakelib/spec.rake
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
|
3
|
+
namespace :spec do
|
4
|
+
task :prepare do
|
5
|
+
if ENV['GENERATE_REPORTS']
|
6
|
+
ENV['CI_REPORTS'] = 'artifacts/rspec'
|
7
|
+
|
8
|
+
require 'ci/reporter/rake/rspec'
|
9
|
+
Rake::Task['ci:setup:rspec'].invoke
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
test_groups = %i[standalone rails].tap do |groups|
|
14
|
+
groups.each do |group|
|
15
|
+
desc "Run specs in spec/#{group} directory"
|
16
|
+
RSpec::Core::RakeTask.new(group) do |task|
|
17
|
+
task.rspec_opts = %w[--color --format documentation --order default]
|
18
|
+
task.pattern = "spec/#{group}/**/*_spec.rb"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
multitask all: test_groups
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Run all specs in spec directory'
|
26
|
+
task spec: ['spec:prepare'] do
|
27
|
+
Rake::Task['spec:all'].invoke
|
28
|
+
ensure
|
29
|
+
reports_dir = ENV['CI_REPORTS']
|
30
|
+
puts "JUnit-format XML test report written to #{reports_dir}" if reports_dir
|
31
|
+
end
|
data/spec/.rubocop.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
inherit_from: ../.rubocop.yml
|
2
|
+
|
3
|
+
Style/ClassAndModuleChildren:
|
4
|
+
Enabled: false
|
5
|
+
|
6
|
+
Layout/LineLength:
|
7
|
+
Enabled: false
|
8
|
+
|
9
|
+
Metrics/BlockLength:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
Metrics/ClassLength:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Metrics/ModuleLength:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Metrics/MethodLength:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
############################################################
|
22
|
+
# Added in Rubocop 0.89
|
23
|
+
|
24
|
+
# Sometimes we're testing the operator
|
25
|
+
Lint/BinaryOperatorWithIdenticalOperands:
|
26
|
+
Enabled: false
|
27
|
+
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
require 'rails'
|
3
|
+
require 'lograge'
|
4
|
+
require 'berkeley_library/logging'
|
5
|
+
|
6
|
+
module BerkeleyLibrary
|
7
|
+
module Logging
|
8
|
+
describe Configurator do
|
9
|
+
describe :configure! do
|
10
|
+
|
11
|
+
attr_reader :config
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
app = Class.new(Rails::Application).new
|
15
|
+
allow(Rails).to receive(:application).and_return(app)
|
16
|
+
@config = app.config
|
17
|
+
|
18
|
+
config.lograge = Lograge::OrderedOptions.new
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'sets the logger' do
|
22
|
+
Configurator.configure(config)
|
23
|
+
expect(config.logger).to be_a(Logging::Logger)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe :configure_lograge! do
|
27
|
+
it 'enables Lograge' do
|
28
|
+
Configurator.configure(config)
|
29
|
+
lograge = config.lograge
|
30
|
+
expect(lograge.enabled).to eq(true)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'extracts request info from log events' do
|
34
|
+
Configurator.configure(config)
|
35
|
+
lograge = config.lograge
|
36
|
+
|
37
|
+
request_headers = {
|
38
|
+
'HTTP_REFERER' => 'value from HTTP_REFERER',
|
39
|
+
'action_dispatch.request_id' => 'value from action_dispatch.request_id',
|
40
|
+
'action_dispatch.remote_ip' => 'value from action_dispatch.remote_ip',
|
41
|
+
'REMOTE_ADDR' => 'value from REMOTE_ADDR',
|
42
|
+
'HTTP_X_FORWARDED_FOR' => 'value from HTTP_X_FORWARDED_FOR',
|
43
|
+
'HTTP_FORWARDED' => 'value from HTTP_FORWARDED'
|
44
|
+
}
|
45
|
+
|
46
|
+
expected_header_map = {
|
47
|
+
referer: 'HTTP_REFERER',
|
48
|
+
request_id: 'action_dispatch.request_id',
|
49
|
+
remote_ip: 'action_dispatch.remote_ip',
|
50
|
+
remote_addr: 'REMOTE_ADDR',
|
51
|
+
x_forwarded_for: 'HTTP_X_FORWARDED_FOR',
|
52
|
+
forwarded: 'HTTP_FORWARDED'
|
53
|
+
}
|
54
|
+
|
55
|
+
event = instance_double(ActiveSupport::Notifications::Event)
|
56
|
+
allow(event).to receive(:payload).and_return({ headers: request_headers })
|
57
|
+
|
58
|
+
custom_options = lograge.custom_options
|
59
|
+
data = custom_options.call(event)
|
60
|
+
expect(data).to be_a(Hash)
|
61
|
+
expect(data[:time]).to be_a(Time) # TODO: check for accuracy
|
62
|
+
expected_header_map.each { |xh, rh| expect(data[xh]).to eq(request_headers[rh]) }
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'formats Lograge data as a hash' do
|
66
|
+
Configurator.configure(config)
|
67
|
+
lograge = config.lograge
|
68
|
+
|
69
|
+
formatter = lograge.formatter
|
70
|
+
expect(formatter.call(nil)).to eq({ msg: 'Request', request: {} })
|
71
|
+
expect(formatter.call('elvis')).to eq({ msg: 'Request', request: { msg: 'elvis' } })
|
72
|
+
some_hash = { foo: 'bar' }
|
73
|
+
expect(formatter.call(some_hash)).to eq({ msg: 'Request', request: some_hash })
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'Webpacker' do
|
78
|
+
it 'works if Webpacker is not present' do
|
79
|
+
expect(Object.const_defined?(:Webpacker)).to eq(false) # just to be sure
|
80
|
+
expect { Configurator.configure(config) }.not_to raise_error
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'sets the Webpacker logger if Webpacker is present' do
|
84
|
+
module ::Webpacker
|
85
|
+
module Instance
|
86
|
+
class << self
|
87
|
+
attr_accessor :logger
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
Configurator.configure(config)
|
93
|
+
expect(Webpacker::Instance.logger).to eq(config.logger)
|
94
|
+
ensure
|
95
|
+
Object.send(:remove_const, :Webpacker) if defined?(Webpacker)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
module BerkeleyLibrary
|
4
|
+
describe Logging do
|
5
|
+
|
6
|
+
attr_reader :orig_rails_env
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@orig_rails_env = Rails.env
|
10
|
+
end
|
11
|
+
|
12
|
+
after(:each) do
|
13
|
+
Rails.env = orig_rails_env
|
14
|
+
end
|
15
|
+
|
16
|
+
describe :env= do
|
17
|
+
it 'sets Rails.env' do
|
18
|
+
expect(defined?(Rails)).to be_truthy # just to be sure
|
19
|
+
Logging.env = 'elvis'
|
20
|
+
expect(Rails.env).to eq('elvis')
|
21
|
+
expect(Rails.env.elvis?).to eq(true)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rails_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,117 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
module BerkeleyLibrary
|
5
|
+
module Logging
|
6
|
+
describe Loggers do
|
7
|
+
attr_reader :orig_rails_env
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
@orig_rails_env = Rails.env
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:each) do
|
14
|
+
Rails.env = orig_rails_env
|
15
|
+
end
|
16
|
+
|
17
|
+
describe :new_json_logger do
|
18
|
+
it 'supports tagged logging' do
|
19
|
+
out = StringIO.new
|
20
|
+
logger = Loggers.new_json_logger(out)
|
21
|
+
logger = ActiveSupport::TaggedLogging.new(logger)
|
22
|
+
|
23
|
+
expected_tag = 'hello'
|
24
|
+
expected_msg = 'this is a test'
|
25
|
+
|
26
|
+
logger.tagged(expected_tag) { logger.info(expected_msg) }
|
27
|
+
|
28
|
+
logged_json = JSON.parse(out.string)
|
29
|
+
expect(logged_json['msg']).to eq(expected_msg)
|
30
|
+
expect(logged_json['tags']).to eq([expected_tag])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe :default_logger do
|
35
|
+
before(:each) { @rails_logger = Rails.logger }
|
36
|
+
after(:each) { Rails.logger = @rails_logger }
|
37
|
+
|
38
|
+
it 'returns the Rails logger' do
|
39
|
+
expected_logger = double(::Logger)
|
40
|
+
Rails.logger = expected_logger
|
41
|
+
|
42
|
+
expect(Loggers.default_logger).to be(expected_logger)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns a readable $stdout logger if Rails logger is nil' do
|
46
|
+
Rails.logger = nil
|
47
|
+
|
48
|
+
actual_logger = Loggers.default_logger
|
49
|
+
expect(actual_logger).to be_a(Logger)
|
50
|
+
expect(actual_logger.formatter).to be_a(Ougai::Formatters::Readable)
|
51
|
+
|
52
|
+
logdev = actual_logger.instance_variable_get(:@logdev)
|
53
|
+
expect(logdev).to be_a(::Logger::LogDevice)
|
54
|
+
expect(logdev.dev).to be($stdout)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "doesn't cache the default logger if the Rails logger is initialized later" do
|
58
|
+
Rails.logger = nil
|
59
|
+
|
60
|
+
initial_default_logger = Loggers.default_logger
|
61
|
+
|
62
|
+
expected_logger = double(::Logger)
|
63
|
+
Rails.logger = expected_logger
|
64
|
+
|
65
|
+
actual_logger = Loggers.default_logger
|
66
|
+
expect(actual_logger).not_to be(initial_default_logger)
|
67
|
+
expect(actual_logger).to be(expected_logger)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
describe :new_default_logger do
|
73
|
+
attr_reader :config
|
74
|
+
|
75
|
+
before(:each) do
|
76
|
+
app = Class.new(Rails::Application).new
|
77
|
+
@config = app.config
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'returns a file logger in test' do
|
81
|
+
BerkeleyLibrary::Logging.env = 'test'
|
82
|
+
logger = Loggers.new_default_logger(config)
|
83
|
+
expect(logger).not_to be_nil
|
84
|
+
logdev = logger.instance_variable_get(:@logdev)
|
85
|
+
expect(logdev.filename).to end_with('log/test.log')
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns a stdout logger in production' do
|
89
|
+
BerkeleyLibrary::Logging.env = 'production'
|
90
|
+
stdout_orig = $stdout
|
91
|
+
stdout_tmp = StringIO.new
|
92
|
+
begin
|
93
|
+
$stdout = stdout_tmp
|
94
|
+
logger = Loggers.new_default_logger(config)
|
95
|
+
ensure
|
96
|
+
$stdout = stdout_orig
|
97
|
+
end
|
98
|
+
expect(logger).not_to be_nil
|
99
|
+
logdev = logger.instance_variable_get(:@logdev)
|
100
|
+
expect(logdev.filename).to be_nil
|
101
|
+
expect(logdev.dev).to eq(stdout_tmp)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'returns a stdout logger in development' do
|
105
|
+
BerkeleyLibrary::Logging.env = 'development'
|
106
|
+
logger = Loggers.new_default_logger(config)
|
107
|
+
expect(logger).not_to be_nil
|
108
|
+
logdev = logger.instance_variable_get(:@logdev)
|
109
|
+
expect(logdev.filename).to be_nil
|
110
|
+
expect(logdev.dev).to eq($stdout)
|
111
|
+
|
112
|
+
# TODO: come up with a succinct way to test broadcast to file
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|