Skip to content

Commit a9133bd

Browse files
committed
feat(logging): implement structured logging
- Replaces default Ruby logger with semantic_logger for better log shipping experience - Make backwards compatible with existing config, by logging to file with the same format as default Ruby - TODO: documentation
1 parent c4f23bc commit a9133bd

26 files changed

+91
-72
lines changed

lib/db.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
require 'pact_broker/project_root'
77

88
module DB
9-
include PactBroker::Logging
9+
include SemanticLogger::Loggable
1010
##
1111
# Sequel by default does not test connections in its connection pool before
1212
# handing them to a client. To enable connection testing you need to load the

lib/pact_broker/api/renderers/html_pact_renderer.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class HtmlPactRenderer
1212

1313
class NotAPactError < StandardError; end
1414

15-
include PactBroker::Logging
15+
include SemanticLogger::Loggable
1616

1717
def self.call pact, options = {}
1818
new(pact, options).call

lib/pact_broker/api/resources/base_resource.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class BaseResource < Webmachine::Resource
2121
include PactBroker::Services
2222
include PactBroker::Api::PactBrokerUrls
2323
include PactBroker::Api::Resources::Authentication
24-
include PactBroker::Logging
24+
include SemanticLogger::Loggable
2525

2626

2727
attr_accessor :user

lib/pact_broker/api/resources/error_handler.rb

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Api
66
module Resources
77
class ErrorHandler
88

9+
include SemanticLogger::Loggable
910
include PactBroker::Logging
1011

1112
def self.call e, request, response

lib/pact_broker/app.rb

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'pact_broker/configuration'
22
require 'pact_broker/db'
33
require 'pact_broker/project_root'
4+
require 'pact_broker/default_formatter'
45
require 'rack-protection'
56
require 'rack/hal_browser'
67
require 'rack/pact_broker/store_base_url'
@@ -18,6 +19,7 @@
1819
module PactBroker
1920

2021
class App
22+
include SemanticLogger::Loggable
2123

2224
attr_accessor :configuration
2325

@@ -58,13 +60,9 @@ def call env
5860

5961
private
6062

61-
def logger
62-
PactBroker.logger
63-
end
64-
6563
def post_configure
66-
PactBroker.logger = configuration.logger
67-
SuckerPunch.logger = configuration.logger
64+
configure_logger
65+
SuckerPunch.logger = SemanticLogger['SuckerPunch']
6866
configure_database_connection
6967
configure_sucker_punch
7068
end
@@ -166,6 +164,14 @@ def configure_sucker_punch
166164
end
167165
end
168166

167+
def configure_logger
168+
if SemanticLogger.appenders.empty?
169+
path = configuration.log_dir + "/pact_broker.log"
170+
FileUtils.mkdir_p(configuration.log_dir)
171+
SemanticLogger.add_appender(file_name: path, formatter: PactBroker::Logging::DefaultFormatter.new)
172+
end
173+
end
174+
169175
def running_app
170176
@running_app ||= begin
171177
apps = @cascade_apps

lib/pact_broker/badges/service.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module Badges
1010
module Service
1111

1212
extend self
13-
include PactBroker::Logging
13+
include SemanticLogger::Loggable
1414

1515
SPACE_DASH_UNDERSCORE = /[\s_\-]/
1616
CACHE = {}

lib/pact_broker/certificates/service.rb

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module Service
88

99
extend self
1010
extend PactBroker::Logging
11+
include SemanticLogger::Loggable
1112

1213
def cert_store
1314
cert_store = OpenSSL::X509::Store.new

lib/pact_broker/config/load.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module PactBroker
77
module Config
88
class Load
99

10-
include PactBroker::Logging
10+
include SemanticLogger::Loggable
1111

1212
def self.call configuration
1313
new(configuration).call

lib/pact_broker/config/save.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module PactBroker
66
module Config
77
class Save
88

9-
include PactBroker::Logging
9+
include SemanticLogger::Loggable
1010

1111
def self.call configuration, setting_names
1212
new(configuration, setting_names).call

lib/pact_broker/configuration.rb

+2-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'pact_broker/error'
22
require 'pact_broker/config/space_delimited_string_list'
3+
require 'semantic_logger'
34

45
module PactBroker
56

@@ -15,6 +16,7 @@ def self.reset_configuration
1516
end
1617

