yabeda-puma-plugin 0.1.0 → 0.5.0

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: 334f667830d1f10ef87b752b222c0a48868f1e378b03d6d10e45e5d5289fa2ba
4
- data.tar.gz: 764ec2ca14697304378c7cfca7663de24865a362b4664ff42dc4a1ff41f58df7
3
+ metadata.gz: ea655ec09c4edd3459d19356df62760dbb70049b24a0e5ccfb69eed7d501ec7d
4
+ data.tar.gz: 49cab44b0913f02a372473b3e8951a6c880020f3a22970c6f9cdadee7d3935ae
5
5
  SHA512:
6
- metadata.gz: 5048143d5d9c98727de4e70adb78c46b2147d4d698f083035ff42a3783301a0df2255eeb65d3c603748e4de10fb00c8b2e0fe953a541499e6dc9cb05d0b775dc
7
- data.tar.gz: 4052ecba8891d22691f7477b0e5fa1eb433a779385f32184f7467d3543f8ea6350ede81f10925268e9e522d67928d3c497be20d6647e354a2c2f27962b692aec
6
+ metadata.gz: d68acb875bb1d793d0bf6c11f1df91313ec730bcf9984f362829586bdb7810e21b809c60980cf606feec93378957b218d046bb30ced55858f8cc704c3b073380
7
+ data.tar.gz: e8e0c33afd4c639ef3abb25485bf2fb9a3598a288d07033ad64ebffd354335f17558aef856afc18d439fb03cf0c767026c9e348b31de6d1ff1cc91a653ca1c7e
@@ -0,0 +1,54 @@
1
+ name: Build and release gem to RubyGems
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - v*
7
+
8
+ jobs:
9
+ release:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v2
13
+ with:
14
+ fetch-depth: 0 # Fetch current tag as annotated. See https://github.com/actions/checkout/issues/290
15
+ - uses: ruby/setup-ruby@v1
16
+ with:
17
+ ruby-version: 2.7
18
+ - name: "Extract data from tag: version, message, body"
19
+ id: tag
20
+ run: |
21
+ git fetch --tags --force # Really fetch annotated tag. See https://github.com/actions/checkout/issues/290#issuecomment-680260080
22
+ echo ::set-output name=version::${GITHUB_REF#refs/tags/v}
23
+ echo ::set-output name=subject::$(git for-each-ref $GITHUB_REF --format='%(contents:subject)')
24
+ # Multiline body for release. See https://github.community/t/set-output-truncates-multiline-strings/16852/5
25
+ BODY="$(git for-each-ref $GITHUB_REF --format='%(contents:body)')"
26
+ BODY="${BODY//'%'/'%25'}"
27
+ BODY="${BODY//$'\n'/'%0A'}"
28
+ BODY="${BODY//$'\r'/'%0D'}"
29
+ echo "::set-output name=body::$BODY"
30
+ - name: Build gem
31
+ run: gem build
32
+ - name: Check version
33
+ run: ls yabeda-puma-plugin-${{ steps.tag.outputs.version }}.gem
34
+ - name: Create Release
35
+ id: create_release
36
+ uses: actions/create-release@v1
37
+ env:
38
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39
+ with:
40
+ tag_name: ${{ github.ref }}
41
+ release_name: ${{ steps.tag.outputs.subject }}
42
+ body: ${{ steps.tag.outputs.body }}
43
+ draft: false
44
+ prerelease: false
45
+ - name: Upload Release Asset
46
+ id: upload-release-asset
47
+ uses: actions/upload-release-asset@v1
48
+ env:
49
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
50
+ with:
51
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
52
+ asset_path: yabeda-puma-plugin-${{ steps.tag.outputs.version }}.gem
53
+ asset_name: yabeda-puma-plugin-${{ steps.tag.outputs.version }}.gem
54
+ asset_content_type: application/x-tar
@@ -0,0 +1,44 @@
1
+ name: Run tests
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - '**'
8
+ tags-ignore:
9
+ - 'v*'
10
+
11
+ jobs:
12
+ test:
13
+ name: "Run tests"
14
+ if: "! contains(toJSON(github.event.commits.latest.message), '[ci skip]')"
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ include:
20
+ - ruby: 2.7
21
+ - ruby: 2.6
22
+ - ruby: 2.5
23
+ container:
24
+ image: ruby:${{ matrix.ruby }}
25
+ env:
26
+ CI: true
27
+ steps:
28
+ - uses: actions/checkout@v2
29
+ - uses: actions/cache@v2
30
+ with:
31
+ path: vendor/bundle
32
+ key: bundle-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}-${{ hashFiles('**/Gemfile') }}
33
+ restore-keys: |
34
+ bundle-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}-${{ hashFiles('**/Gemfile') }}
35
+ bundle-${{ matrix.ruby }}-
36
+ - name: Upgrade Bundler to 2.0 (for older Rubies)
37
+ run: gem install bundler -v '~> 2.0'
38
+ - name: Bundle install
39
+ run: |
40
+ bundle config path vendor/bundle
41
+ bundle install
42
+ bundle update
43
+ - name: Run RSpec
44
+ run: bundle exec rspec
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- <a href="https://amplifr.com/?utm_source=uibook">
1
+ <a href="https://amplifr.com/?utm_source=yabeda-puma-plugin">
2
2
  <img width="100" height="140" align="right"
