meeseeks 0.1.0 → 0.1.3

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: 239577cae2742ede49f2120ac5f0be611872f7827c1f72b97583da59d9b84da0
4
- data.tar.gz: e21ff55141f6ad7e29113516a3c0660bbc981653ced9cdc4aea429f25f987322
3
+ metadata.gz: c2797830d0c41af4fb2ce0dd7cf70c935da9fa17c1c02e065ba21693e57ebc83
4
+ data.tar.gz: 126582c74053256339b37584423e0a02976629b78ee8ca4031cd7c45ff790a5e
5
5
  SHA512:
6
- metadata.gz: e2e068041a6a6ff27150dd5673f09926757c05ad3f33c9b1e1cded25a440533c63c0df32960a3863cfe4c0ab1bba170bb61d17590c342d35aeb1918661b61d46
7
- data.tar.gz: 9a6f0cc519fb5abd30c5b20d91386b37ebf4bf609f9189cbd9f97ff83c51ccbbaf52e692ddc3cb6b7e6f0991536fbecea35fb58dcc3ab9581f805a1f48551c8b
6
+ metadata.gz: 7ddff6adf34e30e2ef933ed781d070041b2d83c9c3c19d1ad30ea8fc34615f58897310c049b97c7494a3a35cdc7c8d90fb4d2ea2eb4c374d7a96ae0cb6cdad15
7
+ data.tar.gz: 8ca041a2e5f8c7434f967c11ef2470d6c7389260ffc8de3c746b51c91d5d252958c8ce4142c768bc40be3a579d85a883d63696be64b39a3d6edf37aab03cb034
data/.gitignore CHANGED
@@ -7,6 +7,5 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
 
10
- # rspec failure tracking
11
10
  .rspec_status
12
11
  .bash_history
data/.rubocop.yml CHANGED
@@ -6,3 +6,7 @@ AllCops:
6
6
  - Guardfile
7
7
  Documentation:
8
8
  Enabled: false
9
+
10
+ Metrics/BlockLength:
11
+ Exclude:
12
+ - spec/**/*
data/.travis.yml CHANGED
@@ -1,5 +1,9 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.5.0
5
- before_install: gem install bundler -v 1.16.1
1
+ sudo: required
2
+ dist: trusty
3
+ group: edge
4
+ services:
5
+ - docker
6
+ before_script:
7
+ - make build
8
+ script:
9
+ - make test
data/Gemfile.lock CHANGED
@@ -1,14 +1,16 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- meeseeks (0.1.0)
4
+ meeseeks (0.1.3)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ ansi (1.5.0)
9
10
  ast (2.4.0)
10
11
  coderay (1.1.2)
11
12
  diff-lcs (1.3)
13
+ docile (1.3.1)
12
14
  ffi (1.9.25)
13
15
  formatador (0.2.5)
14
16
  guard (2.14.2)
@@ -32,7 +34,9 @@ GEM
32
34
  guard-rubocop (1.3.0)
33
35
  guard (~> 2.0)
34
36
  rubocop (~> 0.20)
37
+ hirb (0.7.3)
35
38
  jaro_winkler (1.5.1)
39
+ json (2.1.0)
36
40
  listen (3.1.5)
37
41
  rb-fsevent (~> 0.9, >= 0.9.4)
38
42
  rb-inotify (~> 0.9, >= 0.9.7)
@@ -79,6 +83,15 @@ GEM
79
83
  ruby-progressbar (1.10.0)
80
84
  ruby_dep (1.5.0)
81
85
  shellany (0.0.1)
86
+ simplecov (0.16.1)
87
+ docile (~> 1.1)
88
+ json (>= 1.8, < 3)
89
+ simplecov-html (~> 0.10.0)
90
+ simplecov-console (0.4.2)
91
+ ansi
92
+ hirb
93
+ simplecov
94
+ simplecov-html (0.10.2)
82
95
  thor (0.20.0)
83
96
  unicode-display_width (1.4.0)
84
97
 
@@ -93,6 +106,8 @@ DEPENDENCIES
93
106
  meeseeks!
