bc-prometheus-ruby 0.1.5 → 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: f508f25c190541cb70c122a43df4a1080d806c90c9d40bfcd783dfa8ed98f3b0
4
- data.tar.gz: ce143665ff9e84032601aa8a592c22c374f0939a6b3bd708a8fc8b4d38c47eff
3
+ metadata.gz: 6b7632ea975f9fc41399d9a24624eeeadafc08065aff14ab7825713d0aa21757
4
+ data.tar.gz: daf8ffa859833893d9ab6d70ca06605820c77e47b42382317b5ad7ee2aab65bc
5
5
  SHA512:
6
- metadata.gz: 44464c27e557945ff3f1dfbcf130565a1bf88678d252cbfdf882ecdd9753afb35cf20052a16fe15f25e7e396d63fd6d0139f2b13daf550be78864cccb2bbc778
7
- data.tar.gz: c8392da5b98df9d071af54220d5223a99cd3cb0c52c61bb410c2c88db16143c99621eb62810ce7aa5a7c82d96e2c57d28faf02f061b5e1bde700f2f255642b4f
6
+ metadata.gz: 980d28e7517b613fe7296709638c27d4ef69e93533d7ff81701771651d9dbaac11e23dd08eb22a59edea4d804fb21903c888c5f2f46159fddd9c2b4942097fd4
7
+ data.tar.gz: 367ea000ef4cff7ad04da3fe3701eb890f565a2c259b10e624cf48caa62c9d1c91d3d00f3161702f86dacce4cc38ccf3411faf92881e2dcb984afab7d1a3e634
data/CHANGELOG.md CHANGED
@@ -1,47 +1,53 @@
1
1
  Changelog for the bc-prometheus-ruby gem.
2
2
 
3
- h3. Pending Release
3
+ ### Pending Release
4
4
 
5
- h3. 0.1.5
5
+ ### 0.2.0
6
+
7
+ - Add the ability to pass custom collectors and type collectors to the web instrumenter
8
+ - Add base collector and type collector classes for ease of development of custom integrations
9
+ - Change railtie to after initialization to allow for customization
10
+
11
+ ### 0.1.5
6
12
 
7
13
  - Fix issue where puma collector was not being registered on the server
8
14
 
9
- h3. 0.1.4
15
+ ### 0.1.4
10
16
 
11
17
  - Handle circumstances when before_fork_callbacks is called outside of the web process
12
18
 
13
- h3. 0.1.3
19
+ ### 0.1.3
14
20
 
15
21
  - Move to bigcommerce fork of multitrap to handle IGNORE clauses more cleanly
16
22
 
17
- h3. 0.1.1
23
+ ### 0.1.1
18
24
 
19
25
  - Add multitrap to more cleanly handle trap signals
20
26
  - Use proc in signal handlers for consistent trap handling
21
27
 
22
- h3. 0.1.0
28
+ ### 0.1.0
23
29
 
24
30
  - Replace WEBrick server from PrometheusExporter with Thin server implementation to reduce memory leakage
25
31
  - Utilize NET::HTTP instead of direct sockets to prevent bad socket errors
26
32
 
27
- h3. 0.0.5
33
+ ### 0.0.5
28
34
 
29
35
  - Add resque instrumentation
30
36
 
31
- h3. 0.0.4
37
+ ### 0.0.4
32
38
 
33
39
  - Properly handle SIGINT/SIGTERM to shutdown prometheus exporter
34
40
  - Add process names to log output for easier debugging
35
41
 
36
- h3. 0.0.3
42
+ ### 0.0.3
37
43
 
38
44
  - Add hutch instrumentor for hutch / rmq support
39
45
 
40
- h3. 0.0.2
46
+ ### 0.0.2
41
47
 
42
48
  - Better support for older Rails / Puma versions
43
49
  - Adds basic support for non-Rails applications
44
50
 
45
- h3. 0.0.1
51
+ ### 0.0.1
46
52
 
