coverband-service-client 0.0.8 → 0.0.12.rc.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9d70bb9e3268a13b06640e0437e517cf00ccc4030f2b7f2c20e7b314d26828e2
4
- data.tar.gz: 3400abcd93c90f5f8bb011757933dd08b0619ef907d3f2675a1326bb5eb7a102
3
+ metadata.gz: 9b93d9abe50ba1657318562b8fa04b645cfdd2fc22bca0f711cbde57b6d6b3c7
4
+ data.tar.gz: 1918f4689b50c6bda5b51d2f578b13b4bf439d38fb3510318165152b9093f1d2
5
5
  SHA512:
6
- metadata.gz: fd6972fc75a2e8320a6ce2f991e871df0fed4c6a1298e0d2a443c479d309aca58d56f6c9c0aa346731fec7e1a9e12836e2cdb18480bd687667804f7b3d2a802d
7
- data.tar.gz: e4bd36b15a82c5ab95fcc770909d04b3426d818a1468b90cf1f45667facd1f4fda9d37809c667c85b822b7b8651f3f8576d8323914c331bf207a6458bad81e99
6
+ metadata.gz: 33c461c2915ef4f9582fd8f87b5b2afa230076f1349e88ef7f66987cb1a8dda25d97c26983421ca52f900c3dd2d48d313e44dd69a8b15984a349dbe3fe4b3fd9
7
+ data.tar.gz: 0ea1b378ae8044400d50ad33944881d27552b42296cae06ceda360617b30d26a9bb3614e6a81c10b0bd530bcf59ca10ef9be3fba928e4c98b2f22929c21f4a66
@@ -1,17 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- coverband-service-client (0.0.8)
4
+ coverband-service-client (0.0.12.rc.1)
5
5
  coverband (~> 4.2.4)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- coverband (4.2.4)
10
+ coverband (4.2.5)
11
11
  redis
12
12
  minitest (5.14.0)
13
13
  rake (13.0.1)
14
- redis (4.1.3)
14
+ redis (4.1.4)
15
15
 
16
16
  PLATFORMS
17
17
  ruby
@@ -1,24 +1,32 @@
1
1
  # frozen_string_literal: true
2
+ require 'socket'
2
3
 
4
+ COVERBAND_ORIGINAL_START = ENV['COVERBAND_DISABLE_AUTO_START']
5
+ ENV['COVERBAND_DISABLE_AUTO_START'] = 'true'
3
6
  require 'coverband'
4
7
  require 'coverband/service/client/version'
5
8
  require 'securerandom'
6
9
 
7
- COVERBAND_ENV = ENV['RACK_ENV'] || ENV['RAILS_ENV'] || (defined?(Rails) ? Rails.env : 'unknown')
8
- COVERBAND_SERVICE_URL = ENV['COVERBAND_URL'] || 'https://coverband.io'
9
- COVERBAND_TIMEOUT = (COVERBAND_ENV == 'development') ? 5 : 1
10
- COVERBAND_ENABLE_DEV_MODE = ENV['COVERBAND_ENABLE_DEV_MODE'] || false
11
- COVERBAND_ENABLE_TEST_MODE = ENV['COVERBAND_ENABLE_TEST_MODE'] || false
12
- COVERBAND_PROCESS_TYPE = ENV['PROCESS_TYPE'] || 'unknown'
13
- COVERBAND_REPORT_PERIOD = (ENV['COVERBAND_REPORT_PERIOD'] || 600).to_i
14
-
15
10
  module Coverband
11
+ COVERBAND_ENV = ENV['RACK_ENV'] || ENV['RAILS_ENV'] || (defined?(Rails) ? Rails.env : 'unknown')
12
+ COVERBAND_SERVICE_URL = ENV['COVERBAND_URL'] || 'https://coverband.io'
13
+ COVERBAND_TIMEOUT = (COVERBAND_ENV == 'development') ? 5 : 2
14
+ COVERBAND_ENABLE_DEV_MODE = ENV['COVERBAND_ENABLE_DEV_MODE'] || false
15
+ COVERBAND_ENABLE_TEST_MODE = ENV['COVERBAND_ENABLE_TEST_MODE'] || false
16
+ COVERBAND_PROCESS_TYPE = ENV['PROCESS_TYPE'] || 'unknown'
17
+ COVERBAND_REPORT_PERIOD = (ENV['COVERBAND_REPORT_PERIOD'] || 600).to_i
18
+
19
+ def self.service_disabled_dev_test_env?
20
+ (COVERBAND_ENV == 'test' && !COVERBAND_ENABLE_TEST_MODE) ||
21
+ (COVERBAND_ENV == 'development' && !COVERBAND_ENABLE_DEV_MODE)
22
+ end
16
23
 
