yabeda-activerecord 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0c70f9b0924926fec4e5346d38bc65a9a821260d8904926c88a8584b050c93c7
4
+ data.tar.gz: 60808116a424d5852d037995bd14040c2f0cc758c242faa4a8e4381898b45685
5
+ SHA512:
6
+ metadata.gz: a11ba38c80c349b9ad490b1908a7915fb716b9e01a653ad8553bbdcb3738b46e7af71ad6c764b346097d467cdaa5781c33dddf19c4112e410603e7f611148d90
7
+ data.tar.gz: c31e9c3628b8d19c04b90aaada7bb86f4d9069a75dbde92f5af0ebe7cb4258401efb6939914e5b6cfd77951ec168c239b370f820aa5b1d646fa5ae5ea2f809dc
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,28 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.5
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
14
+
15
+ Style/TrailingCommaInHashLiteral:
16
+ EnforcedStyleForMultiline: consistent_comma
17
+
18
+ Style/TrailingCommaInArguments:
19
+ EnforcedStyleForMultiline: consistent_comma
20
+
21
+ Style/TrailingCommaInArrayLiteral:
22
+ EnforcedStyleForMultiline: consistent_comma
23
+
24
+ Metrics/BlockLength:
25
+ Enabled: false
26
+
27
+ Bundler/DuplicatedGem:
28
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ ## Unreleased
2
+
3
+ ## 0.1.0 - 2022-05-27
4
+
5
+ - Initial release: query performance metrics and connection pool stats. [@Envek][]
6
+
7
+ [@Envek]: https://github.com/Envek/ "Andrey Novikov"
data/Gemfile ADDED
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in yabeda-activerecord.gemspec
6
+ gemspec
7
+
8
+ yabeda_version = ENV.fetch("YABEDA_VERSION", "~> 0.11")
9
+
10
+ case yabeda_version
11
+ when "HEAD"
12
+ gem "yabeda", git: "https://github.com/yabeda-rb/yabeda"
13
+ else
14
+ yabeda_version = "~> #{yabeda_version}.0" if yabeda_version.match?(/^\d+\.\d+$/)
15
+ gem "yabeda", yabeda_version
16
+ end
17
+
18
+ activerecord_version = ENV.fetch("ACTIVERECORD_VERSION", "~> 7.0")
19
+ case activerecord_version
20
+ when "HEAD"
21
+ git "https://github.com/rails/rails.git" do
22
+ gem "activerecord"
23
+ gem "rails"
24
+ end
25
+ else
26
+ activerecord_version = "~> #{activerecord_version}.0" if activerecord_version.match?(/^\d+\.\d+$/)
27
+ gem "activerecord", activerecord_version
28
+ end
29
+
30
+ gem "sqlite3"
31
+
32
+ gem "rake", "~> 13.0"
33
+
34
+ gem "rspec", "~> 3.0"
35
+
36
+ gem "rubocop", "~> 1.30"
37
+
38
+ gem "debug"
data/Gemfile.lock ADDED
@@ -0,0 +1,95 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ yabeda-activerecord (0.1.0)
5
+ activerecord (>= 6.0)
6
+ yabeda (~> 0.6)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activemodel (7.0.3)
12
+ activesupport (= 7.0.3)
13
+ activerecord (7.0.3)
14
+ activemodel (= 7.0.3)
15
+ activesupport (= 7.0.3)
16
+ activesupport (7.0.3)
17
+ concurrent-ruby (~> 1.0, >= 1.0.2)
18
+ i18n (>= 1.6, < 2)
19
+ minitest (>= 5.1)
20
+ tzinfo (~> 2.0)
21
+ anyway_config (2.3.0)
22
+ ruby-next-core (>= 0.14.0)
23
+ ast (2.4.2)
24
+ concurrent-ruby (1.1.10)
25
+ debug (1.5.0)
26
+ irb (>= 1.3.6)
27
+ reline (>= 0.2.7)
28
+ diff-lcs (1.5.0)
29
+ dry-initializer (3.1.1)
30
+ i18n (1.10.0)
31
+ concurrent-ruby (~> 1.0)
32
+ io-console (0.5.11)
33
+ irb (1.4.1)
34
+ reline (>= 0.3.0)
35
+ minitest (5.15.0)
36
+ parallel (1.22.1)
37
+ parser (3.1.2.0)
38
+ ast (~> 2.4.1)
39
+ rainbow (3.1.1)
40
+ rake (13.0.6)
41
+ regexp_parser (2.4.0)
42
+ reline (0.3.1)
43
+ io-console (~> 0.5)
44
+ rexml (3.2.5)
45
+ rspec (3.11.0)
46
+ rspec-core (~> 3.11.0)
47
+ rspec-expectations (~> 3.11.0)
48
+ rspec-mocks (~> 3.11.0)
49
+ rspec-core (3.11.0)
50
+ rspec-support (~> 3.11.0)
51
+ rspec-expectations (3.11.0)
52
+ diff-lcs (>= 1.2.0, < 2.0)
53
+ rspec-support (~> 3.11.0)
54
+ rspec-mocks (3.11.1)
55
+ diff-lcs (>= 1.2.0, < 2.0)
56
+ rspec-support (~> 3.11.0)
57
+ rspec-support (3.11.0)
58
+ rubocop (1.30.0)
59
+ parallel (~> 1.10)
60
+ parser (>= 3.1.0.0)
61
+ rainbow (>= 2.2.2, < 4.0)
62
+ regexp_parser (>= 1.8, < 3.0)
63
+ rexml (>= 3.2.5, < 4.0)
64
+ rubocop-ast (>= 1.18.0, < 2.0)
65
+ ruby-progressbar (~> 1.7)
66
+ unicode-display_width (>= 1.4.0, < 3.0)
67
+ rubocop-ast (1.18.0)
68
+ parser (>= 3.1.1.0)
69
+ ruby-next-core (0.15.1)
70
+ ruby-progressbar (1.11.0)
71
+ sqlite3 (1.4.2)
72
+ tzinfo (2.0.4)
73
+ concurrent-ruby (~> 1.0)
74
+ unicode-display_width (2.1.0)
75
+ yabeda (0.11.0)
76
+ anyway_config (>= 1.0, < 3)
77
+ concurrent-ruby
78
+ dry-initializer
79
+
80
+ PLATFORMS
81
+ ruby
82
+ x86_64-linux
83
+
84
+ DEPENDENCIES
85
+ activerecord (~> 7.0)
86
+ debug
87
+ rake (~> 13.0)
88
+ rspec (~> 3.0)
89
+ rubocop (~> 1.30)
90
+ sqlite3
91
+ yabeda (~> 0.11)
92
+ yabeda-activerecord!
93
+
94
+ BUNDLED WITH
95
+ 2.3.14
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Andrey Novikov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # ![`Yabeda::ActiveRecord`](./yabeda-activerecord-logo.png)
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/yabeda-activerecord.svg)](https://rubygems.org/gems/yabeda-activerecord)
4
+ [![Tests status](https://github.com/yabeda-rb/yabeda-activerecord/actions/workflows/test.yml/badge.svg)](https://github.com/yabeda-rb/yabeda-activerecord/actions/workflows/test.yml)
5
+
6
+ [Yabeda] plugin to collect essential metrics for database query performance and connection pool stats.
7
+
8
+ <a href="https://evilmartians.com/?utm_source=yabeda-activerecord">
9
+ <picture>
10
+ <source media="(prefers-color-scheme: dark)" srcset="https://evilmartians.com/badges/sponsored-by-evil-martians_v2.0_for-dark-bg@2x.png">
11
+ <img alt="Sponsored by Evil Martians" src="https://evilmartians.com/badges/sponsored-by-evil-martians_v2.0@2x.png" width="236" height="54">
12
+ </picture>
13
+ </a>
14
+
15
+ ## Installation
16
+
17
+ Install the gem and add to the application's Gemfile by executing:
18
+
19
+ $ bundle add yabeda-activerecord
20
+
21
+ Launch/restart your application and that's it: metrics are being collected.
22
+
23
+ To expose metrics Don't forget to also add one of [Yabeda adapters](https://github.com/yabeda-rb/yabeda#available-monitoring-system-adapters) to your Gemfile.
24
+
25
+ ## Metrics
26
+
27
+ ### Query performance
28
+ | Metric | Type | Tags | Description |
29
+ |-------------------|-------------|-----------------------------|--------------------------------------------------------------------|
30
+ | `queries_total` | counter | config, kind, cached, async | Total number of SQL queries issued by application via ActiveRecord |
31
+ | `query_duration` | histogram | config, kind, cached, async | Duration for SQL queries generated by ActiveRecord |
32
+
33
+ ### Connection pool stats
34
+
35
+ | Metric | Type | Tags | Description |
36
+ |------------------------------------|-------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
37
+ | `connection_pool_size` | gauge | config | Connection pool size |
38
+ | `connection_pool_connections` | gauge | config | Total number of connections currently created in the pool (sum of busy, dead, and idle). |
39
+ | `connection_pool_busy` | gauge | config | Number of connections that has been checked out by some thread and are in use now. |
40
+ | `connection_pool_dead` | gauge | config | Number of lost connections for the pool. A lost connection can occur if a programmer forgets to checkin a connection at the end of a thread or a thread dies unexpectedly. |
41
+ | `connection_pool_idle` | gauge | config | Number of free connections, that are available for checkout. |
42
+ | `connection_pool_waiting` | gauge | config | Number of threads waiting for a connection to become available for checkout. |
43
+ | `connection_pool_checkout_timeout` | gauge | config | Checkout waiting timeout in seconds |
44
+
45
+ ### Tags
46
+
47
+ - `config` — database configuration name in the `database.yml`
48
+ - `kind` — query kind, usually referring to action over model. E.g. `Post Load`
49
+ - `cached` — `true` if query wasn't executed against the database, results was retrieved from in-memory cache.
50
+ - `async` — `true` if query was loaded in background via [`load_async`](https://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-load_async)
51
+
52
+ ## Development
53
+
54
+ 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.
55
+
56
+ To install this gem onto your local machine, run `bundle exec rake install`.
57
+
58
+
59
+ Bug reports and pull requests are welcome on GitHub at https://github.com/yabeda-rb/yabeda-activerecord.
60
+
61
+ ### Releasing
62
+
63
+ 1. Bump version number in `lib/yabeda/activerecord/version.rb`
64
+
65
+ In case of pre-releases keep in mind [rubygems/rubygems#3086](https://github.com/rubygems/rubygems/issues/3086) and check version with command like `Gem::Version.new(Yabeda::ActiveRecord::VERSION).to_s`
66
+
67
+ 2. Fill `CHANGELOG.md` with missing changes, add header with version and date.
68
+
69
+ 3. Make a commit:
70
+
71
+ ```sh
72
+ git add lib/yabeda/active_record/version.rb CHANGELOG.md
73
+ version=$(ruby -r ./lib/yabeda/active_record/version.rb -e "puts Gem::Version.new(Yabeda::ActiveRecord::VERSION)")
74
+ git commit --message="${version}: " --edit
75
+ ```
76
+
77
+ 4. Create annotated tag:
78
+
79
+ ```sh
80
+ git tag v${version} --annotate --message="${version}: " --edit --sign
81
+ ```
82
+
83
+ 5. Fill version name into subject line and (optionally) some description (list of changes will be taken from changelog and appended automatically)
84
+
85
+ 6. Push it:
86
+
87
+ ```sh
88
+ git push --follow-tags
89
+ ```
90
+
91
+ 7. GitHub Actions will create a new release, build and push gem into RubyGems! You're done!
92
+
93
+
94
+ ## Contributing
95
+
96
+ Bug reports and pull requests are welcome on GitHub at https://github.com/yabeda-rb/yabeda-activerecord.
97
+
98
+ ## License
99
+
100
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
101
+
102
+ [Yabeda]: https://github.com/yabeda-rb/yabeda "Extendable framework for collecting and exporting metrics from your Ruby application"
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yabeda
4
+ module ActiveRecord
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yabeda"
4
+ require "active_record"
5
+
6
+ require_relative "active_record/version"
7
+
8
+ module Yabeda
9
+ # ActiveRecord Yabeda plugin to collect metrics for query performance, connection pool stats, etc
10
+ module ActiveRecord
11
+ class Error < StandardError; end
12
+
13
+ LONG_RUNNING_QUERY_RUNTIME_BUCKETS = [
14
+ 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, # standard (from Prometheus)
15
+ 30, 60, 120, 300, 1800, 3600, 21_600, # Well, sometime queries can execute way too long
16
+ ].freeze
17
+
18
+ # rubocop: disable Layout/LineLength
19
+ Yabeda.configure do
20
+ group :activerecord do
21
+ counter :queries_total, tags: %i[config kind cached async],
22
+ comment: "Total number of SQL queries issued by application via ActiveRecord"
23
+ histogram :query_duration, tags: %i[config kind cached async],
24
+ unit: :seconds, buckets: LONG_RUNNING_QUERY_RUNTIME_BUCKETS,
25
+ comment: "Duration of SQL queries generated by ActiveRecord"
26
+
27
+ gauge :connection_pool_size,
28
+ tags: %i[config],
29
+ comment: "Connection pool size"
30
+ gauge :connection_pool_connections,
31
+ tags: %i[config],
32
+ comment: "Total number of connections currently created in the pool (sum of busy, dead, and idle)."
33
+ gauge :connection_pool_busy,
34
+ tags: %i[config],
35
+ comment: "Number of connections that has been checked out by some thread and are in use now."
36
+ gauge :connection_pool_dead,
37
+ tags: %i[config],
38
+ comment: "Number of lost connections for the pool. A lost connection can occur if a programmer forgets to checkin a connection at the end of a thread or a thread dies unexpectedly."
39
+ gauge :connection_pool_idle,
40
+ tags: %i[config],
41
+ comment: "Number of free connections, that are available for checkout."
42
+ gauge :connection_pool_waiting,
43
+ tags: %i[config],
44
+ comment: "Number of threads waiting for a connection to become available for checkout."
45
+ gauge :connection_pool_checkout_timeout,
46
+ tags: %i[config],
47
+ unit: :seconds,
48
+ comment: "Checkout waiting timeout in seconds"
49
+ end
50
+ # rubocop: enable Layout/LineLength
51
+
52
+ # Query performance metrics collection
53
+ ActiveSupport::Notifications.subscribe "sql.active_record" do |*args|
54
+ event = ActiveSupport::Notifications::Event.new(*args)
55
+
56
+ pool = event.payload[:connection].pool
57
+ next if !pool || pool.is_a?(::ActiveRecord::ConnectionAdapters::NullPool)
58
+
59
+ db_config_name = pool.respond_to?(:db_config) ? pool.db_config.name : pool.spec.name
60
+
61
+ labels = {
62
+ config: db_config_name,
63
+ kind: event.payload[:name],
64
+ cached: !event.payload[:cached].nil?,
65
+ async: !event.payload[:async].nil?,
66
+ }
67
+
68
+ Yabeda.activerecord.queries_total.increment(labels)
69
+ Yabeda.activerecord.query_duration.measure(labels, (event.duration.to_f / 1000).round(3))
70
+ end
71
+
72
+ # Connection pool metrics collection
73
+ collect do
74
+ connection_pools = ::ActiveRecord::Base.connection_handler.connection_pool_list
75
+
76
+ connection_pools.each do |connection_pool|
77
+ stats = connection_pool.stat
78
+ name =
79
+ if connection_pool.respond_to?(:db_config)
80
+ connection_pool.db_config.name
81
+ else
82
+ connection_pool.spec.name
83
+ end
84
+
85
+ tags = { config: name }
86
+ Yabeda.activerecord.connection_pool_size.set(tags, stats[:size])
87
+ Yabeda.activerecord.connection_pool_connections.set(tags, stats[:connections])
88
+ Yabeda.activerecord.connection_pool_busy.set(tags, stats[:busy])
89
+ Yabeda.activerecord.connection_pool_dead.set(tags, stats[:dead])
90
+ Yabeda.activerecord.connection_pool_idle.set(tags, stats[:idle])
91
+ Yabeda.activerecord.connection_pool_waiting.set(tags, stats[:waiting])
92
+ Yabeda.activerecord.connection_pool_checkout_timeout.set(tags, stats[:checkout_timeout])
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "active_record"
@@ -0,0 +1,6 @@
1
+ module Yabeda
2
+ module ActiveRecord
3
+ VERSION: String
4
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
+ end
6
+ end
data/tmp/.keep ADDED
File without changes
Binary file
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yabeda-activerecord
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrey Novikov
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-05-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: yabeda
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.6'
41
+ description: 'Yabeda plugin for easy collection of ActiveRecord metrics: query performance,
42
+ connection pool stats, etc.
43
+
44
+ '
45
+ email:
46
+ - envek@envek.name
47
+ executables: []
48
+ extensions: []
49
+ extra_rdoc_files: []
50
+ files:
51
+ - ".rspec"
52
+ - ".rubocop.yml"
53
+ - CHANGELOG.md
54
+ - Gemfile
55
+ - Gemfile.lock
56
+ - LICENSE.txt
57
+ - README.md
58
+ - Rakefile
59
+ - lib/yabeda/active_record.rb
60
+ - lib/yabeda/active_record/version.rb
61
+ - lib/yabeda/activerecord.rb
62
+ - sig/yabeda/activerecord.rbs
63
+ - tmp/.keep
64
+ - yabeda-activerecord-logo.png
65
+ homepage: https://github.com/yabeda-rb/yabeda-activerecord
66
+ licenses:
67
+ - MIT
68
+ metadata:
69
+ homepage_uri: https://github.com/yabeda-rb/yabeda-activerecord
70
+ source_code_uri: https://github.com/yabeda-rb/yabeda-activerecord
71
+ changelog_uri: https://github.com/yabeda-rb/yabeda-activerecord/blob/master/CHANGELOG.md
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: 2.5.0
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubygems_version: 3.1.6
88
+ signing_key:
89
+ specification_version: 4
90
+ summary: 'Yabeda plugin to collect ActiveRecord metrics: query performance, connection
91
+ pool stats, etc.'
92
+ test_files: []