47
53
  - Initial public release
@@ -30,7 +30,9 @@ require_relative 'prometheus/configuration'
30
30
  require_relative 'prometheus/server'
31
31
  require_relative 'prometheus/client'
32
32
 
33
+ require_relative 'prometheus/collectors/base'
33
34
  require_relative 'prometheus/collectors/resque'
35
+ require_relative 'prometheus/type_collectors/base'
34
36
  require_relative 'prometheus/type_collectors/resque'
35
37
 
36
38
  require_relative 'prometheus/instrumentors/web'
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2019-present, BigCommerce Pty. Ltd. All rights reserved
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11
+ # Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ #
18
+ module Bigcommerce
19
+ module Prometheus
20
+ module Collectors
21
+ ##
22
+ # Base class for collectors
23
+ #
24
+ class Base
25
+ ##
26
+ # Start the collector
27
+ #
28
+ def self.start(*args, &block)
29
+ process_collector = new(*args, &block)
30
+
31
+ stop if @thread
32
+
33
+ @thread = Thread.new do
34
+ Kernel.loop do
35
+ process_collector.run
36
+ end
37
+ end
38
+ end
39
+
40
+ ##
41
+ # Stop the collector
42
+ #
43
+ def self.stop
44
+ t = @thread
45
+ return unless t
46
+
47
+ t.kill
48
+ @thread = nil
49
+ end
50
+
51
+ ##
52
+ # @param [PrometheusExporter::Client] client
53
+ # @param [String] type
54
+ # @param [Integer] frequency
55
+ # @param [Hash] options
56
+ #
57
+ def initialize(client: nil, type: nil, frequency: nil, options: nil)
58
+ @client = client || PrometheusExporter::Client.default
59
+ @type = type || self.class.to_s.downcase.gsub('::', '_').gsub('collector', '')
60
+ @frequency = frequency || 15
61
+ @options = options || {}
62
+ @logger = Bigcommerce::Prometheus.logger
63
+ end
64
+
65
+ ##
66
+ # Run the collector and send stats
67
+ #
68
+ def run
69
+ metrics = { type: @type }
70
+ metrics = collect(metrics)
71
+ @logger.debug "[bigcommerce-prometheus] Pushing #{@type} metrics to type collector: #{metrics.inspect}"
72
+ @client.send_json(metrics)
73
+ rescue StandardError => e
74
+ @logger.error("Prometheus Exporter Failed To Collect #{@type} Stats #{e}")
75
+ ensure
76
+ sleep @frequency
77
+ end
78
+
79
+ ##
80
+ # Collect metrics. This should be overridden in derivative collectors
81
+ #
82
+ # @param [Hash] metrics
83
+ # @return [Hash]
84
+ #
85
+ def collect(metrics = {})
86
+ metrics
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -22,54 +22,21 @@ module Bigcommerce
22
22
  # Collect metrics to push to the server type collector
23
23
  #
24
24
  class Resque
25
- include Bigcommerce::Prometheus::Loggable
26
-
27
- ##
28
- # @param [Bigcommerce::Prometheus::Client] client
29
- # @param [Integer] frequency
30
- #
31
- def initialize(client:, frequency: nil)
32
- @client = client || Bigcommerce::Prometheus.client
33
- @frequency = frequency || 15
34
- end
35
-
36
25
  ##
37
- # Start the collector
26
+ # @param [Hash] metrics
27
+ # @return [Hash]
38
28
  #
39
- def self.start(client: nil, frequency: nil)
40
- collector = new(client: client, frequency: frequency)
41
- Thread.new do
42
- loop do
43
- collector.run
44
- end
45
- end
46
- end
47
-
48
- def run
49
- metric = collect
50
- logger.debug "[bigcommerce-prometheus] Pushing resque metrics to type collector: #{metric.inspect}"
51
- @client.send_json metric
52
- rescue StandardError => e
53
- logger.error "[bigcommerce-prometheus] Failed to collect resque prometheus stats: #{e.message}"
54
- ensure
55
- sleep @frequency
56
- end
57
-
58
- private
59
-
60
- def collect
29
+ def collect(metrics = {})
61
30
  info = ::Resque.info