17
- if ((COVERBAND_ENV == 'test' && !COVERBAND_ENABLE_TEST_MODE) ||
18
- COVERBAND_ENV == 'development' && !COVERBAND_ENABLE_DEV_MODE
19
- )
24
+ if service_disabled_dev_test_env?
20
25
  def self.report_coverage
21
- # for now disable coverband reporting in test env by default
26
+ # for now disable coverband reporting in test & dev env by default
27
+ if Coverband.configuration.verbose
28
+ puts "Coverband: disabled for #{COVERBAND_ENV}, set COVERBAND_ENABLE_DEV_MODE or COVERBAND_ENABLE_TEST_MODE to enable" if Coverband.configuration.verbose || COVERBAND_ENABLE_DEV_MODE
29
+ end
22
30
  end
23
31
  end
24
32
 
@@ -28,16 +36,40 @@ module Coverband
28
36
  #
29
37
  # NOTES:
30
38
  # * uses net/http to avoid any dependencies
31
- # * currently JSON, but likely better to move to something simpler / faster
39
+ # * currently JSON, but likely better to move to something faster
32
40
  ###
33
41
  class Service < Base
34
- attr_reader :coverband_url, :process_type, :runtime_env
42
+ attr_reader :coverband_url, :process_type, :runtime_env, :hostname, :pid, :stats
35
43
 
36
44
  def initialize(coverband_url, opts = {})
37
45
  super()
38
46
  @coverband_url = coverband_url
39
- @process_type = opts.fetch(:process_type) { COVERBAND_PROCESS_TYPE }
47
+ @process_type = opts.fetch(:process_type) { $PROGRAM_NAME&.split('/')&.last || COVERBAND_PROCESS_TYPE }
48
+ @hostname = opts.fetch(:hostname) { ENV["DYNO"] || Socket.gethostname.force_encoding('utf-8').encode }
40
49
  @runtime_env = opts.fetch(:runtime_env) { COVERBAND_ENV }
50
+ initialize_stats
51
+ end
52
+
53
+ def initialize_stats
54
+ return unless ENV['COVERBAND_STATS_KEY']
55
+ return unless defined?(Dogapi::Client)
56
+
57
+ @stats = Dogapi::Client.new(ENV['COVERBAND_STATS_KEY'])
58
+ end
59
+
60
+ def report_timing(timing)
61
+ return unless @stats
62
+
63
+ @stats.emit_point(
64
+ 'coverband.save.time',
65
+ timing,
66
+ host: hostname,
67
+ env: runtime_env,
68
+ client: "coverband_#{self.class.name.split("::").last}")
69
+ end
70
+
71
+ def logger
72
+ Coverband.configuration.logger
41
73
  end
42
74
 
43
75
  def clear!
@@ -53,28 +85,35 @@ module Coverband
53
85
  0
54
86
  end
55
87
 
56
- # TODO: no longer get by type just get both reports in a single request
88
+ def api_key
89
+ ENV['COVERBAND_API_KEY'] || Coverband.configuration.api_key
90
+ end
91
+
92
+ ###
93
+ # Fetch coverband coverage via the API
94
+ ###
57
95
  def coverage(local_type = nil, opts = {})
58
96
  local_type ||= opts.key?(:override_type) ? opts[:override_type] : type
59
- uri = URI("#{coverband_url}/api/coverage/#{ENV['COVERBAND_ID']}?type=#{local_type}")
60
- req = Net::HTTP::Get.new(uri, 'Content-Type' => 'application/json', 'Coverband-Token' => ENV['COVERBAND_API_KEY'])
97
+ env_filter = opts.key?(:env_filter) ? opts[:env_filter] : 'production'
98
+ uri = URI("#{coverband_url}/api/coverage?type=#{local_type}&env_filter=#{env_filter}",)
99
+ req = Net::HTTP::Get.new(uri, 'Content-Type' => 'application/json', 'Coverband-Token' => api_key)
61
100
  res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
62
101
  http.request(req)
63
102
  end
64
103
  coverage_data = JSON.parse(res.body)
65
- # puts "coverage data: "
66
- # puts coverage_data
67
104
  coverage_data
68
105
  rescue StandardError => e
69
- puts "Coverband: Error while retrieving coverage #{e}"
106
+ logger&.error "Coverband: Error while retrieving coverage #{e}" if Coverband.configuration.verbose || COVERBAND_ENABLE_DEV_MODE
70
107
  end
71
108
 
72
109
  def save_report(report)
73
- #puts caller.join(',')
74
110
  return if report.empty?
75
111
 
