deimos 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb1166f1af8b6589e45dc0a2ab20fec615b691db7348e91199b368714a43e3a1
4
- data.tar.gz: 562fd8af67609e08de2f1063053a6f8cd6f84671a844e4d44b5bf61543a14800
3
+ metadata.gz: 15cc6372bc401ffa051316be8573fd8066b5f1749753679d680459c8846a394d
4
+ data.tar.gz: 504c5872e4c5c71ebd1f269075667589697fd3e20b95e6f10461e01fb2d8009a
5
5
  SHA512:
6
- metadata.gz: 980ee84529e282e676faa1191f8053ee6ff451d466f13888a5ecbf0448e450ef9e5c27cb04392847bedb2511c8fb473f38cd2ceeea7320132b5463df619c204b
7
- data.tar.gz: 20afcdeea07eab350938a88580898c0a6e5a11a7b695394c94eac68eeb5ea37e44bc80722f3b70fe5d50f82ccfa397fc0508f8bdd53d1cc61505224a2678b7f3
6
+ metadata.gz: 115bd70bb83642e7e58eeb5fd79856a0c1bb42390f879898ae015d0180bd81770ef6eb9499af239b1dc0ed6c90330f175abd4176a8b0b61834d1603e5dc83075
7
+ data.tar.gz: 4bf4b534367761779afc0c359cd5081c308d7245049b4a8c28fd953ef1d7a332d3d4af32e45098221f96a86a32ae94e2e8f02238b53fb635572a38668bbb6da9
data/Gemfile.lock CHANGED
@@ -2,23 +2,38 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  deimos (0.1.0)
5
+ activesupport
6
+ concurrent-ruby
5
7
  huyegger
8
+ prometheus-client
6
9
  sinatra
7
10
  sinatra-contrib
8
11
 
9
12
  GEM
10
13
  remote: https://rubygems.org/
11
14
  specs:
15
+ activesupport (5.2.2)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 0.7, < 2)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
12
20
  backports (3.12.0)
13
21
  coderay (1.1.2)
22
+ concurrent-ruby (1.1.4)
14
23
  diff-lcs (1.3)
15
24
  huyegger (0.4.4)
25
+ i18n (1.6.0)
26
+ concurrent-ruby (~> 1.0)
16
27
  method_source (0.9.2)
28
+ minitest (5.11.3)
17
29
  multi_json (1.13.1)
18
30
  mustermann (1.0.3)
31
+ prometheus-client (0.9.0)
32
+ quantile (~> 0.2.1)
19
33
  pry (0.12.2)
20
34
  coderay (~> 1.1.0)
21
35
  method_source (~> 0.9.0)
36
+ quantile (0.2.1)
22
37
  rack (2.0.6)
23
38
  rack-protection (2.0.5)
24
39
  rack
@@ -48,7 +63,10 @@ GEM
48
63
  rack-protection (= 2.0.5)
49
64
  sinatra (= 2.0.5)
50
65
  tilt (>= 1.3, < 3)
66
+ thread_safe (0.3.6)
51
67
  tilt (2.0.9)
68
+ tzinfo (1.2.5)
69
+ thread_safe (~> 0.1)
52
70
 
53
71
  PLATFORMS
54
72
  ruby
data/README.md CHANGED
@@ -1,8 +1,10 @@
1
1
  # Deimos