62
31
 
63
- metric = {}
64
- metric[:type] = 'resque'
65
- metric[:environment] = info[:environment].to_s
66
- metric[:workers_total] = info[:workers].to_i
67
- metric[:jobs_failed_total] = info[:failed].to_i
68
- metric[:jobs_pending_total] = info[:pending].to_i
69
- metric[:jobs_processed_total] = info[:processed].to_i
70
- metric[:queues_total] = info[:queues].to_i
71
- metric[:queues] = queue_sizes
72
- metric
32
+ metrics[:environment] = info[:environment].to_s
33
+ metrics[:workers_total] = info[:workers].to_i
34
+ metrics[:jobs_failed_total] = info[:failed].to_i
35
+ metrics[:jobs_pending_total] = info[:pending].to_i
36
+ metrics[:jobs_processed_total] = info[:processed].to_i
37
+ metrics[:queues_total] = info[:queues].to_i
38
+ metrics[:queues] = queue_sizes
39
+ metrics
73
40
  end
74
41
 
75
42
  def queue_sizes
@@ -34,7 +34,9 @@ module Bigcommerce
34
34
  server_host: '0.0.0.0',
35
35
  server_port: PrometheusExporter::DEFAULT_PORT,
36
36
  server_timeout: PrometheusExporter::DEFAULT_TIMEOUT,
37
- server_prefix: PrometheusExporter::DEFAULT_PREFIX
37
+ server_prefix: PrometheusExporter::DEFAULT_PREFIX,
38
+ web_collectors: [],
39
+ web_type_collectors: []
38
40
  }.freeze
39
41
 
40
42
  attr_accessor *VALID_CONFIG_KEYS.keys
@@ -89,6 +91,7 @@ module Bigcommerce
89
91
 
90
92
  self.puma_process_label = ENV.fetch('PROMETHEUS_PUMA_PROCESS_LABEL', 'web').to_s
91
93
  self.puma_collection_frequency = ENV.fetch('PROMETHEUS_PUMA_COLLECTION_FREQUENCY', 30).to_i
94
+ self.web_type_collectors = []
92
95
  end
93
96
 
94
97
  ##
@@ -31,6 +31,8 @@ module Bigcommerce
31
31
  @server_timeout = Bigcommerce::Prometheus.server_timeout
32
32
  @server_prefix = Bigcommerce::Prometheus.server_prefix
33
33
  @process_name = Bigcommerce::Prometheus.process_name
34
+ @collectors = Bigcommerce::Prometheus.web_collectors || []
35
+ @type_collectors = Bigcommerce::Prometheus.web_type_collectors || []
34
36
  end
35
37
 
36
38
  ##
@@ -65,6 +67,9 @@ module Bigcommerce
65
67
  server.add_type_collector(PrometheusExporter::Server::ActiveRecordCollector.new)
66
68
  server.add_type_collector(PrometheusExporter::Server::WebCollector.new)
67
69
  server.add_type_collector(PrometheusExporter::Server::PumaCollector.new)
70
+ @type_collectors.each do |tc|
71
+ server.add_type_collector(tc)
72
+ end
68
73
  server.start
69
74
  end
70
75
  end
@@ -73,6 +78,7 @@ module Bigcommerce
73
78
  @app.config.after_fork_callbacks = [] unless @app.config.after_fork_callbacks
74
79
  @app.config.after_fork_callbacks << lambda do
75
80
  ::Bigcommerce::Prometheus::Integrations::Puma.start
81
+ @collectors.each(&:start)
76
82
  end
77
83
  end
78
84
 
@@ -22,7 +22,7 @@ module Bigcommerce
22
22
  # Railtie for automatic configuration of Rails environments
