turnstile-rb 2.0.1 → 3.0.2

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.
Files changed (59) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -0
  3. data/.travis.yml +2 -2
  4. data/LICENSE.txt +2 -1
  5. data/README.md +200 -11
  6. data/Rakefile +1 -0
  7. data/bin/turnstile +4 -6
  8. data/example/custom_csv_matcher.rb +22 -0
  9. data/lib/turnstile.rb +37 -8
  10. data/lib/turnstile/cli/launcher.rb +83 -0
  11. data/lib/turnstile/cli/parser.rb +166 -0
  12. data/lib/turnstile/cli/runner.rb +58 -0
  13. data/lib/turnstile/collector.rb +2 -2
  14. data/lib/turnstile/collector/actor.rb +81 -0
  15. data/lib/turnstile/collector/controller.rb +121 -0
  16. data/lib/turnstile/collector/flusher.rb +36 -0
  17. data/lib/turnstile/collector/formats.rb +7 -34
  18. data/lib/turnstile/collector/formats/custom_matcher.rb +19 -0
  19. data/lib/turnstile/collector/formats/delimited_matcher.rb +30 -0
  20. data/lib/turnstile/collector/formats/json_matcher.rb +30 -0
  21. data/lib/turnstile/collector/log_reader.rb +84 -46
  22. data/lib/turnstile/collector/{matcher.rb → regexp_matcher.rb} +4 -5
  23. data/lib/turnstile/collector/session.rb +7 -0
  24. data/lib/turnstile/commands.rb +20 -0
  25. data/lib/turnstile/commands/base.rb +20 -0
  26. data/lib/turnstile/commands/flushdb.rb +21 -0
  27. data/lib/turnstile/commands/print_keys.rb +19 -0
  28. data/lib/turnstile/commands/show.rb +89 -0
  29. data/lib/turnstile/configuration.rb +23 -0
  30. data/lib/turnstile/dependencies.rb +31 -0
  31. data/lib/turnstile/logger.rb +9 -40
  32. data/lib/turnstile/logger/helper.rb +42 -0
  33. data/lib/turnstile/logger/provider.rb +74 -0
  34. data/lib/turnstile/observer.rb +5 -9
  35. data/lib/turnstile/redis/adapter.rb +97 -0
  36. data/lib/turnstile/redis/connection.rb +116 -0
  37. data/lib/turnstile/redis/spy.rb +42 -0
  38. data/lib/turnstile/sampler.rb +9 -2
  39. data/lib/turnstile/tracker.rb +14 -14
  40. data/lib/turnstile/version.rb +51 -12
  41. data/lib/turnstile/web_app.rb +29 -0
  42. data/spec/spec_helper.rb +18 -3
  43. data/spec/support/logging.rb +17 -0
  44. data/spec/turnstile/adapter_spec.rb +59 -46
  45. data/spec/turnstile/collector/flusher_spec.rb +16 -0
  46. data/spec/turnstile/collector/log_reader_spec.rb +127 -77
  47. data/spec/turnstile/commands/show_spec.rb +40 -0
  48. data/spec/turnstile/tracker_spec.rb +21 -7
  49. data/spec/turnstile_spec.rb +3 -0
  50. data/turnstile-rb.gemspec +5 -2
  51. metadata +89 -22
  52. data/Gemfile +0 -6
  53. data/lib/turnstile/adapter.rb +0 -61
  54. data/lib/turnstile/collector/runner.rb +0 -72
  55. data/lib/turnstile/collector/updater.rb +0 -86
  56. data/lib/turnstile/parser.rb +0 -107
  57. data/lib/turnstile/runner.rb +0 -54
  58. data/lib/turnstile/summary.rb +0 -57
  59. data/spec/turnstile/summary_spec.rb +0 -41
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'turnstile/commands/show'
3
+
4
+ EXPECTED_NAD_RESPONSE = <<-EOF
5
+ turnstile:android#{"\t"}n#{"\t"}3
6
+ turnstile:ios#{"\t"}n#{"\t"}2
7
+ turnstile:total#{"\t"}n#{"\t"}5
8
+ EOF
9
+ .strip
10
+
11
+ module Turnstile
12
+ module Commands
13
+ RSpec.describe Show do
14
+ let(:options) { { summary: true }}
15
+ subject { described_class.new(options) }
16
+
17
+ let(:aggregate) {
18
+ {
19
+ 'android' => 3,
20
+ 'ios' => 2,
21
+ 'total' => 5
22
+ }
23
+ }
24
+
25
+ describe '#execute' do
26
+ it 'return data in NAD format' do
27
+ expect(subject.nad(aggregate)).to eql(EXPECTED_NAD_RESPONSE)
28
+ end
29
+ end
30
+
31
+ describe '#json' do
32
+ let(:json) { subject.json(aggregate) }
33
+ let(:hash) { JSON.load(json) }
34
+ it 'return data in JSON format' do
35
+ expect(hash).to eql(aggregate)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Turnstile::Tracker do
4
4
 
