require 'elastic-apm' module Ecoportal module API module Common module ElasticApmIntegration class UnexpectedServerError < StandardError def initialize(code, msg) super("Code: #{code} -- Error: #{msg}") end end APM_SERVICE_NAME = 'ecoportal-api-gem' # Log only errors that are only server's responsibility def log_unexpected_server_error(response) raise "Expecting Ecoportal::API::Common::Response. Given: #{response.class}" unless response.is_a?(Common::Response) return nil unless elastic_apm_service return nil unless unexpected_server_error?(response.status) if ElasticAPM.running? ElasticAPM.report(UnexpectedServerError.new(response.status, response.body)) end end private def unexpected_server_error?(code) code && (code >= 500) && (code <= 599) end # finalizer to stop the agent close_elastic_apm = Proc.new do |id| begin if ElasticAPM.running? puts "Stopping ElasticAPM service" ElasticAPM.stop end rescue StandardError => e # Silent end end ObjectSpace.define_finalizer("ElasticAPM", close_elastic_apm) def elastic_apm_service return false if @disable_apm begin ElasticAPM.start(**elastic_apm_options) unless ElasticAPM.running? rescue StandardError => e @disable_apm = true puts "ElasticAPM services not available: #{e}" end end def elastic_apm_options { service_name: APM_SERVICE_NAME, server_url: elastic_apm_url, secret_token: elastic_apm_key, environment: environment, #http_compression: false, transaction_sample_rate: 0.1, transaction_max_spans: 100, span_frames_min_duration: "5ms" }.tap do |options| options.merge!({ log_level: Logger::DEBUG, log_path: File.join(__dir__, "elastic_apm.log") }) if false end end def elastic_apm_url @elastic_apm_url ||= "https://".tap do |url| url << "#{elastic_apm_account_id}" url << ".#{elastic_apm_base_url}" url << ":#{elastic_apm_port}" end end def elastic_apm_key @elastic_apm_key ||= ENV['ELASTIC_APM_KEY'] end def elastic_apm_account_id @elastic_apm_account_id ||= ENV['ELASTIC_APM_ACCOUNT_ID'] end def elastic_apm_base_url @elastic_apm_base_url ||= "apm.#{elastic_apm_region}.aws.cloud.es.io" end def elastic_apm_region @elastic_apm_region ||= ENV['ELASTIC_APM_REGION'] || "ap-southeast-2" end def elastic_apm_port @elastic_apm_port ||= ENV['ELASTIC_APM_PORT'] || "443" end def environment @environment ||= "unknown".tap do |value| if instance_variable_defined?(:@host) && env = @host.gsub(".ecoportal.com", '') value.clear << env end end end end end end end