2
2
 
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/deimos`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Deimos is an application designed to be run alongside Phobos, but can be run in any context to provide a unified status and metrics interface for kubernetes style applications.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ ## Name
6
+
7
+ Deimos, brother of Phobos, from Greek mythology. The personification of dread and terror. Also it is the other natural Martian satelite, the first being Phobos
6
8
 
7
9
  ## Installation
8
10
 
@@ -22,7 +24,74 @@ Or install it yourself as:
22
24
 
23
25
  ## Usage
24
26
 
25
- TODO: Write usage instructions here
27
+ ### Configuration
28
+
29
+ ```ruby
30
+ Deimos.configure do |config|
31
+ config.log_level = ENV.fetch("LOG_LEVEL", ::Logger::INFO)
32
+ config.port = ENV.fetch("PORT", 5000)
33
+ config.bind = ENV.fetch("BIND_IP", "0.0.0.0")
34
+ # An application hash that allows you to add more rack apps
35
+ # Doesn't override the defaults, just merges
36
+ config.applications.merge('/path' => Rack::App.new)
37
+ # Allows you to inject more middlewares into the application
38
+ config.applications.middleware << Middleware
39
+ end
40
+ ```
41
+
42
+ ### Status
43
+
44
+ Deimos allows you to add as many status checks are you like, however the API expects a true or false response. Any false responses from the bound blocks will return an `internal_server_error`
45
+
46
+ ```ruby
47
+ Deimos.status.add(:allocations) { AllocationService::Status.new.call }
48
+ Deimos.status.add(:another_check) { true }
49
+ ```
50
+ ```json
51
+ # GET /status
52
+ { "allocations":true, "another_check":true }
53
+ ```
54
+
55
+ Status checks are run in parallel.
56
+
57
+
58
+ ### Metrics
59
+
60
+ Deimos uses `ActiveSupport::Notification` and `Prometheus` under the hood.
61
+
62
+ #### Subscribing
63
+
64
+ The subsription takes, three required arguments and a block.
65
+ * The event name to subscribe to
66
+ * The type of collector
67
+ * The prometheus label
68
+
69
+ It also takes any extra keyword arguments and passes them to the collector, allowing you to specify extra options for each type of collector
70
+
71
+ * [Prometheus Collectors](https://github.com/prometheus/client_ruby#metrics)
72
+ * [ActiveSupport Notifications](https://api.rubyonrails.org/classes/ActiveSupport/Notifications.html)
73
+
74
+ ```ruby
75
+ Deimos.metrics.subscribe('event.name', type: :gauge, label: 'Label') do |event, collector|
76
+ collector.increment({}, event.payload[:value])
77
+ # event is an ActiveSupport::Notification::Event
78
+ # event.name # => "render"
79
+ # event.duration # => 10 (in milliseconds)
80
+ # event.payload # => {some: :payload}
81
+
82
+ # collector is a Prometheus::Client::#{type.classify}
83
+ end
84
+ ```
85
+
86
+ #### Instrumenting
87
+
88
+ `Deimos.metrics.instrument` delegates directly to `ActiveSupport::Notifications.instrument`, please see the [ActiveSupport Notifications](https://api.rubyonrails.org/classes/ActiveSupport/Notifications.html) documentation for more information
89
+
90
+ ```ruby
91
+ Deimos.metrics.instrument('product_count', value: 10 + i) do
92
+ # can wrap a block to give you code execution duration
93
+ end
94
+ ```
26
95
 
27
96
  ## Development
28
97
 
@@ -32,7 +101,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
101
 
33
102
  ## Contributing
34
103
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/deimos.
104
+ Bug reports and pull requests are welcome on GitHub at https://github.com/adamcarlile/deimos.
36
105
 
37
106
  ## License
38
107
 
data/deimos.gemspec CHANGED
@@ -23,6 +23,9 @@ Gem::Specification.new do |spec|
23
23
  spec.add_dependency "sinatra"
24
24
  spec.add_dependency "sinatra-contrib"
25
25
  spec.add_dependency "huyegger"
26
+ spec.add_dependency "concurrent-ruby"
27
+ spec.add_dependency "prometheus-client"
28
+ spec.add_dependency "activesupport"
26
29
 
27
30
  spec.add_development_dependency "bundler", "~> 1.16"
28
31
  spec.add_development_dependency "rake", "~> 10.0"
@@ -0,0 +1,11 @@
1
+ module Deimos
2
+ module Endpoints
3
+ class Metrics < Sinatra::Application
4
+ disable :logging
5
+ set :logger, Deimos.logger
6
+
7
+ use Prometheus::Middleware::Exporter, registry: Deimos.metrics.registry, path: ''
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ module Deimos
2
+ module Endpoints
3
+ class Status < Sinatra::Application
4
+ disable :logging
5
+ set :logger, Deimos.logger
6
+
7
+ get "/" do
8
+ status_runner = Deimos.status.run!
9
+
10
+ content_type :json
11
+ status status_runner.status
12
+ status_runner.body
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ module Deimos
2
+ module Metrics
3
+ class Manager
4
+ TYPES = {
5
+ counter: Prometheus::Client::Counter,
6
+ gauge: Prometheus::Client::Gauge,
7
+ histogram: Prometheus::Client::Histogram,
8
+ summary: Prometheus::Client::Summary
9
+ }
10
+
11
+ delegate :instrument, to: ActiveSupport::Notifications
12
+
13
+ def subscriptions
14
+ @subscriptions ||= []
15
+ end
16
+
17
+ def collectors
18
+ @collectors ||= {}
19
+ end
20
+
21
+ def registry
22
+ @registry ||= Prometheus::Client.registry
23
+ end
24
+
25
+ def subscribe(event_name, type:, label:, **kwargs, &block)
26
+ Deimos.logger.info "Metrics: Subscribed to #{event_name}..."
27
+ subscriptions << ActiveSupport::Notifications.subscribe(event_name) do |*args|
28
+ event = ActiveSupport::Notifications::Event.new(*args)
29
+ collector = register_collector!(event_name, type, label, kwargs)
30
+ if block_given?
31
+ yield(event, collector)
32
+ else
33
+ Deimos.logger.info event
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def register_collector!(event_name, type, about, **kwargs)
41
+ return collectors[event_name] if collectors[event_name].present?
42
+ name = event_name.gsub(".", "_").to_sym
43
+ collectors[event_name] = TYPES[type].new(name, about, kwargs).tap { |x| registry.register(x) }
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ module Deimos
2
+ module Status
3
+ class Manager
4
+
5
+ attr_reader :checks
6
+ def checks
7
+ @checks ||= {}
8
+ end
9
+
10
+ def add(name, &block)
11
+ Deimos.logger.info "Status: Reporting #{name} status..."
12
+
13
+ checks[name] = block || Proc.new { true }
14
+ end
15
+
16
+ def run!
17
+ Deimos::Status::Runner.new(checks)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ module Deimos
2
+ module Status
3
+ class Runner
4
+ def initialize(checks)
5
+ @checks = checks.dup
6
+ end
7
+
8
+ def status
9
+ ok? ? :ok : :internal_server_error
10
+ end
11
+
12
+ def body
13
+ completed_checks.to_json
14
+ end
15
+
16
+ private
17
+
18
+ def ok?
19
+ completed_checks.values.all?
20
+ end
21
+
22
+ def completed_checks
23
+ @completed_checks ||= @checks.transform_values do |function|
24
+ Concurrent::Promises.future(&function)
25
+ end.transform_values(&:value)
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -1,3 +1,3 @@
1
1
  module Deimos
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/deimos.rb CHANGED
@@ -1,27 +1,53 @@
1
+ require 'rack'
1
2
  require 'huyegger'
2
3
  require 'sinatra'
4
+ require 'active_support'
3
5
  require 'sinatra/contrib'
6
+ require "sinatra/json"
4
7
  require 'webrick'
5
8
  require 'logger'
9
+ require 'webrick'
10
+ require 'concurrent-ruby'
11
+ require 'prometheus/client'
12
+ require 'prometheus/middleware/exporter'
6
13
 
7
14
  require "deimos/version"
8
15
 
9
16
  require 'deimos/logger'
10
- require 'deimos/manager'
17
+ require 'deimos/status/runner'
18
+ require 'deimos/status/manager'
19
+ require 'deimos/metrics/manager'
11
20
 
12
21
  module Deimos
13
22
  module_function
14
23
 
15
24
  def boot!
16
- require 'deimos/status'
17
- Thread.new { Deimos::Status.run! }
25
+ require 'deimos/endpoints/status'
26
+ require 'deimos/endpoints/metrics'
27
+ Thread.new do
28
+ ::Rack::Handler::WEBrick.run(application, {
29
+ BindAddress: Deimos.config.bind,
30
+ Port: Deimos.config.port,
31
+ Logger: Deimos.logger,
32
+ AccessLog: []
33
+ })
34
+ end
35
+ end
36
+
37
+ def application
38
+ Rack::Builder.new do
39
+ Deimos.middleware.each { |m| use m }
40
+ run Rack::URLMap.new(Deimos.applications)
41
+ end
18
42
  end
19
43
 
20
44
  def config
21
45
  @config ||= OpenStruct.new.tap do |x|
22
- x.log_level = ENV.fetch("LOG_LEVEL", ::Logger::INFO)
23
- x.port = ENV.fetch("PORT", 5000)
24
- x.bind = ENV.fetch("BIND_IP", "0.0.0.0")
46
+ x.log_level = ENV.fetch("LOG_LEVEL", ::Logger::INFO)
47
+ x.port = ENV.fetch("PORT", 5000)
48
+ x.bind = ENV.fetch("BIND_IP", "0.0.0.0")
49
+ x.applications = {}
50
+ x.middleware = []
25
51
  end
26
52
  end
27
53
 
@@ -29,12 +55,23 @@ module Deimos
29
55
  yield(config)
30
56
  end
31
57
 
32
- def manager
33
- @manager ||= Deimos::Manager.new
58
+ def middleware
59
+ @middleware ||= [Rack::Deflater, Deimos::Logger] | config.middleware
60
+ end
61
+
62
+ def applications
63
+ @applications ||= {
64
+ "/status" => Deimos::Endpoints::Status,
65
+ "/metrics" => Deimos::Endpoints::Metrics
66
+ }.merge(config.applications)
67
+ end
68
+
69
+ def status
70
+ @status ||= Deimos::Status::Manager.new
34
71
  end
35
72
 
36
- def add(*args, &block)
37
- manager.add(*args, &block)
73
+ def metrics
74
+ @metrics ||= Deimos::Metrics::Manager.new
38
75
  end
39
76
 
40
77
  def logger
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deimos
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Carlile
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-03-03 00:00:00.000000000 Z
11
+ date: 2019-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -52,6 +52,48 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: concurrent-ruby
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: prometheus-client
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: activesupport
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'
55
97
  - !ruby/object:Gem::Dependency
56
98
  name: bundler
57
99
  requirement: !ruby/object:Gem::Requirement
@@ -127,9 +169,12 @@ files:
127
169
  - bin/setup
128
170
  - deimos.gemspec
129
171
  - lib/deimos.rb
172
+ - lib/deimos/endpoints/metrics.rb
173
+ - lib/deimos/endpoints/status.rb
130
174
  - lib/deimos/logger.rb
131
- - lib/deimos/manager.rb
132
- - lib/deimos/status.rb
175
+ - lib/deimos/metrics/manager.rb
176
+ - lib/deimos/status/manager.rb
177
+ - lib/deimos/status/runner.rb
133
178
  - lib/deimos/version.rb
134
179
  homepage: https://github.com/adamcarlile/deimos
135
180
  licenses:
@@ -1,17 +0,0 @@
1
- module Deimos
2
- class Manager
3
-
4
- def checks
5
- @checks ||= {}
6
- end
7
-
8
- def add(name, &block)
9
- checks[name] = block || Proc.new { true }
10
- end
11
-
12
- def call
13
- checks.transform_values(&:call).to_json
14
- end
15
-
16
- end
17
- end
data/lib/deimos/status.rb DELETED
@@ -1,27 +0,0 @@
1
- require "sinatra/base"
2
- require "sinatra/json"
3
- require 'webrick'
4
-
5
- # Sinatra Applicaiton to present basic health check endpoint
6
- module Deimos
7
- class Status < Sinatra::Application
8
-
9
- set :bind, Deimos.config.bind
10
- set :port, Deimos.config.port
11
- disable :show_exceptions, :traps, :logging
12
-
13
- use Deimos::Logger
14
-
15
- set :quiet, true
16
- set :logger, Deimos.logger
17
- set :server, :webrick
18
- set :server_settings,
19
- Logger: Deimos.logger,
20
- AccessLog: []
21
-
22
- get "/status" do
23
- content_type :json
24
- Deimos.manager.call
25
- end
26
- end
27
- end