diff --git a/Gemfile b/Gemfile index 126add0..983ef67 100644 --- a/Gemfile +++ b/Gemfile @@ -22,6 +22,9 @@ gem "tzinfo-data", platforms: %i[ mswin jruby ] # Reduces boot times through caching; required in config/boot.rb gem "bootsnap", require: false +# json logging +gem "json_tagged_logger" + # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] # gem "image_processing", "~> 1.2" diff --git a/Gemfile.lock b/Gemfile.lock index 0f925c8..3646b5d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -112,6 +112,9 @@ GEM actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.7.2) + json_tagged_logger (0.8.0) + actionpack (>= 5.2) + activesupport (>= 5.2) jwt (2.9.3) base64 language_server-protocol (3.17.0.3) @@ -290,6 +293,7 @@ DEPENDENCIES faraday-retry interactor (~> 3.0) jbuilder + json_tagged_logger jwt ostruct puma (>= 5.0) diff --git a/app/lib/audit_logger.rb b/app/lib/audit_logger.rb index 84c3442..788a6cc 100644 --- a/app/lib/audit_logger.rb +++ b/app/lib/audit_logger.rb @@ -1,6 +1,6 @@ class AuditLogger < ActiveSupport::Logger def initialize super(Config[:audit_log_file]) - self.formatter = AuditLogFormatter.new + self.formatter = JsonLogFormatter.new end end diff --git a/app/lib/audit_log_formatter.rb b/app/lib/json_log_formatter.rb similarity index 85% rename from app/lib/audit_log_formatter.rb rename to app/lib/json_log_formatter.rb index 0304ea4..5e759cd 100644 --- a/app/lib/audit_log_formatter.rb +++ b/app/lib/json_log_formatter.rb @@ -1,4 +1,4 @@ -class AuditLogFormatter < ActiveSupport::Logger::SimpleFormatter +class JsonLogFormatter < ActiveSupport::Logger::SimpleFormatter def call(severity, timestamp, _progname, message) # request_id is unique to the life of the api request request_id = Thread.current[:request_id] diff --git a/config/environments/production.rb b/config/environments/production.rb index 11bb8fd..467adad 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -47,14 +47,6 @@ # Skip http-to-https redirect for the default health check endpoint. # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } - # Log to STDOUT by default - config.logger = ActiveSupport::Logger.new(STDOUT) - .tap { |logger| logger.formatter = ::Logger::Formatter.new } - .then { |logger| ActiveSupport::TaggedLogging.new(logger) } - - # Prepend all log lines with the following tags. - config.log_tags = [ :request_id ] - # "info" includes generic and useful information about system operation, but avoids logging too much # information to avoid inadvertent exposure of personally identifiable information (PII). If you # want to log everything, set the level to "debug". diff --git a/config/initializers/logging.rb b/config/initializers/logging.rb new file mode 100644 index 0000000..9fb07bb --- /dev/null +++ b/config/initializers/logging.rb @@ -0,0 +1,4 @@ +Rails.logger = JsonTaggedLogger::Logger.new(Rails.logger) +Rails.configuration.log_tags = JsonTaggedLogger::LogTagsConfig.generate( + :request_id +) diff --git a/test/lib/audit_log_formatter_test.rb b/test/lib/json_log_formatter_test.rb similarity index 70% rename from test/lib/audit_log_formatter_test.rb rename to test/lib/json_log_formatter_test.rb index e23e185..ad73b6e 100644 --- a/test/lib/audit_log_formatter_test.rb +++ b/test/lib/json_log_formatter_test.rb @@ -1,19 +1,19 @@ require "test_helper" -class AuditLogFormatterTest < ActiveSupport::TestCase +class JsonLogFormatterTest < ActiveSupport::TestCase setup do Thread.current[:request_id] = nil end test "#call formats logformatter inputs as json" do t = Time.now - result = AuditLogFormatter.new.call("info", t, nil, "some message") + result = JsonLogFormatter.new.call("info", t, nil, "some message") assert_equal %Q({"type":"info","time":"#{t}","request_id":null,"message":"some message"}\n), result end test "#call accepts and merges a Hash type for the message" do t = Time.now - result = AuditLogFormatter.new.call("info", t, nil, { key: "some message", key2: "another" }) + result = JsonLogFormatter.new.call("info", t, nil, { key: "some message", key2: "another" }) assert_equal %Q({"type":"info","time":"#{t}","request_id":null,"key":"some message","key2":"another"}\n), result end @@ -21,7 +21,7 @@ class AuditLogFormatterTest < ActiveSupport::TestCase t = Time.now req_id = SecureRandom.hex Thread.stub :current, { request_id: req_id } do - result = AuditLogFormatter.new.call("info", t, nil, { key: "some message" }) + result = JsonLogFormatter.new.call("info", t, nil, { key: "some message" }) assert_equal %Q({"type":"info","time":"#{t}","request_id":"#{req_id}","key":"some message"}\n), result end end