1718
class Configuration
19+
include SemanticLogger::Loggable
1820

1921
SAVABLE_SETTING_NAMES = [
2022
:order_versions_by_date,
@@ -52,10 +54,6 @@ def initialize
5254
@api_error_reporters = []
5355
end
5456

55-
def logger
56-
@logger ||= create_logger log_path
57-
end
58-
5957
def self.default_configuration
6058
require 'pact_broker/versions/parse_semantic_version'
6159
require 'pact_broker/pacts/generate_sha'
@@ -202,13 +200,6 @@ def parse_space_delimited_string_list_property property_name, property_value
202200
end
203201
end
204202

205-
def create_logger path
206-
FileUtils::mkdir_p File.dirname(path)
207-
logger = Logger.new(path)
208-
logger.level = Logger::DEBUG
209-
logger
210-
end
211-
212203
def log_path
213204
log_dir + "/pact_broker.log"
214205
end

lib/pact_broker/default_formatter.rb

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
require 'logger'
2+
require 'semantic_logger'
3+
4+
module PactBroker
5+
6+
module Logging
7+
8+
class DefaultFormatter < SemanticLogger::Formatters::Default
9+
def initialize
10+
@formatter = ::Logger::Formatter.new
11+
end
12+
13+
def call(log, output)
14+
@formatter.call(log.level.upcase, log.time, nil, log.message)
15+
end
16+
end
17+
end
18+
end

lib/pact_broker/domain/order_versions.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module PactBroker
44
module Domain
55
class OrderVersions
66

7-
include PactBroker::Logging
7+
include SemanticLogger::Loggable
88

99
def self.call new_version
1010
new_version.lock!

lib/pact_broker/domain/webhook_request.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def redact? name
5353

5454
class WebhookRequest
5555

56-
include PactBroker::Logging
56+
include SemanticLogger::Loggable
5757
include PactBroker::Messages
5858
HEADERS_TO_REDACT = [/authorization/i, /token/i]
5959

lib/pact_broker/logging.rb

+1-19
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,18 @@
1-
require 'logger'
21
require 'pathname'
2+
require 'semantic_logger'
33

44
module PactBroker
55

66
module Logging
7-
8-
# Need to make this configurable based on the calling app!
9-
LOG_DIR = Pathname.new(File.join(File.dirname(__FILE__), '..', '..', 'log')).cleanpath
10-
LOG_FILE_NAME = "#{ENV['RACK_ENV'] || 'development'}.log"
11-
127
def self.included(base)
138
base.extend(self)
149
end
1510

16-
def logger= logger
17-
@@logger = logger
18-
end
19-
2011
def log_error e, description = nil
2112
message = "#{e.class} #{e.message} #{e.backtrace.join("\n")}"
2213
message = "#{description} - #{message}" if description
2314
logger.error message
2415
end
25-
26-
def logger
27-
@@logger ||= begin
28-
FileUtils.mkdir_p(LOG_DIR)
29-
logger = Logger.new(File.join(LOG_DIR, LOG_FILE_NAME))
30-
logger.level = Logger::DEBUG
31-
logger
32-
end
33-
end
3416
end
3517

3618
include Logging

lib/pact_broker/matrix/row.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class Row < Sequel::Model(:matrix)
2424

2525
dataset_module do
2626
include PactBroker::Repositories::Helpers
27-
include PactBroker::Logging
27+
include SemanticLogger::Loggable
2828

2929
def matching_selectors selectors
3030
if selectors.size == 1

lib/pact_broker/pacts/repository.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ module PactBroker
1717
module Pacts
1818
class Repository
1919

20-
include PactBroker::Logging
20+
include SemanticLogger::Loggable
2121
include PactBroker::Repositories
2222

2323
def create params

lib/pact_broker/pacts/service.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module Service
1111

1212
extend PactBroker::Repositories
1313
extend PactBroker::Services
14-
include PactBroker::Logging
14+
include SemanticLogger::Loggable
1515

1616
def find_latest_pact params
1717
pact_repository.find_latest_pact(params[:consumer_name], params[:provider_name], params[:tag])

lib/pact_broker/webhooks/job.rb

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module Webhooks
77
class Job
88

99
include SuckerPunch::Job
10+
include SemanticLogger::Loggable
1011
include PactBroker::Logging
1112

1213
def perform data

lib/pact_broker/webhooks/webhook_request_template.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module PactBroker
77
module Webhooks
88
class WebhookRequestTemplate
99

10-
include PactBroker::Logging
10+
include SemanticLogger::Loggable
1111
include PactBroker::Messages
1212
HEADERS_TO_REDACT = [/authorization/i, /token/i]
1313

pact_broker.gemspec

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Gem::Specification.new do |gem|
3939
gem.add_runtime_dependency 'rack-protection', '~>2.0'
4040
gem.add_runtime_dependency 'dry-types', '~> 0.10.3' # https://travis-ci.org/pact-foundation/pact_broker/jobs/249448621
4141
gem.add_runtime_dependency 'table_print', '~> 1.5'
42+
gem.add_runtime_dependency 'semantic_logger', '~> 4.3'
4243

4344
gem.add_development_dependency 'pact', '~>1.14'
4445
gem.add_development_dependency 'rspec-pact-matchers', '~>0.1'

spec/lib/pact_broker/api/renderers/html_pact_renderer_spec.rb

+5-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ module Renderers
1111
ENV['BACKUP_TZ'] = ENV['TZ']
1212
ENV['TZ'] = "Australia/Melbourne"
1313
PactBroker.configuration.enable_public_badge_access = true
14+
allow(PactBroker::Api::PactBrokerUrls).to receive(:pact_url).with('', pact).and_return(pact_url)
15+
allow_any_instance_of(HtmlPactRenderer).to receive(:logger).and_return(logger)
1416

1517
Timecop.freeze(created_at + 3)
1618
end
@@ -32,10 +34,7 @@ module Renderers
3234
badge_url: 'http://badge'
3335
}
3436
end
35-
36-
before do
37-
allow(PactBroker::Api::PactBrokerUrls).to receive(:pact_url).with('', pact).and_return(pact_url)
38-
end
37+
let(:logger) { double('logger').as_null_object }
3938

