collective-metrics 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Collectfile +3 -1
- data/Gemfile +12 -1
- data/lib/collective/collectors/trackjs.rb +112 -0
- data/lib/collective/version.rb +1 -1
- data/lib/collective.rb +1 -0
- data/spec/lib/collective/collectors/trackjs_spec.rb +342 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/trackjs_helpers.rb +65 -0
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 867d160cc98d20a4135bd89a7e20818ca0a59523
|
4
|
+
data.tar.gz: 14a2dee02b5a23b46e485d3734fbdf8f09b5bf9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d95c2229f1ee18d673702c209ff9a508e0e4f32f20f0c4060c7f69f7b0625b02650a9f2617aaccce8097bf7bad46cf2d893dafaf74c010592bc9ef39c78c24a1
|
7
|
+
data.tar.gz: 505be1fbd644e0a3580bbec41c9218bb7a53ce8f817d8c3fd2fd837ac5403c2cf96385e23f3ed9147439d39e7260ba3a0124ff7d0ab2b10d4d9e75f43a6f5f54
|
data/Collectfile
CHANGED
@@ -4,4 +4,6 @@ use Collective::Collectors::Memcached
|
|
4
4
|
unless ENV['NEWRELIC_API_KEY'].nil? || ENV['NEWRELIC_API_KEY'].empty?
|
5
5
|
use Collective::Collectors::Newrelic, api_key: ENV['NEWRELIC_API_KEY'], filter: ENV['NEWRELIC_APPLICATION_FILTER']
|
6
6
|
end
|
7
|
-
|
7
|
+
unless ENV['TRACKJS_API_KEY'].nil? || ENV['TRACKJS_API_KEY'].empty?
|
8
|
+
use Collective::Collectors::TrackJS, api_key: ENV['TRACKJS_API_KEY'], customer_id: ENV['TRACKJS_CUSTOMER_ID']
|
9
|
+
end
|
data/Gemfile
CHANGED
@@ -6,6 +6,17 @@ gemspec
|
|
6
6
|
group :development do
|
7
7
|
gem 'dalli'
|
8
8
|
gem 'sidekiq'
|
9
|
-
gem 'mongoid',
|
9
|
+
gem 'mongoid', '~> 3.0'
|
10
10
|
gem 'pg'
|
11
11
|
end
|
12
|
+
|
13
|
+
group :development, :test do
|
14
|
+
gem 'rspec', '~> 3.4.0'
|
15
|
+
gem 'dotenv', '~> 2.1.1'
|
16
|
+
gem 'faker'
|
17
|
+
gem 'activesupport'
|
18
|
+
end
|
19
|
+
|
20
|
+
group :test do
|
21
|
+
gem 'webmock'
|
22
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Collective::Collectors
|
2
|
+
class TrackJS < Collective::Collector
|
3
|
+
requires :faraday
|
4
|
+
requires :faraday_middleware
|
5
|
+
requires :json
|
6
|
+
@@frequency = 60 # seconds
|
7
|
+
|
8
|
+
resolution @@frequency.to_s + 's'
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@last_seen_id = options[:last_seen_id] || {}
|
12
|
+
super(options)
|
13
|
+
end
|
14
|
+
|
15
|
+
collect do
|
16
|
+
options[:applications].each do |application|
|
17
|
+
instrument_errors application
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def instrument_errors(application)
|
24
|
+
count = 0
|
25
|
+
paged("/#{customer_id}/v1/errors", {application: application}).each do |error|
|
26
|
+
count += 1
|
27
|
+
end
|
28
|
+
instrument 'trackjs.url.errors', count, source: application, type: 'count'
|
29
|
+
end
|
30
|
+
|
31
|
+
# This function goes through a paged list of errors and yields each
|
32
|
+
# individual error.
|
33
|
+
#
|
34
|
+
# The most basic endpoint in the TrackJS API returns all the errors that
|
35
|
+
# have been detected from the beginning of time to the current date. This
|
36
|
+
# endpoint can return the number of errors seen in the last day, but since
|
37
|
+
# we're just trying to determine the number of errors that occurred in the
|
38
|
+
# last 60s, we use the default endpoint options.
|
39
|
+
#
|
40
|
+
# To avoid fetching all the errors, only the ones we haven't seen since
|
41
|
+
# the last time we checked, so we keep track of the id of the last error
|
42
|
+
# we saw and page through the error list until either:
|
43
|
+
#
|
44
|
+
# 1. We see an error we've already returned
|
45
|
+
# 2. We hit an errors that's more than 60s old (to avoid scanning the entire list of
|
46
|
+
# errors the first time the collector is run)
|
47
|
+
# 3. We hit the very end of the error list
|
48
|
+
#
|
49
|
+
def paged(path, params={})
|
50
|
+
Enumerator.new do |yielder|
|
51
|
+
current_error_time = Time.now.utc
|
52
|
+
oldest_error = current_error_time - @@frequency
|
53
|
+
page = 1
|
54
|
+
page_size = 250
|
55
|
+
current_initial_id = nil
|
56
|
+
get_another_page = true # set to true until an error id that has already been seen is hit
|
57
|
+
application = params[:application]
|
58
|
+
|
59
|
+
resp = get_page(path, params, page, page_size)
|
60
|
+
data = resp.body['data']
|
61
|
+
|
62
|
+
if data.length > 0
|
63
|
+
current_initial_id = data[0]['id']
|
64
|
+
|
65
|
+
while current_error_time > oldest_error do
|
66
|
+
resp.body['data'].each do |error|
|
67
|
+
current_error_time = Time.parse(error['timestamp'])
|
68
|
+
if (error['id'] == @last_seen_id[application]) || (current_error_time <= oldest_error)
|
69
|
+
get_another_page = false
|
70
|
+
break
|
71
|
+
else
|
72
|
+
yielder.yield error
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
break if !get_another_page or !resp.body['metadata']['hasMore']
|
77
|
+
|
78
|
+
page += 1
|
79
|
+
resp = get_page(path, params, page, page_size)
|
80
|
+
end
|
81
|
+
|
82
|
+
@last_seen_id[application] = current_initial_id
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_page(path, params, page, page_size = 500)
|
88
|
+
client.get(path, params.merge(page: page, size: page_size)) do |req|
|
89
|
+
req.headers['Authorization'] = api_key
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def client
|
94
|
+
@client ||= Faraday.new(api_url) do |builder|
|
95
|
+
builder.response :json, content_type: /\bjson$/
|
96
|
+
builder.adapter Faraday.default_adapter
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def api_url
|
101
|
+
"https://api.trackjs.com"
|
102
|
+
end
|
103
|
+
|
104
|
+
def customer_id
|
105
|
+
options[:customer_id]
|
106
|
+
end
|
107
|
+
|
108
|
+
def api_key
|
109
|
+
options[:api_key]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/lib/collective/version.rb
CHANGED
data/lib/collective.rb
CHANGED
@@ -17,6 +17,7 @@ module Collective
|
|
17
17
|
autoload :Newrelic, 'collective/collectors/newrelic'
|
18
18
|
autoload :PGBouncer, 'collective/collectors/pgbouncer'
|
19
19
|
autoload :Postgres, 'collective/collectors/postgres'
|
20
|
+
autoload :TrackJS, 'collective/collectors/trackjs'
|
20
21
|
end
|
21
22
|
|
22
23
|
class << self
|
@@ -0,0 +1,342 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'collective'
|
3
|
+
require 'active_support/core_ext/numeric/time'
|
4
|
+
|
5
|
+
describe Collective::Collectors::TrackJS do
|
6
|
+
let(:env_api_key) { ENV["TRACKJS_API_KEY"] }
|
7
|
+
let(:env_customer_id) { ENV["TRACKJS_CUSTOMER_ID"] }
|
8
|
+
let(:page_size) { 250 }
|
9
|
+
let(:page) { 1 }
|
10
|
+
let(:no_errors) { 0 }
|
11
|
+
let(:empty_response) { trackjs_response errors: no_errors, total_errors: no_errors, page: page, page_size: page_size }
|
12
|
+
|
13
|
+
before do
|
14
|
+
@collector = Collective::Collectors::TrackJS.new(
|
15
|
+
:api_key => env_api_key,
|
16
|
+
:customer_id => env_customer_id
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when no errors are returned' do
|
21
|
+
let(:errors) { 0 }
|
22
|
+
let(:response) { trackjs_response errors: errors, total_errors: errors, page: page, page_size: page_size }
|
23
|
+
|
24
|
+
it 'logs an error count of 0' do
|
25
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
26
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
27
|
+
.to_return(
|
28
|
+
:body => response.to_json,
|
29
|
+
:status => 200,
|
30
|
+
:headers => {'Content-Type' => 'application/json'}
|
31
|
+
)
|
32
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
33
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
34
|
+
.to_return(
|
35
|
+
:body => response.to_json,
|
36
|
+
:status => 200,
|
37
|
+
:headers => {'Content-Type' => 'application/json'}
|
38
|
+
)
|
39
|
+
|
40
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', 0, hash_including(:source => "r101-frontend"))
|
41
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', 0, hash_including(:source => "r101-marketing"))
|
42
|
+
@collector.collect
|
43
|
+
expect(
|
44
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
45
|
+
).to have_been_made
|
46
|
+
expect(
|
47
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
48
|
+
).to have_been_made
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when less than a page of errors are returned' do
|
53
|
+
let(:error_count) { 45 }
|
54
|
+
let(:metadata) { trackjs_metadata total_count: error_count, page: page, page_size: page_size, has_more: false }
|
55
|
+
let(:response) { trackjs_response errors: error_count, total_errors: error_count, page: page, page_size: page_size }
|
56
|
+
|
57
|
+
context 'when none of the errors have been logged before' do
|
58
|
+
context 'all the errors are within the last @frequency seconds' do
|
59
|
+
it 'logs all the errors returned' do
|
60
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
61
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
62
|
+
.to_return(
|
63
|
+
:body => response.to_json,
|
64
|
+
:status => 200,
|
65
|
+
:headers => {'Content-Type' => 'application/json'}
|
66
|
+
)
|
67
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
68
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
69
|
+
.to_return(
|
70
|
+
:body => empty_response.to_json,
|
71
|
+
:status => 200,
|
72
|
+
:headers => {'Content-Type' => 'application/json'}
|
73
|
+
)
|
74
|
+
|
75
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', error_count, hash_including(:source => "r101-frontend"))
|
76
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', 0, hash_including(:source => "r101-marketing"))
|
77
|
+
@collector.collect
|
78
|
+
expect(
|
79
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
80
|
+
).to have_been_made
|
81
|
+
expect(
|
82
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
83
|
+
).to have_been_made
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'not all the errors are within the last @frequency seconds' do
|
88
|
+
let(:old_error_count) { 7 }
|
89
|
+
let(:old_timestamps) { old_error_count.times.map { 3.hours.ago.utc.strftime("%FT%T%:z") } }
|
90
|
+
let(:old_errors) { old_error_count.times.map { |i| trackjs_error({timestamp: old_timestamps[i]}) } }
|
91
|
+
let(:errors) { (error_count - old_error_count).times.map { trackjs_error} + old_errors }
|
92
|
+
let(:response) { { "data" => errors, "metadata" => metadata } }
|
93
|
+
|
94
|
+
it 'logs only the errors in the last @frequency s' do
|
95
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
96
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
97
|
+
.to_return(
|
98
|
+
:body => response.to_json,
|
99
|
+
:status => 200,
|
100
|
+
:headers => {'Content-Type' => 'application/json'}
|
101
|
+
)
|
102
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
103
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
104
|
+
.to_return(
|
105
|
+
:body => empty_response.to_json,
|
106
|
+
:status => 200,
|
107
|
+
:headers => {'Content-Type' => 'application/json'}
|
108
|
+
)
|
109
|
+
|
110
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', error_count - old_error_count, hash_including(:source => "r101-frontend"))
|
111
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', 0, hash_including(:source => "r101-marketing"))
|
112
|
+
@collector.collect
|
113
|
+
expect(
|
114
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
115
|
+
).to have_been_made
|
116
|
+
expect(
|
117
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
118
|
+
).to have_been_made
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'none of the errors are within the last @frequency seconds' do
|
123
|
+
let(:old_timestamps) { error_count.times.map { 3.hours.ago.utc.strftime("%FT%T%:z") } }
|
124
|
+
let(:errors) { error_count.times.map { |i| trackjs_error({timestamp: old_timestamps[i]}) } }
|
125
|
+
let(:response) { { "data" => errors, "metadata" => metadata } }
|
126
|
+
|
127
|
+
it 'logs 0 errors' do
|
128
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
129
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
130
|
+
.to_return(
|
131
|
+
:body => response.to_json,
|
132
|
+
:status => 200,
|
133
|
+
:headers => {'Content-Type' => 'application/json'}
|
134
|
+
)
|
135
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
136
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
137
|
+
.to_return(
|
138
|
+
:body => empty_response.to_json,
|
139
|
+
:status => 200,
|
140
|
+
:headers => {'Content-Type' => 'application/json'}
|
141
|
+
)
|
142
|
+
|
143
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', 0, hash_including(:source => "r101-frontend"))
|
144
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', 0, hash_including(:source => "r101-marketing"))
|
145
|
+
@collector.collect
|
146
|
+
expect(
|
147
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
148
|
+
).to have_been_made
|
149
|
+
expect(
|
150
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
151
|
+
).to have_been_made
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'some of the errors have been logged before' do
|
157
|
+
let(:old_error_count) { 5 }
|
158
|
+
let(:new_error_count) { 3 }
|
159
|
+
let(:old_errors) { old_error_count.times.map { trackjs_error } }
|
160
|
+
let(:new_errors) { new_error_count.times.map { trackjs_error } }
|
161
|
+
let(:all_errors) { new_errors + old_errors }
|
162
|
+
let(:old_metadata) { trackjs_metadata total_count: old_error_count, page: page, page_size: page_size, has_more: false }
|
163
|
+
let(:new_metadata) { trackjs_metadata total_count: (old_error_count + new_error_count), page: page, page_size: page_size, has_more: false }
|
164
|
+
let(:old_response) { {"data" => old_errors, "metadata" => old_metadata} }
|
165
|
+
let(:new_response) { {"data" => all_errors, "metadata" => new_metadata} }
|
166
|
+
|
167
|
+
before do
|
168
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
169
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
170
|
+
.to_return(
|
171
|
+
:body => empty_response.to_json,
|
172
|
+
:status => 200,
|
173
|
+
:headers => {'Content-Type' => 'application/json'}
|
174
|
+
)
|
175
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
176
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
177
|
+
.to_return(
|
178
|
+
:body => old_response.to_json,
|
179
|
+
:status => 200,
|
180
|
+
:headers => {'Content-Type' => 'application/json'}
|
181
|
+
)
|
182
|
+
|
183
|
+
@collector.collect
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'logs only the errors that have occurred since the last time logging happened' do
|
187
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
188
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
189
|
+
.to_return(
|
190
|
+
:body => empty_response.to_json,
|
191
|
+
:status => 200,
|
192
|
+
:headers => {'Content-Type' => 'application/json'}
|
193
|
+
)
|
194
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
195
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
196
|
+
.to_return(
|
197
|
+
:body => new_response.to_json,
|
198
|
+
:status => 200,
|
199
|
+
:headers => {'Content-Type' => 'application/json'}
|
200
|
+
)
|
201
|
+
|
202
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', 0, hash_including(:source => "r101-frontend"))
|
203
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', new_errors.length, hash_including(:source => "r101-marketing"))
|
204
|
+
@collector.collect
|
205
|
+
expect(
|
206
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
207
|
+
).to have_been_made.times(2)
|
208
|
+
expect(
|
209
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
210
|
+
).to have_been_made.times(2)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context 'when multiple pages of errors are returned' do
|
216
|
+
let(:old_error_count) { 250 }
|
217
|
+
let(:new_error_count) { 50 }
|
218
|
+
let(:total_errors) { 800 }
|
219
|
+
let(:page2) { 2 }
|
220
|
+
|
221
|
+
context 'none of the errors have been logged before' do
|
222
|
+
let(:recent_timestamps) { old_error_count.times.map { Time.now.utc.strftime("%FT%T%:z") } }
|
223
|
+
let(:old_timestamps) { new_error_count.times.map { 3.hours.ago.utc.strftime("%FT%T%:z") } }
|
224
|
+
let(:combined_timestamps) { recent_timestamps.slice(0, old_error_count - new_error_count) + old_timestamps }
|
225
|
+
let(:response) { trackjs_response errors: old_error_count, timestamps: recent_timestamps, total_errors: total_errors, page: page, page_size: page_size }
|
226
|
+
let(:response2) { trackjs_response errors: old_error_count, timestamps: combined_timestamps, total_errors: total_errors, page: page2, page_size: page_size }
|
227
|
+
|
228
|
+
it 'logs only the errors that occurred in the last @frequency seconds' do
|
229
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
230
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
231
|
+
.to_return(
|
232
|
+
:body => response.to_json,
|
233
|
+
:status => 200,
|
234
|
+
:headers => {'Content-Type' => 'application/json'}
|
235
|
+
)
|
236
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
237
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
238
|
+
.to_return(
|
239
|
+
:body => empty_response.to_json,
|
240
|
+
:status => 200,
|
241
|
+
:headers => {'Content-Type' => 'application/json'}
|
242
|
+
)
|
243
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
244
|
+
.with(:query => {"page" => page2, "size" => page_size, "application" => "r101-frontend"})
|
245
|
+
.to_return(
|
246
|
+
:body => response2.to_json,
|
247
|
+
:status => 200,
|
248
|
+
:headers => {'Content-Type' => 'application/json'}
|
249
|
+
)
|
250
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
251
|
+
.with(:query => {"page" => page2, "size" => page_size, "application" => "r101-marketing"})
|
252
|
+
.to_return(
|
253
|
+
:body => empty_response.to_json,
|
254
|
+
:status => 200,
|
255
|
+
:headers => {'Content-Type' => 'application/json'}
|
256
|
+
)
|
257
|
+
|
258
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', 2 * page_size - old_timestamps.length, hash_including(:source => "r101-frontend"))
|
259
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', 0, hash_including(:source => "r101-marketing"))
|
260
|
+
@collector.collect
|
261
|
+
expect(
|
262
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
263
|
+
).to have_been_made.times(1)
|
264
|
+
expect(
|
265
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
266
|
+
).to have_been_made.times(1)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
context 'some of the errors have been logged before' do
|
271
|
+
let(:page1_errors) { old_error_count.times.map { trackjs_error } }
|
272
|
+
let(:old_timestamps) { new_error_count.times.map { 3.hours.ago.utc.strftime("%FT%T%:z") } }
|
273
|
+
let(:out_of_date_errors) { new_error_count.times.map { |i| trackjs_error({timestamp: old_timestamps[i]}) } }
|
274
|
+
let(:page2_errors) { ((old_error_count - new_error_count).times.map { trackjs_error }) + out_of_date_errors }
|
275
|
+
let(:new_errors) { new_error_count.times.map { trackjs_error } }
|
276
|
+
let(:combined_errors) { (new_errors + page1_errors).first page_size }
|
277
|
+
let(:old_metadata) { trackjs_metadata total_count: old_error_count, page: page, page_size: page_size, has_more: true }
|
278
|
+
let(:combined_metadata) { trackjs_metadata total_count: (old_error_count + new_error_count), page: page2, page_size: page_size, has_more: true }
|
279
|
+
let(:old_page1_response) { { "data" => page1_errors, "metadata" => old_metadata } }
|
280
|
+
let(:old_page2_response) { { "data" => page2_errors, "metadata" => old_metadata } }
|
281
|
+
let(:combined_response) { { "data" => combined_errors, "metadata" => combined_metadata } }
|
282
|
+
|
283
|
+
before do
|
284
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
285
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
286
|
+
.to_return(
|
287
|
+
:body => old_page1_response.to_json,
|
288
|
+
:status => 200,
|
289
|
+
:headers => {'Content-Type' => 'application/json'}
|
290
|
+
)
|
291
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
292
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
293
|
+
.to_return(
|
294
|
+
:body => empty_response.to_json,
|
295
|
+
:status => 200,
|
296
|
+
:headers => {'Content-Type' => 'application/json'}
|
297
|
+
)
|
298
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
299
|
+
.with(:query => {"page" => page2, "size" => page_size, "application" => "r101-frontend"})
|
300
|
+
.to_return(
|
301
|
+
:body => old_page2_response.to_json,
|
302
|
+
:status => 200,
|
303
|
+
:headers => {'Content-Type' => 'application/json'}
|
304
|
+
)
|
305
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
306
|
+
.with(:query => {"page" => page2, "size" => page_size, "application" => "r101-marketing"})
|
307
|
+
.to_return(
|
308
|
+
:body => empty_response.to_json,
|
309
|
+
:status => 200,
|
310
|
+
:headers => {'Content-Type' => 'application/json'}
|
311
|
+
)
|
312
|
+
@collector.collect
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'logs only the errors that have occurred since the last time logging happened' do
|
316
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
317
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
318
|
+
.to_return(
|
319
|
+
:body => combined_response.to_json,
|
320
|
+
:status => 200,
|
321
|
+
:headers => {'Content-Type' => 'application/json'}
|
322
|
+
)
|
323
|
+
stub_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors")
|
324
|
+
.with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
325
|
+
.to_return(
|
326
|
+
:body => empty_response.to_json,
|
327
|
+
:status => 200,
|
328
|
+
:headers => {'Content-Type' => 'application/json'}
|
329
|
+
)
|
330
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', new_errors.length, hash_including(:source => "r101-frontend"))
|
331
|
+
expect(Metrics).to receive(:instrument).with('trackjs.url.errors', 0, hash_including(:source => "r101-marketing"))
|
332
|
+
@collector.collect
|
333
|
+
expect(
|
334
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-frontend"})
|
335
|
+
).to have_been_made.times(2)
|
336
|
+
expect(
|
337
|
+
a_request(:get, "https://api.trackjs.com/#{env_customer_id}/v1/errors").with(:query => {"page" => page, "size" => page_size, "application" => "r101-marketing"})
|
338
|
+
).to have_been_made.times(2)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'webmock/rspec'
|
2
|
+
|
3
|
+
require 'dotenv'
|
4
|
+
Dotenv.load('.env.test')
|
5
|
+
|
6
|
+
|
7
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
8
|
+
# in spec/support/ and its subdirectories.
|
9
|
+
Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each {|f| require f}
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.mock_with :rspec
|
13
|
+
|
14
|
+
config.raise_errors_for_deprecations!
|
15
|
+
|
16
|
+
# Allow RSpec to run focused specs
|
17
|
+
config.filter_run_including focus: true
|
18
|
+
config.filter_run_excluding broken: true
|
19
|
+
config.filter_run_excluding :bollocksed
|
20
|
+
config.run_all_when_everything_filtered = true
|
21
|
+
config.fail_fast = false
|
22
|
+
config.before focus: true do
|
23
|
+
fail "Hey dummy, don't commit focused specs." if ENV['CI']
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'faker'
|
3
|
+
|
4
|
+
module TrackJSHelpers
|
5
|
+
def trackjs_error(
|
6
|
+
message: nil,
|
7
|
+
timestamp: Time.now.utc.strftime("%FT%T%:z"),
|
8
|
+
url: "https://www.remind.com",
|
9
|
+
application: "r101-frontend",
|
10
|
+
id: SecureRandom.uuid
|
11
|
+
)
|
12
|
+
trackjs_url = "https://my.trackjs.com/details/#{id}"
|
13
|
+
message = message || Faker::Lorem.sentence
|
14
|
+
|
15
|
+
return {
|
16
|
+
"message" => message,
|
17
|
+
"timestamp" => timestamp,
|
18
|
+
"url" => url,
|
19
|
+
"id" => id,
|
20
|
+
"browserName" => "Chrome",
|
21
|
+
"browserVersion" => "49.0.2623",
|
22
|
+
"entry" => "window",
|
23
|
+
"application" => application,
|
24
|
+
"line" => 11,
|
25
|
+
"column" => 13161,
|
26
|
+
"file" => "https://www.remind.com/classes/sci02",
|
27
|
+
"userId" => "11111111",
|
28
|
+
"sessionId" => "",
|
29
|
+
"trackJsUrl" => trackjs_url,
|
30
|
+
"isStarred" => false
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def trackjs_metadata(total_count: 0, page: 1, page_size: 250, has_more: true)
|
35
|
+
return {
|
36
|
+
"totalCount" => total_count,
|
37
|
+
"page" => page,
|
38
|
+
"size" => page_size,
|
39
|
+
"hasMore" => has_more,
|
40
|
+
"trackJsUrl" => "https://my.trackjs.com/recent?"
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def trackjs_response(errors: 0, timestamps: nil, total_errors: 0, page: 1, page_size: 250)
|
45
|
+
timestamps = timestamps || errors.times.map { Time.now.utc.strftime("%FT%T%:z") }
|
46
|
+
data = errors.times.map do |i|
|
47
|
+
trackjs_error(timestamp: timestamps[i])
|
48
|
+
end
|
49
|
+
has_more = (page * page_size) < total_errors
|
50
|
+
|
51
|
+
return {
|
52
|
+
"data" => data,
|
53
|
+
"metadata" => trackjs_metadata(
|
54
|
+
total_count: total_errors,
|
55
|
+
page: page,
|
56
|
+
page_size: page_size,
|
57
|
+
has_more: has_more
|
58
|
+
)
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
RSpec.configure do |config|
|
64
|
+
config.include TrackJSHelpers
|
65
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: collective-metrics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric J. Holmes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rufus-scheduler
|
@@ -159,7 +159,11 @@ files:
|
|
159
159
|
- lib/collective/collectors/rabbitmq.rb
|
160
160
|
- lib/collective/collectors/redis.rb
|
161
161
|
- lib/collective/collectors/sidekiq.rb
|
162
|
+
- lib/collective/collectors/trackjs.rb
|
162
163
|
- lib/collective/version.rb
|
164
|
+
- spec/lib/collective/collectors/trackjs_spec.rb
|
165
|
+
- spec/spec_helper.rb
|
166
|
+
- spec/support/trackjs_helpers.rb
|
163
167
|
homepage: https://github.com/remind101/collective-metrics
|
164
168
|
licenses:
|
165
169
|
- MIT
|
@@ -180,8 +184,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
180
184
|
version: '0'
|
181
185
|
requirements: []
|
182
186
|
rubyforge_project:
|
183
|
-
rubygems_version: 2.4.
|
187
|
+
rubygems_version: 2.4.8
|
184
188
|
signing_key:
|
185
189
|
specification_version: 4
|
186
190
|
summary: Collect and output metrics
|
187
|
-
test_files:
|
191
|
+
test_files:
|
192
|
+
- spec/lib/collective/collectors/trackjs_spec.rb
|
193
|
+
- spec/spec_helper.rb
|
194
|
+
- spec/support/trackjs_helpers.rb
|