turnstile-rb 2.0.1 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,86 +0,0 @@
1
- module Turnstile
2
- module Collector
3
- class Updater
4
-
5
- class Session < ::Struct.new(:uid, :platform, :ip); end
6
-
7
- attr_accessor :queue, :semaphore, :cache, :tracker, :buffer_interval, :flush_interval
8
-
9
- def initialize(queue, buffer_interval = 5, flush_interval = 6)
10
- @queue = queue
11
- @semaphore = Mutex.new
12
- @cache = Hash.new(0)
13
- @tracker = Turnstile::Tracker.new
14
- @buffer_interval = buffer_interval
15
- @buffer_interval = 6 if @buffer_interval <= 0
16
- @flush_interval = flush_interval
17
- @flush_interval = 5 if @flush_interval <= 0
18
- end
19
-
20
- def run
21
- run_queue_popper
22
- run_flusher
23
- end
24
-
25
- private
26
-
27
- def run_flusher
28
- Thread.new do
29
- Thread.current[:name] = 'updater:flush'
30
- loop do
31
- semaphore.synchronize {
32
- unless cache.empty?
33
- Turnstile::Logger.logging "flushing cache with [#{cache.keys.size}] keys" do
34
- cache.keys.each do |key|
35
- session = parse(key)
36
- if session.uid && !session.uid.empty?
37
- tracker.track(session.uid, session.platform, session.ip)
38
- end
39
- end
40
- reset_cache
41
- end
42
- else
43
- Turnstile::Logger.log "nothing to flush, sleeping #{flush_interval}s.."
44
- end
45
- }
46
- sleep flush_interval
47
- end
48
- end
49
- end
50
-
51
- def run_queue_popper
52
- Thread.new do
53
- Thread.current[:name] = 'updater:queue'
54
- loop do
55
- unless queue.empty?
56
- Turnstile::Logger.logging "caching [#{queue.size}] keys locally" do
57
- while !queue.empty?
58
- semaphore.synchronize {
59
- add(queue.pop)
60
- }
61
- end
62
- end
63
- else
64
- Turnstile::Logger.log "nothing in the queue, sleeping #{buffer_interval}s..."
65
- end
66
- sleep buffer_interval
67
- end
68
- end
69
- end
70
-
71
- def add(token)
72
- cache[token] = 1
73
- end
74
-
75
- def parse(token)
76
- a = token.split(':')
77
- Session.new(a[2], a[0], a[1])
78
- end
79
-
80
- def reset_cache
81
- @cache.clear
82
- GC.start
83
- end
84
- end
85
- end
86
- end
@@ -1,107 +0,0 @@
1
- require 'optparse'
2
- require 'colored2'
3
- require 'forwardable'
4
-
5
- require 'turnstile/version'
6
-
7
- module Turnstile
8
- class Parser
9
- extend Forwardable
10
- def_delegators :@system, :stdout, :stdin, :stderr
11
-
12
- attr_accessor :options, :argv, :system
13
-
14
- def initialize(argv, system)
15
- self.system = system
16
- self.argv = argv.dup
17
- self.options = Hashie::Mash.new
18
- self.argv << '-h' if argv.empty?
19
- end
20
-
21
- def parse
22
- OptionParser.new do |opts|
23
- opts.banner = "Usage:\n".bold.magenta +
24
- " turnstile -f <file> [ --daemon ] [ options ]\n".yellow +
25
- " turnstile -s [ json | csv | nad ] [ options ]\n".yellow +
26
- " turnstile -a 'platform:ip:user' [ options ]\n".yellow
27
-
28
- opts.separator 'Description:'.bold.magenta
29
- opts.separator ' ' + ::Turnstile::DESCRIPTION.gsub(/\n/, "\n ")
30
-
31
- opts.separator 'Log File Specification:'.bold.magenta
32
- opts.on('-f', '--file FILE', 'File to monitor') do |file|
33
- options[:file] = file
34
- end
35
- opts.on('-t', '--file-type TYPE',
36
- 'Either: json_formatted, pipe_delimited,',
37
- 'or comma_delimited (default).') do |type|
38
- options[:filetype] = type
39
- end
40
- opts.on('-D', '--delimiter CHAR',
41
- 'Forces "delimited" file type, and uses ',
42
- 'the character in the argument as the delimiter') do |v|
43
- options[:delimiter] = v
44
- end
45
- opts.separator "\nRedis Server:".bold.magenta
46
- opts.on('-r', '--redis-url URL', 'Redis server URL') do |host|
47
- Turnstile.config.redis_url = host
48
- end
49
- opts.on('--redis-host HOST', 'Redis server host') do |host|
50
- Turnstile.config.redis_host = host
51
- end
52
- opts.on('--redis-port PORT', 'Redis server port') do |port|
53
- Turnstile.config.redis_port = port
54
- end
55
- opts.on('--redis-db DB', 'Redis server db') do |db|
56
- Turnstile.config.redis_db = db
57
- end
58
- opts.separator "\nMode of Operation:".bold.magenta
59
- opts.on('-d', '--daemonize', 'Daemonize to watch the logs') do |v|
60
- options[:daemonize] = true
61
- end
62
- opts.on('-s', '--summary [FORMAT]',
63
- 'Print current stats and exit. Optional format can be',
64
- 'json (default), nad, yaml, or csv') do |v|
65
- options[:summary] = true
66
- options[:summary_format] = (v || 'json').to_sym
67
- end
68
- opts.on('-a', '--add TOKEN',
69
- 'Registers an event from the token, such as ',
70
- '"ios:123.4.4.4:32442". Use -d to customize delimiter.') do |v|
71
- options[:add] = v
72
- end
73
- opts.separator "\nTiming Adjustments:".bold.magenta
74
- opts.on('-b', '--buffer-interval INTERVAL', 'Buffer for this many seconds') do |v|
75
- options[:buffer_interval] = v.to_i
76
- end
77
- opts.on('-i', '--flush-interval INTERVAL', 'Flush then sleep for this many seconds') do |v|
78
- options[:flush_interval] = v.to_i
79
- end
80
- opts.separator "\nMiscellaneous:".bold.magenta
81
- opts.on('-v', '--verbose', 'Print status to stdout') do |v|
82
- options[:debug] = true
83
- end
84
- opts.on_tail('-h', '--help', 'Show this message') do
85
- puts opts
86
- return
87
- end
88
- end.parse!(argv)
89
-
90
- if options[:summary]
91
- Turnstile::Summary.print(options[:summary_format] || :json, options[:delimiter])
92
- elsif options[:add]
93
- Turnstile::Tracker.new.add_token(options[:add], options[:delimiter] || ':')
94
- Turnstile::Summary.print(options[:summary_format] || :json)
95
- else
96
- Turnstile::Collector::Runner.new(options).run
97
- end
98
-
99
- rescue OptionParser::MissingArgument => e
100
- STDERR.puts e.message.bold.red
101
- rescue Exception => e
102
- STDERR.puts e.message.bold.red
103
- end
104
- end
105
- end
106
-
107
-
@@ -1,54 +0,0 @@
1
- require 'optparse'
2
- require 'colored2'
3
-
4
- require 'turnstile/version'
5
- require 'turnstile/parser'
6
-
7
- module Turnstile
8
-
9
-
10
- class Runner
11
- attr_reader :argv, :stdin, :stdout, :stderr, :kernel
12
-
13
- # Allow everything fun to be injected from the outside while defaulting to normal implementations.
14
- def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
15
- @argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
16
- end
17
-
18
- def execute!
19
- exit_code = begin
20
-
21
- Colored2.disable! unless stdout.tty?
22
-
23
- $stderr = stderr
24
- $stdin = stdin
25
- $stdout = stdout
26
-
27
- Turnstile::Parser.new(argv, self).parse
28
-
29
- # Thor::Base#start does not have a return value, assume success if no exception is raised.
30
- 0
31
- rescue StandardError => e
32
- # The ruby interpreter would pipe this to STDERR and exit 1 in the case of an unhandled exception
33
- b = e.backtrace
34
- @stderr.puts("#{b.shift}: #{e.message} (#{e.class})")
35
- @stderr.puts(b.map { |s| "\tfrom #{s}" }.join("\n"))
36
- 1
37
- rescue SystemExit => e
38
- e.status
39
- ensure
40
- $stderr = STDERR
41
- $stdin = STDIN
42
- $stdout = STDOUT
43
- end
44
-
45
- # Proxy our exit code back to the injected kernel.
46
- @kernel.exit(exit_code)
47
- end
48
- end
49
- end
50
-
51
- module Turnstile
52
-
53
- end
54
-
@@ -1,57 +0,0 @@
1
- require 'csv'
2
- module Turnstile
3
- class Summary
4
-
5
- class << self
6
- def print(method, delimiter = nil)
7
- summary = new
8
- if summary.respond_to?(method)
9
- STDOUT.puts summary.send(method, delimiter)
10
- else
11
- STDERR.puts "don't know how to use format '#{method}'mac"
12
- end
13
- end
14
- end
15
-
16
- def json(*)
17
- out = "{\n"
18
- first = true
19
- aggregate.each_pair do |key, value|
20
- out << ",\n" unless first
21
- first = false
22
- out << json_row(key, value)
23
- end
24
- out << "\n}"
25
- out
26
- end
27
-
28
- def nad(*)
29
- out = ''
30
- aggregate.each_pair do |key, value|
31
- out << nad_row(key, value)
32
- end
33
- out
34
- end
35
-
36
- def csv(delimiter = nil)
37
- out = CSV.generate do |csv|
38
- aggregate.each_pair do |key, value|
39
- csv << [key, value]
40
- end
41
- end
42
- delimiter ? out.gsub(/,/m, delimiter) : out
43
- end
44
-
45
- def nad_row(key, value)
46
- %Q(turnstile:#{key}#{"\tn\t"}#{value}\n)
47
- end
48
-
49
- def json_row(key, value)
50
- %Q( "#{key}": #{value})
51
- end
52
-
53
- def aggregate
54
- Turnstile::Adapter.new.aggregate
55
- end
56
- end
57
- end
@@ -1,41 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Turnstile::Summary do
4
- subject { described_class.new }
5
-
6
- let(:aggregate) {
7
- {
8
- 'android' => 3,
9
- 'ios' => 2,
10
- 'total' => 5
11
- }
12
- }
13
-
14
- before { expect(subject).to receive(:aggregate).once.and_return(aggregate) }
15
-
16
- describe '#nad' do
17
- context 'have some data' do
18
- let(:expected_string) {
19
- <<-EOF
20
- turnstile:android#{"\t"}n#{"\t"}3
21
- turnstile:ios#{"\t"}n#{"\t"}2
22
- turnstile:total#{"\t"}n#{"\t"}5
23
- EOF
24
- }
25
-
26
- it 'return data in NAD format' do
27
- expect(subject.nad).to eql(expected_string)
28
- end
29
- end
30
- end
31
-
32
- describe '#json' do
33
- context 'have some data' do
34
- let(:json) { subject.json }
35
- let(:hash) { JSON.load(json) }
36
- it 'return data in NAD format' do
37
- expect(hash).to eql(aggregate)
38
- end
39
- end
40
- end
41
- end