diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c9dcd6..ecacb57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased + +* Fix OpenTelemetry errors when using with Logstasher gem ([#372](https://github.com/alphagov/govuk_app_config/pull/372)) + # 9.11.0 * Add GDS::SSO::PermissionDeniedError to excluded exceptions list ([#366](https://github.com/alphagov/govuk_app_config/pull/366)) diff --git a/lib/govuk_app_config/govuk_json_logging.rb b/lib/govuk_app_config/govuk_json_logging.rb index 79c35ce..9c8ff3c 100644 --- a/lib/govuk_app_config/govuk_json_logging.rb +++ b/lib/govuk_app_config/govuk_json_logging.rb @@ -16,6 +16,12 @@ def add_custom_fields(&block) end def self.configure(&block) + # Fixes the monkey patch from the logstasher gem to support Rails 7 + config = Rails.application.config.logstasher + if (!config.controller_monkey_patch && config.controller_monkey_patch != false) || config.controller_monkey_patch == true + require_relative "./govuk_json_logging/rails_ext/action_controller/metal/instrumentation" + end + configuration = Configuration.new configuration.instance_eval(&block) if block_given? diff --git a/lib/govuk_app_config/govuk_json_logging/rails_ext/action_controller/metal/instrumentation.rb b/lib/govuk_app_config/govuk_json_logging/rails_ext/action_controller/metal/instrumentation.rb new file mode 100644 index 0000000..19773ba --- /dev/null +++ b/lib/govuk_app_config/govuk_json_logging/rails_ext/action_controller/metal/instrumentation.rb @@ -0,0 +1,65 @@ +# This is copied from +# https://github.com/shadabahmed/logstasher/blob/main/lib/logstasher/rails_ext/action_controller/metal/instrumentation.rb +# Changes have been highlight in comments, otherwise the code is the same. + +module ActionController + module Instrumentation + alias_method "orig_process_action", "process_action" + + def process_action(*args) + # The raw payload has been updated to reflect the payload structure used + # in Rails 7.1, primarily the addition of the `headers`, `request` keys + # and using `request.filtered_path` instead of `request.fullpath`. + # https://github.com/rails/rails/blame/d39db5d1891f7509cde2efc425c9d69bbb77e670/actionpack/lib/action_controller/metal/instrumentation.rb#L60 + raw_payload = { + controller: self.class.name, + action: action_name, + request:, + params: request.filtered_parameters, + headers: request.headers, + format: request.format.ref, + method: request.request_method, + path: begin + request.filtered_path + rescue StandardError + "unknown" + end, + } + + LogStasher.add_default_fields_to_payload(raw_payload, request) + + LogStasher.clear_request_context + LogStasher.add_default_fields_to_request_context(request) + + ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup) + + ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload| + if respond_to?(:logstasher_add_custom_fields_to_request_context) + logstasher_add_custom_fields_to_request_context(LogStasher.request_context) + end + + if respond_to?(:logstasher_add_custom_fields_to_payload) + before_keys = raw_payload.keys.clone + logstasher_add_custom_fields_to_payload(raw_payload) + after_keys = raw_payload.keys + # Store all extra keys added to payload hash in payload itself. This is a thread safe way + LogStasher::CustomFields.add(*(after_keys - before_keys)) + end + + result = super + + payload[:status] = response.status + append_info_to_payload(payload) + LogStasher.store.each do |key, value| + payload[key] = value + end + + LogStasher.request_context.each do |key, value| + payload[key] = value + end + result + end + end + alias_method "logstasher_process_action", "process_action" + end +end diff --git a/spec/lib/govuk_json_logging_spec.rb b/spec/lib/govuk_json_logging_spec.rb index ac8da16..9b63ec5 100644 --- a/spec/lib/govuk_json_logging_spec.rb +++ b/spec/lib/govuk_json_logging_spec.rb @@ -16,6 +16,7 @@ def self.headers end end end + before do stub_const("DummyLoggingRailsApp", Class.new(Rails::Application) do config.hosts.clear