112
+ # We set here vs initialize to avoid setting on the primary process vs child processes
113
+ @pid ||= ::Process.pid
114
+
76
115
  # TODO: do we need dup
77
- # TODO: remove timestamps, server will track first_seen
116
+ # TODO: remove upstream timestamps, server will track first_seen
78
117
  Thread.new do
79
118
  data = expand_report(report.dup)
80
119
  full_package = {
@@ -83,12 +122,18 @@ module Coverband
83
122
  tags: {
84
123
  process_type: process_type,
85
124
  app_loading: type == Coverband::EAGER_TYPE,
86
- runtime_env: runtime_env
125
+ runtime_env: runtime_env,
126
+ pid: pid,
127
+ hostname: hostname,
87
128
  },
88
129
  file_coverage: data
89
130
  }
90
131
  }
132
+
133
+ starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
91
134
  save_coverage(full_package)
135
+ ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
136
+ report_timing((ending - starting))
92
137
  end&.join
93
138
  end
94
139
 
@@ -99,12 +144,18 @@ module Coverband
99
144
  private
100
145
 
101
146
  def save_coverage(data)
147
+ if api_key.nil?
148
+ puts "Coverband: Error: no Coverband API key was found!"
149
+ return
150
+ end
151
+
102
152
  uri = URI("#{coverband_url}/api/collector")
103
153
  req = Net::HTTP::Post.new(uri,
104
154
  'Content-Type' => 'application/json',
105
- 'Coverband-Token' => ENV['COVERBAND_API_KEY'])
106
- # puts "sending #{data}"
155
+ 'Coverband-Token' => api_key)
107
156
  req.body = { remote_uuid: SecureRandom.uuid, data: data }.to_json