3
3
  alt="Sponsored by Amplifr" src="https://amplifr-direct.s3-eu-west-1.amazonaws.com/social_images/image/37b580d9-3668-4005-8d5a-137de3a3e77c.png" />
4
4
  </a>
@@ -14,7 +14,7 @@ Works as the Puma plugin and provides following metrics:
14
14
  - `puma_booted_workers` - the number of booted puma workers
15
15
  - `puma_old_workers` - the number of old puma worker
16
16
 
17
- Segmented by the worker:
17
+ Segmented by the worker (index of the worker):
18
18
  - `puma_pool_capacity` - the capacity of each worker: the number of requests that the server is capable of taking right now. More details are [here](https://github.com/puma/puma/blob/0f8b10737e36fc24cdd572f76a739659b5fad9cb/lib/puma/server.rb#L167).
19
19
  - `puma_running` - the number of running threads (spawned threads) for any puma worker
20
20
  - `puma_max_threads` - preconfigured maximum number of worker threads
@@ -25,7 +25,7 @@ Segmented by the worker:
25
25
  Add this line to your application's Gemfile:
26
26
 
27
27
  ```ruby
28
- gem 'yabeda-puma'
28
+ gem 'yabeda-puma-plugin'
29
29
  ```
30
30
 
31
31
  And then execute:
@@ -34,6 +34,8 @@ And then execute:
34
34
 
35
35
  ## Usage
36
36
 
37
+ ### Collecting metrics
38
+
37
39
  Add those 2 lines of code to your `config/puma.rb` file:
38
40
  ```ruby
39
41
  activate_control_app
@@ -41,6 +43,52 @@ plugin :yabeda
41
43
  ```
42
44
  It will activate default puma control application working over the unix socket, and runs the `yabeda` puma plugin, for registering and collecting the metrics.
43
45
 
46
+ ### Exposing metrics
47
+
48
+ Some monitoring system agents (like NewRelic or DataDog) will send metrics automatically in the background. But for some of monitoring systems (like Prometheus) you have to explicitly set up metrics export.
49
+
50
+ #### Prometheus
51
+
52
+ ##### On the same endpoint with your application
53
+
54
+ For non-Rails applications place following line in your `config.ru` _before_ running your application:
55
+
56
+ ```ruby
57
+ use Yabeda::Prometheus::Exporter, path: "/metrics"
58
+ ```
59
+
60
+ In Ruby on Rails applications you can add following line in `config/routes.rb` instead:
61
+
62
+ ```ruby
63
+ mount Yabeda::Prometheus::Exporter => "/metrics"
64
+ ```
65
+
66
+ In both cases your Puma instance metrics (along with your application metrics) will be available at `/metrics` endpoint.
67
+
68
+ ##### On different port
69
+
70
+ Sometimes you don't want to expose metrics publicly for security reasons. For that case prometheus exporter plugin is bundled with this gem.
71
+
72
+ Don't forget to add either `yabeda-prometheus` or `yabeda-prometheus-mmap` gem into your `Gemfile`!
73
+
74
+ Add this plugin into your `config/puma.rb`:
75
+
76
+ ```ruby
77
+ plugin :yabeda_prometheus
78
+ ```
79
+
80
+ By default metrics will be available at `http://0.0.0.0:9394/metrics`.
81
+
82
+ Bind host, port, and path can be controlled either by config file option `prometheus_exporter_url`:
83
+
84
+ ```ruby
85
+ # config/puma.rb
86
+ prometheus_exporter_url "tcp://127.0.0.1:9395/shmetrics"
87
+ ```
88
+
89
+ Or by environment variables `PROMETHEUS_EXPORTER_URL`, `PROMETHEUS_EXPORTER_BIND`, `PROMETHEUS_EXPORTER_PORT`, and `PROMETHEUS_EXPORTER_PATH` (takes precedence over configuration option).
90
+
91
+
44
92
  ## Details
45
93
 
46
94
  In accordance with the [architecture](https://github.com/puma/puma/blob/master/docs/architecture.md) of the puma web server lets look how it works:
@@ -84,7 +132,7 @@ docker-compose run app bundle exec rspec
84
132
 
85
133
  ## Contributing
86
134
 
87
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/yabeda-puma.
135
+ Bug reports and pull requests are welcome on GitHub at https://github.com/yabeda-rb/yabeda-puma-plugin.
88
136
 
89
137
  ## License
90
138
 
Binary file
@@ -14,14 +14,14 @@ Puma::Plugin.create do
14
14
 
15
15
  Yabeda.configure do
16
16
  group :puma
17
-
18
- gauge :backlog, comment: 'Number of established but unaccepted connections in the backlog'
19
- gauge :running, comment: 'Number of running worker threads'
20
- gauge :pool_capacity, comment: 'Number of allocatable worker threads'
21
- gauge :max_threads, comment: 'Maximum number of worker threads'
22
- gauge :workers, comment: 'Number of configured workers'
17
+
18
+ gauge :backlog, tags: %i[index], comment: 'Number of established but unaccepted connections in the backlog'
19
+ gauge :running, tags: %i[index], comment: 'Number of running worker threads'
20
+ gauge :pool_capacity, tags: %i[index], comment: 'Number of allocatable worker threads'
21
+ gauge :max_threads, tags: %i[index], comment: 'Maximum number of worker threads'
23
22
 
24
23
  if clustered
24
+ gauge :workers, comment: 'Number of configured workers'
25
25
  gauge :booted_workers, comment: 'Number of booted workers'
26
26
  gauge :old_workers, comment: 'Number of old workers'
27
27
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'yabeda/prometheus/exporter'
5
+ rescue LoadError
6
+ raise LoadError, 'Please add either yabeda-prometheus or yabeda-prometheus-mmap gem into your Gemfile to use yabeda/prometheus/exporter!'
7
+ end
8
+
9
+ require 'uri'
10
+ require 'rack'
11
+
12
+ module Puma
13
+ class DSL
14
+ def prometheus_exporter_url(uri)
15
+ @options[:prometheus_exporter_url] = uri
16
+ end
17
+ end
18
+ end
19
+
20
+ Puma::Plugin.create do
21
+ def start(launcher)
22
+ events = launcher.events
23
+
24
+ uri = launcher.options.fetch(:prometheus_exporter_url, 'tcp://0.0.0.0:9394/metrics')
25
+ uri = URI.parse(ENV.fetch('PROMETHEUS_EXPORTER_URL', uri))
26
+ host = ENV.fetch('PROMETHEUS_EXPORTER_BIND', uri.host)
27
+ port = Integer(ENV.fetch('PROMETHEUS_EXPORTER_PORT', uri.port))
28
+ path = ENV.fetch('PROMETHEUS_EXPORTER_PATH', uri.path)
29
+
30
+ events.on_booted do
31
+ app = Yabeda::Prometheus::Exporter.rack_app(Yabeda::Prometheus::Exporter, path: path)
32
+
33
+ metrics = Puma::Server.new app, events
34
+ metrics.min_threads = 0
35
+ metrics.max_threads = 1
36
+
37
+ events.log "* Starting Yabeda Prometheus metrics exporter on http://#{host}:#{port}#{path}"
38
+ metrics.add_tcp_listener host, port
39
+
40
+ events.register(:state) do |state|
41
+ if %i[halt restart stop].include?(state)
42
+ metrics.stop(true) unless metrics.shutting_down?
43
+ end
44
+ end
45
+
46
+ metrics.run
47
+ end
48
+ end
49
+ end
@@ -2,8 +2,8 @@ module Yabeda
2
2
  module Puma
3
3
  module Plugin
4
4
  module Statistics
5
- METRICS = [:backlog, :running, :pool_capacity, :max_threads, :workers]
6
- CLUSTERED_METRICS = [:booted_workers, :old_workers]
5
+ METRICS = [:backlog, :running, :pool_capacity, :max_threads]
6
+ CLUSTERED_METRICS = [:booted_workers, :old_workers, :workers]
7
7
  end
8
8
  end
9
9
  end
@@ -7,13 +7,29 @@ module Yabeda
7
7
  module Statistics
8
8
  class Fetcher
9
9
  def self.call
10
- body = Socket.unix(Yabeda::Puma::Plugin.control_url.gsub("unix://", '')) do |socket|
11
- socket << "GET /stats?token=#{Yabeda::Puma::Plugin.control_auth_token} HTTP/1.0\r\n\r\n"
12
- socket.read
10
+ control_url = Yabeda::Puma::Plugin.control_url
11
+
12
+ body = if control_url.start_with? "unix://"
13
+ path = control_url.gsub("unix://", '')
14
+ Socket.unix(path, &socket_block)
15
+ elsif control_url.start_with? "tcp://"
16
+ host, port = control_url.match(/^tcp:\/\/([a-z0-9\-._~%]+):([0-9]+)/).captures
17
+ Socket.tcp(host, port, &socket_block)
18
+ else
19
+ raise ArgumentError.new("Unknown puma control url type #{control_url}")
13
20
  end
14
21
 
15
22
  JSON.parse(body.split("\n").last)
16
23
  end
24
+
25
+ private
26
+
27
+ def self.socket_block
28
+ Proc.new do |s|
29
+ s << "GET /stats?token=#{Yabeda::Puma::Plugin.control_auth_token} HTTP/1.0\r\n\r\n"
30
+ s.read
31
+ end
32
+ end
17
33
  end
18
34
  end
19
35
  end
@@ -13,21 +13,33 @@ module Yabeda
13
13
  end
14
14
 
15
15
  def call
16
- Array.new.tap { |result| parse(data, result) }
16
+ [].tap { |result| parse(data, {}, result) }
17
17
  end
18
18
 
19
19
  private
20
20
 
21
- def parse(stats, labels = {}, result)
21
+ def parse(stats, labels, result)
22
22
  stats.each do |key, value|
23
- value.each { |s| parse(s, labels.merge(index: s['index']), result) } if key == 'worker_status'
24
- parse(value, labels, result) if key == 'last_status'
25
- result << {name: key, value: value, labels: labels} if metric?(key)
23
+ case key
24
+ when 'worker_status'
25
+ value.each { |s| parse(s, labels.merge(index: s['index']), result) }
26
+ when 'last_status'
27
+ parse(value, labels, result)
28
+ else
29
+ next unless metric?(key)
30
+
31
+ l = clustered_metric?(key) ? labels : { index: 0 }.merge(labels)
32
+ result << { name: key, value: value, labels: l }
33
+ end
26
34
  end
27
35
  end
28
36
 
29
37
  def metric?(name)
30
- Statistics::METRICS.include?(name.to_sym) || (Statistics::CLUSTERED_METRICS.include?(name.to_sym) && clustered)
38
+ Statistics::METRICS.include?(name.to_sym) || clustered_metric?(name)
39
+ end
40
+
41
+ def clustered_metric?(name)
42
+ clustered && Statistics::CLUSTERED_METRICS.include?(name.to_sym)
31
43
  end
32
44
  end
33
45
  end
@@ -1,7 +1,7 @@
1
1
  module Yabeda
2
2
  module Puma
3
3
  module Plugin
4
- VERSION = "0.1.0"
4
+ VERSION = "0.5.0"
5
5
  end
6
6
  end
7
7
  end
@@ -21,12 +21,12 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- spec.add_runtime_dependency "yabeda"
24
+ spec.add_runtime_dependency "yabeda", "~> 0.2"
25
25
  spec.add_runtime_dependency "puma"
26
26
  spec.add_runtime_dependency "json"
27
27
 
28
28
  spec.add_development_dependency "bundler"
29
- spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "rake", "~> 13.0"
30
30
  spec.add_development_dependency "rspec", "~> 3.0"
31
31
  spec.add_development_dependency "rack"
32
32
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yabeda-puma-plugin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Salahutdinov Dmitry
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-04-01 00:00:00.000000000 Z
11
+ date: 2020-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: yabeda
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '0.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '0.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: puma
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '10.0'
75
+ version: '13.0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '10.0'
82
+ version: '13.0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -115,9 +115,10 @@ executables: []
115
115
  extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
+ - ".github/workflows/build-release.yml"
119
+ - ".github/workflows/test.yml"
118
120
  - ".gitignore"
119
121
  - ".rspec"
120
- - ".travis.yml"
121
122
  - Gemfile
122
123
  - LICENSE
123
124
  - LICENSE.txt
@@ -129,6 +130,7 @@ files:
129
130
  - docs/diagram.png
130
131
  - docs/grafana.png
131
132
  - lib/puma/plugin/yabeda.rb
133
+ - lib/puma/plugin/yabeda_prometheus.rb
132
134
  - lib/yabeda/puma/plugin.rb
133
135
  - lib/yabeda/puma/plugin/statistics.rb
134
136
  - lib/yabeda/puma/plugin/statistics/fetcher.rb
@@ -154,8 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
156
  - !ruby/object:Gem::Version
155
157
  version: '0'
156
158
  requirements: []
157
- rubyforge_project:
158
- rubygems_version: 2.7.7
159
+ rubygems_version: 3.1.4
159
160
  signing_key:
160
161
  specification_version: 4
161
162
  summary: Puma web server plugin for collecting puma metrics with Yabeda framework.
@@ -1,9 +0,0 @@
1
- sudo: require
2
- services:
3
- - docker
4
-
5
- before_script:
6
- - unset BUNDLE_GEMFILE
7
- - docker-compose run app bundle install
8
- script:
9
- - docker-compose run app bundle exec rspec