23
23
  #
24
24
  class Railtie < ::Rails::Railtie
25
- initializer 'zzz_bigcommerce.prometheus.configure_rails_initialization' do |app|
25
+ config.after_initialize do |app|
26
26
  Bigcommerce::Prometheus::Instrumentors::Web.new(app: app).start
27
27
  end
28
28
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2019-present, BigCommerce Pty. Ltd. All rights reserved
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11
+ # Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ #
18
+ module Bigcommerce
19
+ module Prometheus
20
+ module TypeCollectors
21
+ ##
22
+ # Base type collector class
23
+ #
24
+ class Base < PrometheusExporter::Server::TypeCollector
25
+ attr_reader :type
26
+
27
+ ##
28
+ # @param [String] type
29
+ # @param [Hash] default_labels
30
+ #
31
+ def initialize(type: nil, default_labels: {})
32
+ @type = type || self.class.to_s.downcase.gsub('::', '_').gsub('typecollector', '')
33
+ @default_labels = default_labels || {}
34
+ @metrics = build_metrics
35
+ end
36
+
37
+ ##
38
+ # @return [Array]
39
+ #
40
+ def metrics
41
+ return [] unless @metrics.any?
42
+
43
+ @metrics.values
44
+ end
45
+
46
+ ##
47
+ # @param [Symbol] key
48
+ #
49
+ def metric(key)
50
+ @metrics.fetch(key.to_sym, nil)
51
+ end
52
+
53
+ ##
54
+ # Collect metrics from input data
55
+ #
56
+ # @param [Hash] data
57
+ #
58
+ def collect(data)
59
+ custom_labels = data.fetch('custom_labels', nil)
60
+ labels = custom_labels.nil? ? @default_labels : @default_labels.merge(custom_labels)
61
+ collect_metrics(data: data, labels: labels)
62
+ end
63
+
64
+ private
65
+
66
+ ##
67
+ # Collect metrics. Implementations of translating metrics to observed calls should happen here.
68
+ #
69
+ def collect_metrics(*)
70
+ raise NotImplementedError, 'Must implement collect_metrics'
71
+ end
72
+
73
+ ##
74
+ # Build and return all observable metrics. This should be a hash of symbol keys that map to
75
+ # PrometheusExporter::Metric::Base objects.
76
+ #
77
+ # @return [Hash]
78
+ #
79
+ def build_metrics
80
+ {}
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -21,59 +21,33 @@ module Bigcommerce
21
21
  ##
22
22
  # Collect resque data from collectors and parse them into metrics
23
23
  #
24
- class Resque < PrometheusExporter::Server::TypeCollector
24
+ class Resque < Bigcommerce::Prometheus::TypeCollectors::Base
25
25
  ##
26
26
  # Initialize the collector
27
27
  #
28
- def initialize
29
- @workers_total = PrometheusExporter::Metric::Gauge.new('resque_workers_total', 'Number of active workers')
30
- @jobs_failed_total = PrometheusExporter::Metric::Gauge.new('jobs_failed_total', 'Number of failed jobs')
31
- @jobs_pending_total = PrometheusExporter::Metric::Gauge.new('jobs_pending_total', 'Number of pending jobs')
32
- @jobs_processed_total = PrometheusExporter::Metric::Gauge.new('jobs_processed_total', 'Number of processed jobs')
33
- @queues_total = PrometheusExporter::Metric::Gauge.new('queues_total', 'Number of total queues')
34
- @queue_sizes = PrometheusExporter::Metric::Gauge.new('queue_sizes', 'Size of each queue')
35
- end
36
-
37
- ##
38
- # @return [String]
39
- #
40
- def type
41
- 'resque'
42
- end
43
-
44
- ##
45
- # @return [Array]
46
- #
47
- def metrics
48
- return [] unless @workers_total
49
-
50
- [
51
- @workers_total,
52
- @jobs_failed_total,
53
- @jobs_pending_total,
54
- @jobs_processed_total,
55
- @queues_total,
56
- @queue_sizes
57
- ]
28
+ def build_metrics
29
+ {
30
+ workers_total: PrometheusExporter::Metric::Gauge.new('resque_workers_total', 'Number of active workers'),
31
+ jobs_failed_total: PrometheusExporter::Metric::Gauge.new('jobs_failed_total', 'Number of failed jobs'),
32
+ jobs_pending_total: PrometheusExporter::Metric::Gauge.new('jobs_pending_total', 'Number of pending jobs'),
33
+ jobs_processed_total: PrometheusExporter::Metric::Gauge.new('jobs_processed_total', 'Number of processed jobs'),
34
+ queues_total: PrometheusExporter::Metric::Gauge.new('queues_total', 'Number of total queues'),
35
+ queue_sizes: PrometheusExporter::Metric::Gauge.new('queue_sizes', 'Size of each queue')
36
+ }
58
37
  end
59
38
 
60
39
  ##
61
40
  # Collect resque metrics from input data
62
41
  #
63
- def collect(obj)
64
- default_labels = { environment: obj['environment'] }
65
-
66
- custom_labels = obj['custom_labels']
67
- labels = custom_labels.nil? ? default_labels : default_labels.merge(custom_labels)
68
-
69
- @workers_total.observe(obj['workers_total'], labels)
70
- @jobs_failed_total.observe(obj['jobs_failed_total'], labels)
71
- @jobs_pending_total.observe(obj['jobs_pending_total'], labels)
72
- @jobs_processed_total.observe(obj['jobs_processed_total'], labels)
73
- @queues_total.observe(obj['queues_total'], labels)
74
-
75
- obj['queues'].each do |name, size|
76
- @queue_sizes.observe(size, labels.merge(queue: name))
42
+ def collect_metrics(data:, labels: {})
43
+ metric(:workers_total).observe(obj['workers_total'], labels)
44
+ metric(:jobs_failed_total).observe(obj['jobs_failed_total'], labels)
45
+ metric(:jobs_pending_total).observe(obj['jobs_pending_total'], labels)
46
+ metric(:jobs_processed_total).observe(obj['jobs_processed_total'], labels)
47
+ metric(:queues_total).observe(obj['queues_total'], labels)
48
+
49
+ data['queues'].each do |name, size|
50
+ metric(:queue_sizes).observe(size, labels.merge(queue: name))
77
51
  end
78
52
  end
79
53
  end
@@ -17,6 +17,6 @@
17
17
  #
18
18
  module Bigcommerce
19
19
  module Prometheus
20
- VERSION = '0.1.5'
20
+ VERSION = '0.2.0'
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bc-prometheus-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shaun McCormick
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-12 00:00:00.000000000 Z
11
+ date: 2019-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -177,6 +177,7 @@ files:
177
177
  - bc-prometheus-ruby.gemspec
178
178
  - lib/bigcommerce/prometheus.rb
179
179
  - lib/bigcommerce/prometheus/client.rb
180
+ - lib/bigcommerce/prometheus/collectors/base.rb
180
181
  - lib/bigcommerce/prometheus/collectors/resque.rb
181
182
  - lib/bigcommerce/prometheus/configuration.rb
182
183
  - lib/bigcommerce/prometheus/instrumentors/hutch.rb
@@ -195,6 +196,7 @@ files:
195
196
  - lib/bigcommerce/prometheus/servers/thin/rack_app.rb
196
197
  - lib/bigcommerce/prometheus/servers/thin/server.rb
197
198
  - lib/bigcommerce/prometheus/servers/thin/server_metrics.rb
199
+ - lib/bigcommerce/prometheus/type_collectors/base.rb
198
200
  - lib/bigcommerce/prometheus/type_collectors/resque.rb
199
201
  - lib/bigcommerce/prometheus/version.rb
200
202
  homepage: https://github.com/bigcommerce/bc-prometheus-ruby