94
107
  rake (~> 10.0)
95
108
  rspec (~> 3.0)
109
+ simplecov (~> 0.15)
110
+ simplecov-console (~> 0.4)
96
111
 
97
112
  BUNDLED WITH
98
113
  1.16.4
data/Makefile CHANGED
@@ -27,7 +27,7 @@ bundle:
27
27
  docker-compose run meeseeks bash -l -c "bundle check || bundle install"
28
28
 
29
29
  console: bundle
30
- docker-compose run meeseeks bash -l -c "bundle exec bin/console"
30
+ docker-compose exec meeseeks bash -l -c "bundle exec bin/console" || docker-compose run meeseeks bash -l -c "bundle exec bin/console"
31
31
 
32
32
  guard-down:
33
33
  docker-compose -p meeseeks-guard down --remove-orphans
@@ -45,7 +45,7 @@ guard-shell:
45
45
  docker-compose -p meeseeks-guard run meeseeks bash -c "(bundle check || bundle install) && bash"
46
46
 
47
47
  rubocop:
48
- docker-compose run meeseeks bash -l -c "bundle exec rubocop -a"
48
+ docker-compose run meeseeks bash -l -c "(bundle check || bundle install) && bundle exec rubocop -a"
49
49
 
50
50
 
51
51
  test: guard-down guard-up