157
+
158
+ logger&.info "Coverband: saving (#{uri}) #{req.body}" if Coverband.configuration.verbose
108
159
  res = Net::HTTP.start(
109
160
  uri.hostname,
110
161
  uri.port,
@@ -116,7 +167,51 @@ module Coverband
116
167
  http.request(req)
117
168
  end
118
169
  rescue StandardError => e
119
- puts "Coverband: Error while saving coverage #{e}"
170
+ logger&.info "Coverband: Error while saving coverage #{e}" if Coverband.configuration.verbose || COVERBAND_ENABLE_DEV_MODE
171
+ end
172
+ end
173
+
174
+ class PersistentService < Service
175
+ attr_reader :http, :stats
176
+
177
+ def initialize(coverband_url, opts = {})
178
+ super
179
+ initiate_http
180
+ end
181
+
182
+ private
183
+
184
+ def initiate_http
185
+ @http = Net::HTTP::Persistent.new name: 'coverband_persistent'
186
+ @http.headers['Content-Type'] = 'application/json'
187
+ @http.headers['Coverband-Token'] = api_key
188
+ @http.open_timeout = COVERBAND_TIMEOUT
189
+ @http.read_timeout = COVERBAND_TIMEOUT
190
+ @http.ssl_timeout = COVERBAND_TIMEOUT
191
+ end
192
+
193
+ def save_coverage(data)
194
+ persistent_attempts = 0
195
+ begin
196
+ if api_key.nil?
197
+ puts "Coverband: Error: no Coverband API key was found!"
198
+ return
199
+ end
200
+
201
+ post_uri = URI("#{coverband_url}/api/collector")
202
+ post = Net::HTTP::Post.new post_uri.path
203
+ body = { remote_uuid: SecureRandom.uuid, data: data }.to_json
204
+ post.body = body
205
+ logger&.info "Coverband: saving (#{post_uri}) #{body}" if Coverband.configuration.verbose
206
+ res = http.request post_uri, post
207
+ rescue Net::HTTP::Persistent::Error => e
208
+ persistent_attempts += 1
209
+ http.shutdown
210
+ initiate_http
211
+ retry if persistent_attempts < 2
212
+ end
213
+ rescue StandardError => e
214
+ logger&.info "Coverband: Error while saving coverage #{e}" if Coverband.configuration.verbose || COVERBAND_ENABLE_DEV_MODE
120
215
  end
121
216
  end
122
217
  end
@@ -150,14 +245,22 @@ module Coverband
150
245
  rescue StandardError => e
151
246
  # we don't want to raise errors if Coverband can't reach redis.
152
247
  # This is a nice to have not a bring the system down
153
- logger&.error "Coverband: view_tracker failed to store, error #{e.class.name}"
248
+ logger&.error "Coverband: view_tracker failed to store, error #{e.class.name}" if Coverband.configuration.verbose || COVERBAND_ENABLE_DEV_MODE
154
249
  end
155
250
 
156
251
  private
157
252
 
253
+ def api_key
254
+ ENV['COVERBAND_API_KEY'] || Coverband.configuration.api_key
255
+ end
256
+
257
+ def logger
258
+ Coverband.configuration.logger
259
+ end
260
+
158
261
  def save_tracked_views(views:, reported_time:)
159
262
  uri = URI("#{COVERBAND_SERVICE_URL}/api/collector")
160
- req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json', 'Coverband-Token' => ENV['COVERBAND_API_KEY'])
263
+ req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json', 'Coverband-Token' => api_key)
161
264
  data = {
162
265
  collection_type: 'view_tracker_delta',
163
266
  collection_data: {
@@ -174,25 +277,53 @@ module Coverband
174
277
  http.request(req)
175
278
  end
176
279
  rescue StandardError => e
177
- puts "Coverband: Error while saving coverage #{e}"
280
+ logger&.error "Coverband: Error while saving coverage #{e}" if Coverband.configuration.verbose || COVERBAND_ENABLE_DEV_MODE
178
281
  end
179
282
  end
180
283
  end
181
284
  end
182
285
 
286
+ module Coverband
287
+ class Configuration
288
+ attr_accessor :api_key
289
+ end
290
+ end
291
+
292
+ ENV['COVERBAND_DISABLE_AUTO_START'] = COVERBAND_ORIGINAL_START
183
293
  Coverband.configure do |config|
184
- # Use The Test Service Adapter
185
- config.store = Coverband::Adapters::Service.new(COVERBAND_SERVICE_URL)
294
+ # Use the Service Adapter
295
+ if defined?(Net::HTTP::Persistent)
296
+ config.store = Coverband::Adapters::PersistentService.new(Coverband::COVERBAND_SERVICE_URL)
297
+ else
298
+ config.store = Coverband::Adapters::Service.new(Coverband::COVERBAND_SERVICE_URL)
299
+ end
186
300
 
187
301
  # default to tracking views true
188
- config.track_views = ENV['COVERBAND_DISABLE_VIEW_TRACKER'] ? false : true
302
+ config.track_views = if ENV['COVERBAND_DISABLE_VIEW_TRACKER']
303
+ false
304
+ elsif Coverband.service_disabled_dev_test_env?
305
+ false
306
+ else
307
+ true
308
+ end
189
309
 
190
310
  # report every 10m by default
191
- config.background_reporting_sleep_seconds = COVERBAND_ENV == 'production' ? COVERBAND_REPORT_PERIOD : 60
311
+ config.background_reporting_sleep_seconds = Coverband::COVERBAND_ENV == 'production' ? Coverband::COVERBAND_REPORT_PERIOD : 60
192
312
  # add a wiggle to avoid service stampede
193
- config.reporting_wiggle = COVERBAND_ENV == 'production' ? 90 : 6
313
+ config.reporting_wiggle = Coverband::COVERBAND_ENV == 'production' ? 90 : 6
194
314
 
195
- if COVERBAND_ENV == 'test'
315
+ if Coverband::COVERBAND_ENV == 'test'
196
316
  config.background_reporting_enabled = false
197
317
  end
198
318
  end
319
+
320
+ # NOTE: it is really hard to bypass / overload our config we should fix this in Coverband
321
+ # this hopefully detects anyone that has both gems and was trying to configure Coverband themselves.
322
+ if File.exist?('./config/coverband.rb')
323
+ puts "Warning: config/coverband.rb found, this overrides coverband service allowing one to setup open source Coverband" if Coverband.configuration.verbose || COVERBAND_ENABLE_DEV_MODE
324
+ end
325
+
326
+ Coverband.configure('./config/coverband_service.rb') if File.exist?('./config/coverband_service.rb')
327
+ Coverband.start
328
+ require "coverband/utils/railtie" if defined? ::Rails::Railtie
329
+ require "coverband/integrations/resque" if defined? ::Resque
@@ -1,7 +1,7 @@
1
1
  module Coverband
2
2
  module Service
3
3
  module Client
4
- VERSION = '0.0.8'
4
+ VERSION = '0.0.12.rc.1'
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coverband-service-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.12.rc.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Mayer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-05-02 00:00:00.000000000 Z
12
+ date: 2020-06-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -106,9 +106,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
106
106
  version: '0'
107
107
  required_rubygems_version: !ruby/object:Gem::Requirement
108
108
  requirements:
109
- - - ">="
109
+ - - ">"
110
110
  - !ruby/object:Gem::Version
111
- version: '0'
111
+ version: 1.3.1
112
112
  requirements: []
113
113
  rubygems_version: 3.0.3
114
114
  signing_key: