diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9a6bf6414f3..22122a59ae8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2115,8 +2115,8 @@ lib/va_profile/profile/v3/health_benefit_bio_response.rb @department-of-veterans lib/va_profile/profile/v3/service.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/vfs-mhv-integration @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/controllers/v0/profile/contacts_controller_spec.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/vfs-mhv-integration @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/lib/va_profile/profile/v3/service_spec.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/vfs-mhv-integration @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -lib/logging/third_party_transaction.rb @department-of-veterans-affairs/backend-review-group -spec/lib/logging/third_party_transaction_spec.rb @department-of-veterans-affairs/backend-review-group +lib/logging @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers +spec/lib/logging @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers spec/lib/zero_silent_failures @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group Brewfile @department-of-veterans-affairs/backend-review-group docker-compose-deps.yml @department-of-veterans-affairs/backend-review-group diff --git a/lib/burials/monitor.rb b/lib/burials/monitor.rb index 62712b94531..1da80f43581 100644 --- a/lib/burials/monitor.rb +++ b/lib/burials/monitor.rb @@ -1,12 +1,14 @@ # frozen_string_literal: true -require 'zero_silent_failures/monitor' +require 'logging/monitor' module Burials ## # Monitor functions for Rails logging and StatsD # class Monitor < ::ZeroSilentFailures::Monitor + include Logging::Monitor + # statsd key for api CLAIM_STATS_KEY = 'api.burial_claim' diff --git a/lib/logging/monitor.rb b/lib/logging/monitor.rb new file mode 100644 index 00000000000..b5e9adb51ff --- /dev/null +++ b/lib/logging/monitor.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Logging + class Monitor < ::ZeroSilentFailures::Monitor + def initialize(service) + @service = service + super(@service) + end + + ## + # log GET request + # + # @param message [String] + # @param metric [String] + # @param form_type [String] + # @param user_account_uuid [User] + # + def track_request(message, metric, form_type = 'Unknown Form Type', user_account_uuid = nil, call_location: nil) + function, file, line = parse_caller(call_location) + + StatsD.increment(metric) + Rails.logger.error("#{form_type} #{message}", + { + statsd: metric, + user_account_uuid:, + function:, + file:, + line: + }) + end + end +end diff --git a/lib/logging/sidekiq.rb b/lib/logging/sidekiq.rb new file mode 100644 index 00000000000..5b190c8fd15 --- /dev/null +++ b/lib/logging/sidekiq.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +module Logging + class Sidekiq < Monitor + def initialize(service) + @service = service + super(@service) + end + + # ## + # log info request + # + # @param message [String] + # @param metric [String] + # @param claim [SavedClaim] + # @param benefits_intake_uuid [FormSubmissions] + # @param user_account_uuid [User] + # @param additional_context [Hash] + # + # rubocop:disable Metrics/ParameterLists + def track_claim_submission(message, metric, claim, benefits_intake_uuid, + user_account_uuid, additional_context, call_location: nil) + function, file, line = parse_caller(call_location) + + StatsD.increment(metric) + Rails.logger.info(message.to_s, + { + statsd: metric, + user_account_uuid:, + claim_id: claim&.id, + benefits_intake_uuid: benefits_intake_uuid, + confirmation_number: claim&.confirmation_number, + additional_context:, + function:, + file:, + line: + }) + end + + # ## + # log warn request + # + # @param message [String] + # @param metric [String] + # @param claim [SavedClaim] + # @param benefits_intake_uuid [FormSubmissions] + # @param user_account_uuid [User] + # @param additional_context [Hash] + # + def track_claim_submission_warn(message, metric, claim, benefits_intake_uuid, + user_account_uuid, additional_context, call_location: nil) + function, file, line = parse_caller(call_location) + + StatsD.increment(metric) + Rails.logger.warn(message.to_s, + { + statsd: metric, + user_account_uuid:, + claim_id: claim&.id, + benefits_intake_uuid: benefits_intake_uuid, + confirmation_number: claim&.confirmation_number, + additional_context:, + function:, + file:, + line: + }) + end + + # ## + # log error request + # + # @param message [String] + # @param metric [String] + # @param claim [SavedClaim] + # @param benefits_intake_uuid [FormSubmissions] + # @param user_account_uuid [User] + # @param additional_context [Hash] + # + def track_claim_submission_error(message, metric, claim, benefits_intake_uuid, + user_account_uuid, additional_context, call_location: nil) + function, file, line = parse_caller(call_location) + + StatsD.increment(metric) + Rails.logger.error(message.to_s, + { + statsd: metric, + user_account_uuid:, + claim_id: claim&.id, + benefits_intake_uuid: benefits_intake_uuid, + confirmation_number: claim&.confirmation_number, + additional_context:, + function:, + file:, + line: + }) + end + end + # rubocop:enable Metrics/ParameterLists +end diff --git a/lib/zero_silent_failures/monitor.rb b/lib/zero_silent_failures/monitor.rb index 2cdf4728d60..d62fbd03b3f 100644 --- a/lib/zero_silent_failures/monitor.rb +++ b/lib/zero_silent_failures/monitor.rb @@ -63,10 +63,6 @@ def log_silent_failure_avoided(additional_context, user_account_uuid = nil, call }) end - private - - attr_reader :service - # parse information from the `caller` # # @see https://alextaylor.ca/read/caller-tricks/ @@ -78,5 +74,9 @@ def parse_caller(call_location) call_location ||= caller_locations.second # default to location calling 'log_silent_failure...' [call_location.base_label, call_location.path, call_location.lineno] end + + private + + attr_reader :service end end diff --git a/modules/pensions/lib/pensions/monitor.rb b/modules/pensions/lib/pensions/monitor.rb index b588a315fb2..25102b39793 100644 --- a/modules/pensions/lib/pensions/monitor.rb +++ b/modules/pensions/lib/pensions/monitor.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'zero_silent_failures/monitor' +require 'logging/monitor' module Pensions ## @@ -8,6 +8,8 @@ module Pensions # @todo abstract, split logging for controller and sidekiq # class Monitor < ::ZeroSilentFailures::Monitor + include Logging::Monitor + # statsd key for api CLAIM_STATS_KEY = 'api.pension_claim' diff --git a/spec/lib/logging/monitor_spec.rb b/spec/lib/logging/monitor_spec.rb new file mode 100644 index 00000000000..c602c12e405 --- /dev/null +++ b/spec/lib/logging/monitor_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'zero_silent_failures/monitor' +require 'logging/monitor' + +RSpec.describe Logging::Monitor do + let(:service) { 'test-application' } + let(:monitor) { described_class.new(service) } + let(:call_location) { double('Location', base_label: 'method_name', path: '/path/to/file.rb', lineno: 42) } + let(:metric) { 'api.monitor.404' } + let(:form_type) { '21P-50EZ' } + let(:user_account_uuid) { '123-test-uuid' } + let(:payload) do + { + statsd: 'OVERRIDE', + user_account_uuid:, + function: call_location.base_label, + file: call_location.path, + line: call_location.lineno + } + end + + context 'with a call location provided' do + describe '#track_request' do + it 'logs a request with call location' do + payload[:statsd] = 'api.monitor.404' + + expect(StatsD).to receive(:increment).with('api.monitor.404') + expect(Rails.logger).to receive(:error).with('21P-50EZ 404 Not Found!', payload) + + monitor.track_request('404 Not Found!', metric, form_type, user_account_uuid, call_location:) + end + end + end +end diff --git a/spec/lib/logging/sidekiq_spec.rb b/spec/lib/logging/sidekiq_spec.rb new file mode 100644 index 00000000000..4d8ba550a96 --- /dev/null +++ b/spec/lib/logging/sidekiq_spec.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'zero_silent_failures/monitor' +require 'logging/monitor' +require 'logging/sidekiq' + +RSpec.describe Logging::Sidekiq do + let(:service) { 'test-application' } + let(:monitor) { described_class.new(service) } + let(:call_location) { double('Location', base_label: 'method_name', path: '/path/to/file.rb', lineno: 42) } + let(:metric) { 'api.monitor.sidekiq' } + let(:user_account_uuid) { '123-test-uuid' } + let(:benefits_intake_uuid) { '123-test-uuid' } + let(:additional_context) { { file: 'foobar.pdf', attachments: ['file.txt', 'file2.txt'] } } + let(:claim) do + FactoryBot.create( + :pensions_module_pension_claim, + form: { + veteranFullName: { + first: 'Test', + last: 'User' + }, + email: 'foo@foo.com', + veteranDateOfBirth: '1989-12-13', + veteranSocialSecurityNumber: '111223333', + veteranAddress: { + country: 'USA', + state: 'CA', + postalCode: '90210', + street: '123 Main St', + city: 'Anytown' + }, + statementOfTruthCertified: true, + statementOfTruthSignature: 'Test User' + }.to_json + ) + end + let(:payload) do + { + statsd: 'OVERRIDE', + user_account_uuid: user_account_uuid, + claim_id: claim&.id, + benefits_intake_uuid: benefits_intake_uuid, + confirmation_number: claim&.confirmation_number, + additional_context: additional_context, + function: call_location.base_label, + file: call_location.path, + line: call_location.lineno + } + end + + context 'with a call location provided' do + describe '#track_claim_submission' do + it 'logs a request with call location' do + payload[:statsd] = 'api.monitor.sidekiq' + + expect(StatsD).to receive(:increment).with('api.monitor.sidekiq') + expect(Rails.logger).to receive(:info).with('Lighthouse::Job submission to LH attempted', payload) + + monitor.track_claim_submission('Lighthouse::Job submission to LH attempted', metric, claim, + benefits_intake_uuid, user_account_uuid, additional_context, call_location:) + end + end + + describe '#track_claim_submission_warn' do + it 'logs a request with call location' do + payload[:statsd] = 'api.monitor.sidekiq' + + expect(StatsD).to receive(:increment).with('api.monitor.sidekiq') + expect(Rails.logger).to receive(:warn).with('Lighthouse::Job submission to LH failure', payload) + + monitor.track_claim_submission_warn('Lighthouse::Job submission to LH failure', metric, claim, + benefits_intake_uuid, user_account_uuid, additional_context, call_location:) + end + end + + describe '#track_claim_submission_error' do + it 'logs a request with call location' do + payload[:statsd] = 'api.monitor.sidekiq' + + expect(StatsD).to receive(:increment).with('api.monitor.sidekiq') + expect(Rails.logger).to receive(:error).with('Lighthouse::Job submission to LH exhausted!', payload) + + monitor.track_claim_submission_error('Lighthouse::Job submission to LH exhausted!', metric, claim, + benefits_intake_uuid, user_account_uuid, + additional_context, call_location:) + end + end + end +end