data/README.md CHANGED
@@ -1,39 +1,75 @@
1
- # Meeseeks
1
+ [![Build Status](https://travis-ci.com/coup-mobility/meeseeks.svg?branch=master)](https://travis-ci.com/coup-mobility/meeseeks) [![Maintainability](https://api.codeclimate.com/v1/badges/3b8aad1633758b0723bc/maintainability)](https://codeclimate.com/github/coup-mobility/meeseeks/maintainability)
2
+
3
+ ![](meeseeks.png)
4
+ > Meeseeks are creatures who are created to serve a singular purpose for which they will go to any length to fulfill. After they serve their purpose, they expire and vanish into the air. [[1](http://rickandmorty.wikia.com/wiki/Mr._Meeseeks)]
2
5
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/meeseeks`. To experiment with that code, run `bin/console` for an interactive prompt.
6
+ # Meeseeks
4
7
 
5
- TODO: Delete this and the text above, and describe your gem
8
+ ⚠️ Do not use in production ⚠️
6
9
 
7
- ## Installation
10
+ ## Usage
8
11
 
9
- Add this line to your application's Gemfile:
12
+ Asynchronously submit metrics to a Circonus HTTPTrap:
10
13
 
11
14
  ```ruby
12
- gem 'meeseeks'
15
+ > m = Meeseeks::Meeseeks.new(
16
+ data_submission_url: 'https://api.circonus.com/module/httptrap/2ds89as2-29e3-4155-a54a-4b7261419e11/secret',
17
+ interval: 60,
18
+ max_batch_size: 100,
19
+ max_queue_size: 10_000
20
+ )
21
+ => #<Meeseeks::Meeseeks:0x00005640e59dd380 … >
22
+ > m.record('group', 'metric', 22.02)
23
+ => true
13
24
  ```
14
25
 
15
- And then execute:
26
+ You can also configure Meeseeks via environment variables
16
27
 
17
- $ bundle
28
+ - `MEESEEKS_DATA_SUBMISSION_URL=https://api.circonus.com/module/httptrap/2ds89as2-29e3-4155-a54a-4b7261419e11/secret`
29
+ - `MEESEEKS_INTERVAL=60`
30
+ - `MEESEEKS_MAX_BATCH_SIZE=100`
31
+ - `MEESEEKS_MAX_QUEUE_SIZE=10000`
18
32
 
19
- Or install it yourself as:
33
+ and use the singleton (to the same effect as the example above):
20
34
 
21
- $ gem install meeseeks
35
+ ```ruby
36
+ Meeseeks.instance.record('group', 'metric', 22.02)
37
+ ```
22
38
 
23
- ## Usage
39
+ ### Meeseeks statistics
40
+
41
+ Meeseeks will instrument itself on Circonus. Look for these metrics:
24
42
 
25
- TODO: Write usage instructions here
43
+ - ``meeseeks`batch_size`` (how many measurements were submitted per request to Circonus?)
44
+ - ``meeseeks`cycle_count`` (how many intervals did this meeseeks instance do?)
45
+ - ``meeseeks`queue_size`` (how many measurements are waiting in the queue to be submitted?)
46
+ - ``meeseeks`request_count`` (how many requests to Circonus did this meeseeks instance do?)
26
47
 
27
48
  ## Development
28
49
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
50
+ After checking out the repo, run `make build` - you need only docker on your machine, no ruby, rvm, or any of that.
30
51
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
52
+ ### Launch a shell or console
53
+
54
+ To try it out locally while developing, you can `make shell` to open a shell in a container where the gem's dependencies are installed, and you can use `make console` as an alias for entering `make shell` and `rake console`.
55
+
56
+ ### Run the tests
57
+
58
+ During development, you can just keep `make guard` running and it will test files as you edit them. You can also run `make test` to run all of the tests.
59
+
60
+ ### Automatically fix rubocop offenses
61
+
62
+ Run `make rubocop`.
32
63
 
33
64
  ## Contributing
34
65
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/jayniz/meeseeks. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
66
+ Bug reports and pull requests are welcome on GitHub at https://github.com/coup-mobility/meeseeks. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
67
 
37
68
  ## Code of Conduct
38
69
 
39
- Everyone interacting in the Meeseeks project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/jayniz/meeseeks/blob/master/CODE_OF_CONDUCT.md).
70
+ Everyone interacting in the Meeseeks project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/coup-mobility/meeseeks/blob/master/CODE_OF_CONDUCT.md).
71
+
72
+
73
+ ## Acknowledgements
74
+
75
+ Mr. Meeseeks picture by [Nathan Andrews](https://dribbble.com/shots/2846308-Mr-Meeseeks)
data/docker-compose.yml CHANGED
@@ -15,5 +15,3 @@ services:
15
15
  image: coup-mobility/meeseeks
16
16
  volumes:
17
17
  meeseeks-bundler-cache:
18
- meeseeks-rails-bundler-cache:
19
-
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meeseeks
4
+ class Error < StandardError
5
+ end
6
+ end
7
+
8
+ require 'meeseeks/errors/invalid_type'
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meeseeks
4
+ module Errors
5
+ class InvalidType < Meeseeks::Error
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'meeseeks/http_trap'
4
+
5
+ # Checks a queue in regular intervals and bulk submits measurements
6
+ # to a Circonus HTTPTrap https://login.circonus.com/resources/docs/user/Data/CheckTypes/HTTPTrap.html
7
+ module Meeseeks
8
+ class Harvester
9
+ attr_reader :interval, :max_batch_size, :cycle_count
10
+
11
+ def initialize(queue:, http_trap:, interval: 60, max_batch_size: 100)
12
+ @queue = queue
13
+ @http_trap = http_trap
14
+ @interval = interval
15
+ @max_batch_size = max_batch_size
16
+ @cycle_count = 0
17
+ @lock = Mutex.new
18
+ end
19
+
20
+ def start
21
+ @continue = true
22
+ return if @thread&.alive?
23
+
24
+ @thread = Thread.new do
25
+ loop do
26
+ sleep(@interval)
27
+ break unless @continue
28
+
29
+ @cycle_count += 1
30
+ drain
31
+ end
32
+ end
33
+ end
34
+
35
+ def stop
36
+ @continue = false
37
+ end
38
+
39
+ def kill
40
+ @thread&.kill if @thread&.alive?
41
+ end
42
+
43
+ def running?
44
+ @thread&.alive?
45
+ end
46
+
47
+ def drain
48
+ @lock.synchronize do
49
+ drain_queue_async
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def drain_queue_async
56
+ loop do
57
+ batch = batch_from_queue
58
+
59
+ begin
60
+ submit(batch)
61
+ rescue StandardError
62
+ # TODO: think about whether or not this is a good idea. It's nice to
63
+ # recover from the occasional HTTP hickup, but when we can't submit
64
+ # to Circonus for whatever reason, we'll fill up the RAM. Do we want
65
+ # to implement limited retries here, or do we want to impose a max
66
+ # length on the queue, or what do we want to do?
67
+ batch.map { |d| @queue.push(d) }
68
+ end
69
+
70
+ # Even if the batch is empty, we want to submit our own statistics
71
+ # for this cycle, and that's why we don't break before the submit
72
+ break if batch.empty?
73
+ end
74
+ end
75
+
76
+ def batch_from_queue
77
+ batch = []
78
+
79
+ loop do
80
+ batch << @queue.pop(true)
81
+ break if @queue.empty? || batch.length >= @max_batch_size - 1
82
+ rescue ThreadError => e
83
+ e.message == 'queue empty' ? break : raise
84
+ end
85
+
86
+ batch
87
+ end
88
+
89
+ def meeseeks_stats_payload(batch_size)
90
+ { meeseeks: {} }.tap do |stats|
91
+ stats[:meeseeks].merge!(Payload.for('batch_size', batch_size))
92
+ stats[:meeseeks].merge!(Payload.for('queue_size', @queue.size))
93
+ stats[:meeseeks].merge!(Payload.for('request_count', submit_count))
94
+ stats[:meeseeks].merge!(Payload.for('cycle_count', @cycle_count))
95
+ end
96
+ end
97
+
98
+ def submit_count
99
+ @http_trap.submit_count
100
+ end
101
+
102
+ def submit(measurements)
103
+ stats = [meeseeks_stats_payload(measurements.length + 1)]
104
+ @http_trap.submit(measurements + stats)
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+
6
+ module Meeseeks
7
+ class HTTPTrap
8
+ attr_reader :last, :submit_count
9
+
10
+ def initialize(data_submission_url)
11
+ @uri = URI.parse(data_submission_url)
12
+ @submit_count = 0
13
+ end
14
+
15
+ def submit(measurements)
16
+ req = request(measurements)
17
+ res = http.request(req)
18
+
19
+ @last = OpenStruct.new(time: Time.now, request: req, response: res)
20
+ @submit_count += 1
21
+
22
+ JSON.parse res.body
23
+ end
24
+
25
+ private
26
+
27
+ def request(measurements)
28
+ put.tap do |request|
29
+ request.body = measurements.map(&:to_json).join("\n")
30
+ end
31
+ end
32
+
33
+ def http
34
+ Net::HTTP.new(@uri.host, @uri.port).tap do |http|
35
+ http.use_ssl = @uri.scheme == 'https'
36
+ end
37
+ end
38
+
39
+ def put
40
+ Net::HTTP::Put.new(@uri.path, 'Content-Type' => 'application/json')
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'meeseeks/error'
4
+ require 'meeseeks/harvester'
5
+ require 'meeseeks/http_trap'
6
+ require 'meeseeks/payload'
7
+ require 'date'
8
+
9
+ # Allows you to asynchronously send measurements to Circonus. Measurements are
10
+ # stored in a queue and a harvester in a background thread empties the queue
11
+ # in regular intervals and submits data to a Circonus HTTPTrap.
12
+ module Meeseeks
13
+ class Meeseeks
14
+ attr_reader :queue, :harvester, :http_trap
15
+
16
+ def initialize(data_submission_url: nil,
17
+ interval: nil,
18
+ max_batch_size: nil,
19
+ max_queue_size: nil)
20
+ @queue = Queue.new
21
+ @interval = interval || ENV.fetch('MEESEEKS_INTERVAL', 60).to_i
22
+ @max_queue_size = max_queue_size ||
23
+ ENV.fetch('MEESEEKS_MAX_QUEUE_SIZE', 100).to_i
24
+ @max_batch_size = max_batch_size ||
25
+ ENV.fetch('MEESEEKS_MAX_BATCH_SIZE', 1_000).to_i
26
+ @data_submission_url = data_submission_url ||
27
+ ENV.fetch('MEESEEKS_DATA_TRANSMISSION_URL')
28
+
29
+ create_http_trap
30
+ start_harvester
31
+ end
32
+
33
+ def record!(group, metric, value, time = DateTime.now)
34
+ Payload.validate_type!(value)
35
+ return false if @queue.size >= @max_queue_size
36
+
37
+ @queue.push(Payload.for_group(group, metric, value, time))
38
+ true
39
+ end
40
+
41
+ def record(group, metric, value, time = DateTime.now)
42
+ record!(group, metric, value, time)
43
+ rescue Error
44
+ false
45
+ end
46
+
47
+ private
48
+
49
+ def create_http_trap
50
+ @http_trap = HTTPTrap.new(@data_submission_url)
51
+ end
52
+
53
+ def start_harvester
54
+ @harvester = Harvester.new(
55
+ queue: @queue,
56
+ http_trap: @http_trap,
57
+ interval: @interval,
58
+ max_batch_size: @max_batch_size
59
+ )
60
+ @harvester.start
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'meeseeks/error'
4
+ require 'date'
5
+
6
+ module Meeseeks
7
+ module Payload
8
+ def self.for_group(group, metric, value, time)
9
+ {
10
+ group => self.for(metric, value, time)
11
+ }
12
+ end
13
+
14
+ def self.for(metric, value, time = DateTime.now)
15
+ {
16
+ metric.to_s => {
17
+ '_ts' => time.to_datetime.strftime('%Q'),
18
+ '_value' => value,
19
+ '_type' => 'i'
20
+ }
21
+ }
22
+ end
23
+
24
+ def self.validate_type!(value)
25
+ return if value.is_a?(String) || value.is_a?(Numeric)
26
+
27
+ raise Errors::InvalidType, "#{value.class.name} values are not supported"
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Meeseeks
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.3'
5
5
  end
data/lib/meeseeks.rb CHANGED
@@ -1,7 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'meeseeks/version'
4
+ require 'meeseeks/meeseeks'
5
+ require 'forwardable'
4
6
 
5
7
  module Meeseeks
6
- # Your code goes here...
8
+ extend SingleForwardable
9
+
10
+ def self.instance
11
+ @instance ||= Meeseeks.new
12
+ end
13
+
14
+ def_delegators :instance, *::Meeseeks::Meeseeks.instance_methods(false)
7
15
  end
data/meeseeks.gemspec CHANGED
@@ -25,4 +25,6 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency 'guard-rubocop', '~> 1.3'
26
26
  spec.add_development_dependency 'rake', '~> 10.0'
27
27
  spec.add_development_dependency 'rspec', '~> 3.0'
28
+ spec.add_development_dependency 'simplecov', '~> 0.15'
29
+ spec.add_development_dependency 'simplecov-console', '~> 0.4'
28
30
  end
data/meeseeks.png ADDED
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meeseeks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jannis Hermanns
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-09-13 00:00:00.000000000 Z
11
+ date: 2018-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,6 +94,34 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.15'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.15'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov-console
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.4'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.4'
97
125
  description: Submits measurements to a circonus http trap
98
126
  email:
99
127
  - jannis.hermanns@joincoup.com
@@ -117,8 +145,15 @@ files:
117
145
  - bin/setup
118
146
  - docker-compose.yml
119
147
  - lib/meeseeks.rb
148
+ - lib/meeseeks/error.rb
149
+ - lib/meeseeks/errors/invalid_type.rb
150
+ - lib/meeseeks/harvester.rb
151
+ - lib/meeseeks/http_trap.rb
152
+ - lib/meeseeks/meeseeks.rb
153
+ - lib/meeseeks/payload.rb
120
154
  - lib/meeseeks/version.rb
121
155
  - meeseeks.gemspec
156
+ - meeseeks.png
122
157
  homepage: https://github.com/coup-mobility/meeseeks
123
158
  licenses: []
124
159
  metadata: {}