5
- subject { Turnstile::Tracker.new }
5
+ subject(:tracker) { Turnstile::Tracker.new }
6
6
 
7
7
  let(:adapter) { subject.send(:adapter) }
8
8
 
@@ -10,16 +10,30 @@ describe Turnstile::Tracker do
10
10
  let(:platform) { :ios }
11
11
  let(:ip) { '1.2.3.4' }
12
12
 
13
- describe "#track" do
14
- it "calls adapter with correct parameters" do
13
+ describe '#track_and_sample' do
14
+ it 'calls adapter with correct parameters' do
15
15
  expect(adapter).to receive(:add).once.with(uid, platform, ip)
16
- subject.track(uid, platform, ip)
16
+ subject.track_and_sample(uid, platform, ip)
17
17
  end
18
18
 
19
- it "does not track if sampler returns no" do
20
- allow_any_instance_of(Turnstile::Sampler).to receive(:sample).and_return false
19
+ it 'does not track if sampler returns no' do
20
+ allow(tracker).to receive(:should_track?).and_return false
21
21
  expect(adapter).to receive(:add).never
22
- subject.track(uid)
22
+ subject.track_and_sample(uid)
23
+ end
24
+ end
25
+
26
+ describe '#track_token' do
27
+ it 'calls adapter with correct parameters' do
28
+ expect(adapter).to receive(:add).once.with(uid.to_s, platform.to_s, ip)
29
+ subject.track_token("#{platform}:#{ip}:#{uid}")
30
+ end
31
+ end
32
+
33
+ describe '#track_all' do
34
+ it 'does not track if sampler returns no' do
35
+ expect(adapter).to receive(:add).once
36
+ subject.track_all(uid)
23
37
  end
24
38
  end
25
39
  end
@@ -4,6 +4,7 @@ describe Turnstile do
4
4
 
5
5
  let(:tracker) { Turnstile::Tracker.new }
6
6
  let(:observer) { Turnstile::Observer.new }
7
+ let(:adapter) { tracker.adapter }
7
8
 
8
9
  let(:uid_1) { 1238438 }
9
10
  let(:uid_2) { 1238439 }
@@ -21,6 +22,8 @@ describe Turnstile do
21
22
  let(:other_ip) { '4.3.2.1' }
22
23
 
23
24
  describe 'general tests' do
25
+ before { adapter.flushdb }
26
+
24
27
  let(:expected_stats) do
