bc-prometheus-ruby 0.8.0 → 0.8.1
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 +4 -4
- data/bc-prometheus-ruby.gemspec +2 -0
- data/lib/bigcommerce/prometheus/client.rb +8 -0
- data/lib/bigcommerce/prometheus/configuration.rb +2 -1
- data/lib/bigcommerce/prometheus/instrumentors/hutch.rb +2 -0
- data/lib/bigcommerce/prometheus/instrumentors/web.rb +2 -0
- data/lib/bigcommerce/prometheus/integrations/active_record.rb +115 -0
- data/lib/bigcommerce/prometheus/integrations/puma.rb +1 -1
- data/lib/bigcommerce/prometheus/servers/puma/controllers/metrics_controller.rb +2 -0
- data/lib/bigcommerce/prometheus/type_collectors/active_record.rb +53 -0
- data/lib/bigcommerce/prometheus/version.rb +1 -1
- data/lib/bigcommerce/prometheus.rb +2 -0
- metadata +19 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a7a2ca2f975be9d346e217c4a13e4ca702a573889383c43292094f66aa82c562
|
|
4
|
+
data.tar.gz: 2724f8826c1ee9d668357676834f15dc24836ed1d05337f7b217133119fb4e26
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c1e174d621f686a1d32b4db922d4409f1cdffa1f0afd2c6f6b853f51978150b53be7ae3237fc0a1b8daf139423c98f0186ad317345b16a070eb0824f00249ef3
|
|
7
|
+
data.tar.gz: 8c215d4cb4349041e082bedaee24580afbc4f567bf6e8af848c0e00afa42b228a982790f6d21acfdbf6023de82aaa9cfecc2e55b625730e75102443c1e946ef1
|
data/bc-prometheus-ruby.gemspec
CHANGED
|
@@ -69,6 +69,14 @@ module Bigcommerce
|
|
|
69
69
|
URI("http://#{@host}:#{@port}#{path}")
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
+
##
|
|
73
|
+
# @param [String] str
|
|
74
|
+
def send(str)
|
|
75
|
+
return unless Bigcommerce::Prometheus.enabled
|
|
76
|
+
|
|
77
|
+
super
|
|
78
|
+
end
|
|
79
|
+
|
|
72
80
|
##
|
|
73
81
|
# Process the current queue and flush to the collector
|
|
74
82
|
#
|
|
@@ -54,7 +54,8 @@ module Bigcommerce
|
|
|
54
54
|
web_type_collectors: [],
|
|
55
55
|
|
|
56
56
|
# Additional configuration
|
|
57
|
-
railtie_disabled: ENV.fetch('PROMETHEUS_DISABLE_RAILTIE', 0).to_i.positive
|
|
57
|
+
railtie_disabled: ENV.fetch('PROMETHEUS_DISABLE_RAILTIE', 0).to_i.positive?,
|
|
58
|
+
active_record_enabled: ENV.fetch('PROMETHEUS_ACTIVE_RECORD_ENABLED', 1).to_i.positive?
|
|
58
59
|
}.freeze
|
|
59
60
|
|
|
60
61
|
attr_accessor *VALID_CONFIG_KEYS.keys
|
|
@@ -46,10 +46,12 @@ module Bigcommerce
|
|
|
46
46
|
|
|
47
47
|
server.add_type_collector(PrometheusExporter::Server::ActiveRecordCollector.new)
|
|
48
48
|
server.add_type_collector(PrometheusExporter::Server::HutchCollector.new)
|
|
49
|
+
::Bigcommerce::Prometheus::Integrations::ActiveRecordSql.register_type_collector(server, process_name: @process_name)
|
|
49
50
|
@type_collectors.each do |tc|
|
|
50
51
|
server.add_type_collector(tc)
|
|
51
52
|
end
|
|
52
53
|
server.start
|
|
54
|
+
::Bigcommerce::Prometheus::Integrations::ActiveRecordSql.start_safe(client: Bigcommerce::Prometheus.client, process_name: @process_name)
|
|
53
55
|
setup_middleware
|
|
54
56
|
rescue StandardError => e
|
|
55
57
|
logger.error "[bigcommerce-prometheus][#{@process_name}] Failed to start hutch instrumentation - #{e.message} - #{e.backtrace[0..4].join("\n")}"
|
|
@@ -67,6 +67,7 @@ module Bigcommerce
|
|
|
67
67
|
server.add_type_collector(PrometheusExporter::Server::ActiveRecordCollector.new)
|
|
68
68
|
server.add_type_collector(PrometheusExporter::Server::WebCollector.new)
|
|
69
69
|
server.add_type_collector(PrometheusExporter::Server::PumaCollector.new)
|
|
70
|
+
::Bigcommerce::Prometheus::Integrations::ActiveRecordSql.register_type_collector(server, process_name: @process_name)
|
|
70
71
|
@type_collectors.each do |tc|
|
|
71
72
|
server.add_type_collector(tc)
|
|
72
73
|
end
|
|
@@ -78,6 +79,7 @@ module Bigcommerce
|
|
|
78
79
|
@app.config.after_fork_callbacks = [] unless @app.config.after_fork_callbacks
|
|
79
80
|
@app.config.after_fork_callbacks << lambda do
|
|
80
81
|
::Bigcommerce::Prometheus::Integrations::Puma.start(client: Bigcommerce::Prometheus.client)
|
|
82
|
+
::Bigcommerce::Prometheus::Integrations::ActiveRecordSql.start_safe(client: Bigcommerce::Prometheus.client, process_name: @process_name)
|
|
81
83
|
@collectors.each(&:start)
|
|
82
84
|
rescue StandardError => e
|
|
83
85
|
logger.error "[bigcommerce-prometheus][#{@process_name}] Failed to start web prometheus middleware after fork: #{e.message}"
|
|
@@ -0,0 +1,115 @@
|
|
|
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 Integrations
|
|
21
|
+
##
|
|
22
|
+
# Subscribes to ActiveSupport sql.active_record notifications and pushes a per-operation
|
|
23
|
+
# SQL query duration histogram to the Prometheus exporter.
|
|
24
|
+
#
|
|
25
|
+
class ActiveRecordSql
|
|
26
|
+
IGNORED_NAMES = %w[SCHEMA CACHE].freeze
|
|
27
|
+
TYPE = 'active_record_sql'
|
|
28
|
+
|
|
29
|
+
# Idempotent: returns the same instance on repeated calls within a process,
|
|
30
|
+
# so calling .start more than once (e.g. from both the gem's instrumentor and a
|
|
31
|
+
# consuming app's initializer) does not register duplicate subscribers and
|
|
32
|
+
# double-count every SQL query.
|
|
33
|
+
#
|
|
34
|
+
# Noop when ActiveRecord is not loaded so non-Rails consumers (or any process that
|
|
35
|
+
# never loads ActiveRecord) can call this safely.
|
|
36
|
+
def self.start(client: nil)
|
|
37
|
+
return unless active_record_loaded?
|
|
38
|
+
|
|
39
|
+
@start ||= new(client: client || ::Bigcommerce::Prometheus.client).tap(&:subscribe!)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [Boolean] whether ActiveRecord is loaded in the current process.
|
|
43
|
+
def self.active_record_loaded?
|
|
44
|
+
defined?(::ActiveRecord) ? true : false
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Wrapper for instrumentor wiring: registers the AR SQL type collector on the given server,
|
|
48
|
+
# gated on the active_record_enabled config flag, and swallows errors so an additive
|
|
49
|
+
# feature failure cannot take down core instrumentation.
|
|
50
|
+
def self.register_type_collector(server, process_name: nil)
|
|
51
|
+
return unless ::Bigcommerce::Prometheus.active_record_enabled
|
|
52
|
+
|
|
53
|
+
server.add_type_collector(::Bigcommerce::Prometheus::TypeCollectors::ActiveRecordSql.new)
|
|
54
|
+
rescue StandardError => e
|
|
55
|
+
log_warn(process_name, "Failed to register ActiveRecord type collector: #{e.message}")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Wrapper for instrumentor wiring: starts the AR integration, gated on the
|
|
59
|
+
# active_record_enabled config flag, and swallows errors so an additive feature
|
|
60
|
+
# failure cannot take down core instrumentation.
|
|
61
|
+
def self.start_safe(client: nil, process_name: nil)
|
|
62
|
+
return unless ::Bigcommerce::Prometheus.active_record_enabled
|
|
63
|
+
|
|
64
|
+
start(client: client)
|
|
65
|
+
rescue StandardError => e
|
|
66
|
+
log_warn(process_name, "Failed to start ActiveRecord integration: #{e.message}")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def self.log_warn(process_name, message)
|
|
70
|
+
process_name ||= ::Bigcommerce::Prometheus.process_name
|
|
71
|
+
::Bigcommerce::Prometheus.logger&.warn("[bigcommerce-prometheus][#{process_name}] #{message}")
|
|
72
|
+
end
|
|
73
|
+
private_class_method :log_warn
|
|
74
|
+
|
|
75
|
+
def initialize(client:)
|
|
76
|
+
@client = client
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def subscribe!
|
|
80
|
+
ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
|
|
81
|
+
call(ActiveSupport::Notifications::Event.new(*args))
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def call(event)
|
|
86
|
+
return if IGNORED_NAMES.include?(event.payload[:name])
|
|
87
|
+
|
|
88
|
+
@client.send_json(
|
|
89
|
+
type: TYPE,
|
|
90
|
+
duration_seconds: event.duration / 1000.0,
|
|
91
|
+
custom_labels: { operation: classify(event.payload[:sql]) }
|
|
92
|
+
)
|
|
93
|
+
rescue StandardError
|
|
94
|
+
# Never let metric instrumentation propagate into the request path.
|
|
95
|
+
nil
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def classify(sql)
|
|
101
|
+
return 'other' if sql.nil?
|
|
102
|
+
|
|
103
|
+
first_token = sql.lstrip.split(/\s+/, 2).first&.upcase
|
|
104
|
+
case first_token
|
|
105
|
+
when 'SELECT' then 'select'
|
|
106
|
+
when 'INSERT' then 'insert'
|
|
107
|
+
when 'UPDATE' then 'update'
|
|
108
|
+
when 'DELETE' then 'delete'
|
|
109
|
+
else 'other'
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -51,7 +51,7 @@ module Bigcommerce
|
|
|
51
51
|
# @return [Boolean]
|
|
52
52
|
#
|
|
53
53
|
def self.active_record_enabled?
|
|
54
|
-
defined?(ActiveRecord) && ::ActiveRecord::Base.connection_pool.respond_to?(:stat)
|
|
54
|
+
defined?(::ActiveRecord) && ::ActiveRecord::Base.connection_pool.respond_to?(:stat)
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
##
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
# Render-side counterpart to Integrations::ActiveRecordSql. Aggregates per-operation
|
|
23
|
+
# SQL query duration into a Prometheus Histogram exposed at /metrics.
|
|
24
|
+
#
|
|
25
|
+
class ActiveRecordSql < Bigcommerce::Prometheus::TypeCollectors::Base
|
|
26
|
+
def initialize(
|
|
27
|
+
default_labels: {},
|
|
28
|
+
buckets: [0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 20, 30, 60]
|
|
29
|
+
)
|
|
30
|
+
@buckets = buckets
|
|
31
|
+
super(type: Bigcommerce::Prometheus::Integrations::ActiveRecordSql::TYPE, default_labels: default_labels)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def build_metrics
|
|
35
|
+
{
|
|
36
|
+
sql_query_duration_seconds: PrometheusExporter::Metric::Histogram.new(
|
|
37
|
+
'sql_query_duration_seconds',
|
|
38
|
+
'ActiveRecord SQL query duration in seconds, labeled by operation.',
|
|
39
|
+
buckets: @buckets
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def collect_metrics(data:, labels: {})
|
|
45
|
+
duration = data['duration_seconds']
|
|
46
|
+
return if duration.nil?
|
|
47
|
+
|
|
48
|
+
metric(:sql_query_duration_seconds).observe(duration.to_f, labels)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -35,6 +35,8 @@ require_relative 'prometheus/collectors/base'
|
|
|
35
35
|
require_relative 'prometheus/collectors/resque'
|
|
36
36
|
require_relative 'prometheus/type_collectors/base'
|
|
37
37
|
require_relative 'prometheus/type_collectors/resque'
|
|
38
|
+
require_relative 'prometheus/integrations/active_record'
|
|
39
|
+
require_relative 'prometheus/type_collectors/active_record'
|
|
38
40
|
|
|
39
41
|
require_relative 'prometheus/instrumentors/web'
|
|
40
42
|
require_relative 'prometheus/instrumentors/hutch'
|
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.8.
|
|
4
|
+
version: 0.8.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shaun McCormick
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-05-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bigcommerce-multitrap
|
|
@@ -80,6 +80,20 @@ dependencies:
|
|
|
80
80
|
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '10.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: '6.0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '6.0'
|
|
83
97
|
description: Simple integration of ruby and puma servers with prometheus
|
|
84
98
|
email:
|
|
85
99
|
- shaun.mccormick@bigcommerce.com
|
|
@@ -99,6 +113,7 @@ files:
|
|
|
99
113
|
- lib/bigcommerce/prometheus/instrumentors/hutch.rb
|
|
100
114
|
- lib/bigcommerce/prometheus/instrumentors/resque.rb
|
|
101
115
|
- lib/bigcommerce/prometheus/instrumentors/web.rb
|
|
116
|
+
- lib/bigcommerce/prometheus/integrations/active_record.rb
|
|
102
117
|
- lib/bigcommerce/prometheus/integrations/puma.rb
|
|
103
118
|
- lib/bigcommerce/prometheus/integrations/railtie.rb
|
|
104
119
|
- lib/bigcommerce/prometheus/integrations/resque.rb
|
|
@@ -112,6 +127,7 @@ files:
|
|
|
112
127
|
- lib/bigcommerce/prometheus/servers/puma/rack_app.rb
|
|
113
128
|
- lib/bigcommerce/prometheus/servers/puma/server.rb
|
|
114
129
|
- lib/bigcommerce/prometheus/servers/puma/server_metrics.rb
|
|
130
|
+
- lib/bigcommerce/prometheus/type_collectors/active_record.rb
|
|
115
131
|
- lib/bigcommerce/prometheus/type_collectors/base.rb
|
|
116
132
|
- lib/bigcommerce/prometheus/type_collectors/resque.rb
|
|
117
133
|
- lib/bigcommerce/prometheus/version.rb
|
|
@@ -134,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
134
150
|
- !ruby/object:Gem::Version
|
|
135
151
|
version: '0'
|
|
136
152
|
requirements: []
|
|
137
|
-
rubygems_version: 3.5.
|
|
153
|
+
rubygems_version: 3.5.7
|
|
138
154
|
signing_key:
|
|
139
155
|
specification_version: 4
|
|
140
156
|
summary: Simple integration of ruby and puma servers with prometheus
|