4039
subject { HtmlPactRenderer.call pact, options }
4140

@@ -95,8 +94,8 @@ module Renderers
9594
end
9695

9796
it "logs a warning" do
98-
allow(PactBroker.logger).to receive(:warn).with(/Error/)
99-
expect(PactBroker.logger).to receive(:warn).with(/Could not parse/)
97+
allow(logger).to receive(:warn).with(/Error/)
98+
expect(logger).to receive(:warn).with(/Could not parse/)
10099
subject
101100
end
102101
end

spec/lib/pact_broker/api/resources/error_handler_spec.rb

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ module Api
55
module Resources
66
describe ErrorHandler do
77
describe "call" do
8+
9+
before do
10+
allow(ErrorHandler).to receive(:logger).and_return(logger)
11+
end
12+
13+
let(:logger) { double('logger').as_null_object }
814
let(:error) { StandardError.new('test error') }
915
let(:thing) { double('thing', call: nil, another_call: nil) }
1016
let(:options) { { env: env } }
@@ -91,7 +97,7 @@ class TestError < StandardError; end
9197
end
9298

9399
it "logs the error" do
94-
expect(PactBroker.logger).to receive(:error).at_least(1).times
100+
expect(logger).to receive(:error).at_least(1).times
95101
subject
96102
end
97103

spec/lib/pact_broker/badges/service_spec.rb

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module Service
1010
let(:label) { nil }
1111
let(:initials) { false }
1212
let(:verification_status) { :success }
13-
13+
let(:logger) { double('logger').as_null_object }
1414
let(:expected_url) { "https://img.shields.io/badge/#{expected_left_text}-#{expected_right_text}-#{expected_color}.svg" }
1515
let(:expected_color) { "brightgreen" }
1616
let(:expected_right_text) { "verified" }
@@ -24,6 +24,7 @@ module Service
2424

2525
before do
2626
Service.clear_cache
27+
allow(Service).to receive(:logger).and_return(logger)
2728
end
2829

2930
it "returns the svg file" do
@@ -224,7 +225,7 @@ module Service
224225
end
225226

226227
it "logs the error" do
227-
expect(PactBroker.logger).to receive(:error).with(/Error retrieving badge from.*shield.*an error/)
228+
expect(logger).to receive(:error).with(/Error retrieving badge from.*shield.*an error/)
228229
subject
229230
end
230231

0 commit comments

Comments
 (0)