25
28
  {
26
29
  stats: {
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.homepage = 'https://github.com/kigster/turnstile-rb'
17
17
  spec.license = 'MIT'
18
18
 
19
- spec.files = `git ls-files`.split($/)
19
+ spec.files = `git ls-files`.split($/).reject {|f| f =~ /Gemfile/ }
20
20
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
21
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
22
  spec.require_paths = ['lib']
@@ -24,13 +24,16 @@ Gem::Specification.new do |spec|
24
24
  spec.add_dependency 'redis'
25
25
  spec.add_dependency 'file-tail'
26
26
  spec.add_dependency 'daemons'
27
- spec.add_dependency 'json'
28
27
  spec.add_dependency 'hashie'
29
28
  spec.add_dependency 'colored2'
29
+ spec.add_dependency 'connection_pool'
30
+ spec.add_dependency 'activesupport'
31
+ spec.add_dependency 'sinatra'
30
32
 
31
33
  spec.add_development_dependency 'bundler'
32
34
  spec.add_development_dependency 'rake'
33
35
  spec.add_development_dependency 'yard'
36
+ spec.add_development_dependency 'irbtools'
34
37
 
35
38
  spec.add_development_dependency 'rspec'
36
39
  spec.add_development_dependency 'rspec-its'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turnstile-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-04 00:00:00.000000000 Z
11
+ date: 2018-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: json
56
+ name: hashie
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: hashie
70
+ name: colored2
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,35 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: colored2
84
+ name: connection_pool
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: activesupport
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: sinatra
85
113
  requirement: !ruby/object:Gem::Requirement
86
114
  requirements:
87
115
  - - ">="
@@ -136,6 +164,20 @@ dependencies:
136
164
  - - ">="
137
165
  - !ruby/object:Gem::Version
138
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: irbtools
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
139
181
  - !ruby/object:Gem::Dependency
140
182
  name: rspec
141
183
  requirement: !ruby/object:Gem::Requirement
@@ -178,12 +220,15 @@ dependencies:
178
220
  - - ">="
179
221
  - !ruby/object:Gem::Version
180
222
  version: '0'
181
- description: |2
182
- Turnstile is a Redis-based library that can accurately track total number of concurrent
183
- users accessing a web/API based server application. It can break it down by "platform"
184
- or a device type, and returns data in JSON, CSV of NAD formats. While user tracking
185
- may happen synchronously using a Rack middleware, another method is provided that is
186
- based on log file analysis, and can therefore be performed outside web server process.
223
+ description: |+
224
+ Turnstile is a Redis-based library that can accurately track total number
225
+ of concurrent users accessing a web/API based server application. It can
226
+ break it down by "platform" or a device type, and returns data in JSON,
227
+ CSV of NAD formats. While user tracking may happen synchronously using a
228
+ Rack middleware, another method is provided that is based on log file
229
+ analysis, and can therefore be performed outside web server process.
230
+
231
+
187
232
  email:
188
233
  - kigster@gmail.com
189
234
  executables:
@@ -194,37 +239,56 @@ files:
194
239
  - ".gitignore"
195
240
  - ".rspec"
196
241
  - ".travis.yml"
197
- - Gemfile
198
242
  - LICENSE.txt
199
243
  - README.md
200
244
  - Rakefile
201
245
  - bin/turnstile
246
+ - example/custom_csv_matcher.rb
202
247
  - lib/turnstile.rb
203
- - lib/turnstile/adapter.rb
248
+ - lib/turnstile/cli/launcher.rb
249
+ - lib/turnstile/cli/parser.rb
250
+ - lib/turnstile/cli/runner.rb
204
251
  - lib/turnstile/collector.rb
252
+ - lib/turnstile/collector/actor.rb
253
+ - lib/turnstile/collector/controller.rb
254
+ - lib/turnstile/collector/flusher.rb
205
255
  - lib/turnstile/collector/formats.rb
256
+ - lib/turnstile/collector/formats/custom_matcher.rb
257
+ - lib/turnstile/collector/formats/delimited_matcher.rb
258
+ - lib/turnstile/collector/formats/json_matcher.rb
206
259
  - lib/turnstile/collector/log_reader.rb
207
- - lib/turnstile/collector/matcher.rb
208
- - lib/turnstile/collector/runner.rb
209
- - lib/turnstile/collector/updater.rb
260
+ - lib/turnstile/collector/regexp_matcher.rb
261
+ - lib/turnstile/collector/session.rb
262
+ - lib/turnstile/commands.rb
263
+ - lib/turnstile/commands/base.rb
264
+ - lib/turnstile/commands/flushdb.rb
265
+ - lib/turnstile/commands/print_keys.rb
266
+ - lib/turnstile/commands/show.rb
210
267
  - lib/turnstile/configuration.rb
268
+ - lib/turnstile/dependencies.rb
211
269
  - lib/turnstile/logger.rb
270
+ - lib/turnstile/logger/helper.rb
271
+ - lib/turnstile/logger/provider.rb
212
272
  - lib/turnstile/observer.rb
213
- - lib/turnstile/parser.rb
214
- - lib/turnstile/runner.rb
273
+ - lib/turnstile/redis/adapter.rb
274
+ - lib/turnstile/redis/connection.rb
275
+ - lib/turnstile/redis/spy.rb
215
276
  - lib/turnstile/sampler.rb
216
- - lib/turnstile/summary.rb
217
277
  - lib/turnstile/tracker.rb
218
278
  - lib/turnstile/version.rb
279
+ - lib/turnstile/web_app.rb
280
+ - spec/fixtures/custom-production.log
219
281
  - spec/fixtures/sample-production.log
220
282
  - spec/fixtures/sample-production.log.json
221
283
  - spec/spec_helper.rb
284
+ - spec/support/logging.rb
222
285
  - spec/turnstile/adapter_spec.rb
286
+ - spec/turnstile/collector/flusher_spec.rb
223
287
  - spec/turnstile/collector/log_reader_spec.rb
288
+ - spec/turnstile/commands/show_spec.rb
224
289
  - spec/turnstile/configuration_spec.rb
225
290
  - spec/turnstile/observer_spec.rb
226
291
  - spec/turnstile/sampler_spec.rb
227
- - spec/turnstile/summary_spec.rb
228
292
  - spec/turnstile/tracker_spec.rb
229
293
  - spec/turnstile_spec.rb
230
294
  - turnstile-rb.gemspec
@@ -248,20 +312,23 @@ required_rubygems_version: !ruby/object:Gem::Requirement
248
312
  version: '0'
249
313
  requirements: []
250
314
  rubyforge_project:
251
- rubygems_version: 2.6.11
315
+ rubygems_version: 2.7.6
252
316
  signing_key:
253
317
  specification_version: 4
254
318
  summary: Asynchronous and non-invasive concurrent user tracking with Redis, by scanning
255
319
  application logs across all servers.
256
320
  test_files:
321
+ - spec/fixtures/custom-production.log
257
322
  - spec/fixtures/sample-production.log
258
323
  - spec/fixtures/sample-production.log.json
259
324
  - spec/spec_helper.rb
325
+ - spec/support/logging.rb
260
326
  - spec/turnstile/adapter_spec.rb
327
+ - spec/turnstile/collector/flusher_spec.rb
261
328
  - spec/turnstile/collector/log_reader_spec.rb
329
+ - spec/turnstile/commands/show_spec.rb
262
330
  - spec/turnstile/configuration_spec.rb
263
331
  - spec/turnstile/observer_spec.rb
264
332
  - spec/turnstile/sampler_spec.rb
265
- - spec/turnstile/summary_spec.rb
266
333
  - spec/turnstile/tracker_spec.rb
267
334
  - spec/turnstile_spec.rb
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- source 'https://rubygems.org'
4
-
5
- # Specify your gem's dependencies in turnstile-rb.gemspec
6
- gemspec
@@ -1,61 +0,0 @@
1
- require 'redis'
2
- require 'timeout'
3
-
4
- module Turnstile
5
- class Adapter
6
- attr_accessor :redis
7
- include Timeout
8
-
9
- def initialize
10
- self.redis = config.redis.url ?
11
- ::Redis.new(url: config.redis.url) :
12
- ::Redis.new(host: config.redis.host,
13
- port: config.redis.port,
14
- db: config.redis.db)
15
- end
16
-
17
- def add(uid, platform, ip)
18
- key = compose_key(uid, platform, ip)
19
- timeout(config.redis.timeout) do
20
- redis.setex(key, config.activity_interval, 1)
21
- end
22
- rescue StandardError => e
23
- Turnstile::Logger.log "exception while writing to redis: #{e.inspect}"
24
- end
25
-
26
- def fetch
27
- redis.keys('t:*').map do |key|
28
- fields = key.split(':')
29
- {
30
- uid: fields[1],
31
- platform: fields[2],
32
- ip: fields[3],
33
- }
34
- end
35
- end
36
-
37
- def aggregate
38
- redis.keys('t:*').inject({}) { |hash, key| increment_platform(hash, key) }.tap do |h|
39
- h['total'] = h.values.inject(&:+) || 0
40
- end
41
- end
42
-
43
- private
44
-
45
- def increment_platform(hash, key)
46
- platform = key.split(':')[2]
47
- hash[platform] ||= 0
48
- hash[platform] += 1
49
- hash
50
- end
51
-
52
- def config
53
- Turnstile.config
54
- end
55
-
56
- def compose_key(uid, platform = nil, ip = nil)
57
- "t:#{uid}:#{platform}:#{ip}"
58
- end
59
-
60
- end
61
- end
@@ -1,72 +0,0 @@
1
- require 'thread'
2
- require 'daemons/daemonize'
3
- require 'colored2'
4
-
5
-
6
- module Turnstile
7
- module Collector
8
- class Runner
9
- attr_accessor :config, :queue, :reader, :updater, :file
10
-
11
- def initialize(*args)
12
- @config = args.last.is_a?(Hash) ? args.pop : {}
13
- @file = config[:file]
14
- @queue = Queue.new
15
-
16
- config[:debug] ? Turnstile::Logger.enable : Turnstile::Logger.disable
17
-
18
- wait_for_file(@file)
19
-
20
- self.reader
21
- self.updater
22
-
23
- Daemonize.daemonize if config[:daemonize]
24
- STDOUT.sync = true if config[:debug]
25
- end
26
-
27
- def wait_for_file(file)
28
- sleep_period = 1
29
- while !File.exist?(file)
30
- STDERR.puts "File #{file.bold.yellow} does not exist, waiting for it to appear..."
31
- STDERR.puts 'Press Ctrl-C to abort.' if sleep_period == 1
32
-
33
- sleep sleep_period
34
- sleep_period *= 1.2
35
- end
36
- end
37
-
38
- def run
39
- threads = [reader, updater].map(&:run)
40
- threads.last.join
41
- end
42
-
43
- def updater
44
- @updater ||= Turnstile::Collector::Updater.new(queue,
45
- config[:buffer_interval] || 5,
46
- config[:flush_interval] || 6)
47
- end
48
-
49
- def log_reader_class
50
- Turnstile::Collector::LogReader
51
- end
52
-
53
- def reader
54
- args = [file, queue]
55
- matcher = :default
56
-
57
- if config[:delimiter]
58
- matcher = :delimited
59
- args << config[:delimiter]
60
- elsif config[:filetype]
61
- matcher = config[:filetype].to_sym
62
- end
63
-
64
- @reader ||= if log_reader_class.respond_to?(matcher)
65
- log_reader_class.send(matcher, *args)
66
- else
67
- raise ArgumentError, "Invalid matcher #{matcher}"
68
- end
69
- end
70
- end
71
- end
72
- end