meeseeks 0.1.0 → 0.1.3

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 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: {}