class Coverband::Adapters::Service
Take Coverband
data and store a merged coverage set to the Coverband
service
NOTES:
-
uses net/http to avoid any dependencies
-
currently JSON, but likely better to move to something faster
Attributes
coverband_url[R]
hostname[R]
pid[R]
process_type[R]
runtime_env[R]
stats[R]
Public Class Methods
new(coverband_url, opts = {})
click to toggle source
Calls superclass method
# File lib/coverband-service-client.rb, line 45 def initialize(coverband_url, opts = {}) super() @coverband_url = coverband_url @process_type = opts.fetch(:process_type) { $PROGRAM_NAME&.split('/')&.last || COVERBAND_PROCESS_TYPE } @hostname = opts.fetch(:hostname) { ENV["DYNO"] || Socket.gethostname.force_encoding('utf-8').encode } @hostname = @hostname.gsub("'",'').gsub("’",'') @runtime_env = opts.fetch(:runtime_env) { COVERBAND_ENV } @failed_coverage_reports = [] initialize_stats end
Public Instance Methods
api_key()
click to toggle source
# File lib/coverband-service-client.rb, line 92 def api_key ENV['COVERBAND_API_KEY'] || Coverband.configuration.api_key end
clear!()
click to toggle source
# File lib/coverband-service-client.rb, line 79 def clear! # TBD end
clear_file!(filename)
click to toggle source
# File lib/coverband-service-client.rb, line 83 def clear_file!(filename) # TBD end
coverage(local_type = nil, opts = {})
click to toggle source
Fetch coverband coverage via the API
# File lib/coverband-service-client.rb, line 99 def coverage(local_type = nil, opts = {}) local_type ||= opts.key?(:override_type) ? opts[:override_type] : type env_filter = opts.key?(:env_filter) ? opts[:env_filter] : 'production' uri = URI("#{coverband_url}/api/coverage?type=#{local_type}&env_filter=#{env_filter}",) req = Net::HTTP::Get.new(uri, 'Content-Type' => 'application/json', 'Coverband-Token' => api_key) res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http| http.request(req) end coverage_data = JSON.parse(res.body) coverage_data rescue StandardError => e logger&.error "Coverband: Error while retrieving coverage #{e}" if Coverband.configuration.verbose || COVERBAND_ENABLE_DEV_MODE end
initialize_stats()
click to toggle source
# File lib/coverband-service-client.rb, line 56 def initialize_stats return unless ENV['COVERBAND_STATS_KEY'] return unless defined?(Dogapi::Client) @stats = Dogapi::Client.new(ENV['COVERBAND_STATS_KEY']) @app_name = defined?(Rails) ? Rails.application.class.module_parent.to_s : "unknown" end
logger()
click to toggle source
# File lib/coverband-service-client.rb, line 75 def logger Coverband.configuration.logger end
raw_store()
click to toggle source
# File lib/coverband-service-client.rb, line 145 def raw_store self end
report_timing(timing)
click to toggle source
# File lib/coverband-service-client.rb, line 64 def report_timing(timing) return unless @stats @stats.emit_point( 'coverband.save.time', timing, host: hostname, device: "coverband_#{self.class.name.split("::").last}", options: {tags: [runtime_env]}) end
save_report(report)
click to toggle source
# File lib/coverband-service-client.rb, line 113 def save_report(report) return if report.empty? # We set here vs initialize to avoid setting on the primary process vs child processes @pid ||= ::Process.pid # TODO: do we need dup # TODO: remove upstream timestamps, server will track first_seen Thread.new do data = expand_report(report.dup) full_package = { collection_type: 'coverage_delta', collection_data: { tags: { process_type: process_type, app_loading: type == Coverband::EAGER_TYPE, runtime_env: runtime_env, pid: pid, hostname: hostname, }, file_coverage: data } } starting = Process.clock_gettime(Process::CLOCK_MONOTONIC) if @stats save_coverage(full_package) ending = Process.clock_gettime(Process::CLOCK_MONOTONIC) if @stats report_timing((ending - starting)) if @stats retry_failed_reports end&.join end
size()
click to toggle source
TODO: we should support nil to mean not supported
# File lib/coverband-service-client.rb, line 88 def size 0 end
Private Instance Methods
add_retry_message(report_body)
click to toggle source
# File lib/coverband-service-client.rb, line 164 def add_retry_message(report_body) if @failed_coverage_reports.length > 5 logger&.info "Coverband: The errored reporting queue has reached 5. Subsequent reports will not be transmitted" else @failed_coverage_reports << report_body end end
retry_failed_reports()
click to toggle source
# File lib/coverband-service-client.rb, line 151 def retry_failed_reports retries = [] @failed_coverage_reports.any? do report_body = @failed_coverage_reports.pop send_report_body(report_body) rescue StandardError retries << report_body end retries.each do |report_body| add_retry_message(report_body) end end
save_coverage(data)
click to toggle source
# File lib/coverband-service-client.rb, line 172 def save_coverage(data) if api_key.nil? puts "Coverband: Error: no Coverband API key was found!" return end coverage_body = { remote_uuid: SecureRandom.uuid, data: data }.to_json send_report_body(coverage_body) rescue StandardError => e add_retry_message(coverage_body) logger&.info "Coverband: Error while saving coverage #{e}" if Coverband.configuration.verbose || COVERBAND_ENABLE_DEV_MODE end
send_report_body(coverage_body)
click to toggle source
# File lib/coverband-service-client.rb, line 185 def send_report_body(coverage_body) uri = URI("#{coverband_url}/api/collector") req = ::Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json', 'Coverband-Token' => api_key) req.body = coverage_body logger&.info "Coverband: saving (#{uri}) #{req.body}" if Coverband.configuration.verbose res = ::Net::HTTP.start( uri.hostname, uri.port, open_timeout: COVERBAND_TIMEOUT, read_timeout: COVERBAND_TIMEOUT, ssl_timeout: COVERBAND_TIMEOUT, use_ssl: uri.scheme == 'https' ) do |http| http.request(req) end if res.code.to_i >= 500 add_retry_message(coverage_body) end end