Class: Gitlab::Metrics::Subscribers::ActiveRecord
- Inherits:
-
ActiveSupport::Subscriber
- Object
- ActiveSupport::Subscriber
- Gitlab::Metrics::Subscribers::ActiveRecord
- Extended by:
- Utils::StrongMemoize
- Defined in:
- lib/gitlab/metrics/subscribers/active_record.rb
Overview
Class for tracking the total query duration of a transaction.
Constant Summary collapse
- DB_COUNTERS =
i[count write_count cached_count txn_count].freeze
- SQL_COMMANDS_WITH_COMMENTS_REGEX =
%r{\A(?>/\*.*?\*/\s)?(?!.*[^\w'"](?:DELETE|UPDATE|INSERT INTO)[^\w'"])(?:WITH.*)?SELECT(?!.*(?:FOR UPDATE|FOR SHARE))}i- SQL_DURATION_BUCKET =
[0.05, 0.1, 0.25].freeze
- TRANSACTION_DURATION_BUCKET =
[0.1, 0.25, 1].freeze
- DB_LOAD_BALANCING_ROLES =
i[replica primary].freeze
- DB_LOAD_BALANCING_COUNTERS =
i[txn_count count write_count cached_count wal_count wal_cached_count].freeze
- DB_LOAD_BALANCING_DURATIONS =
i[txn_max_duration_s txn_duration_s duration_s].freeze
- SQL_WAL_LOCATION_REGEX =
/pg_current_wal_insert_lsn\(\)::text|pg_last_wal_replay_lsn\(\)::text/
Class Method Summary collapse
- .compose_metric_key(metric, db_role = nil, db_config_name = nil) ⇒ Object
- .db_counter_keys ⇒ Object
- .db_counter_payload ⇒ Object
- .load_balancing_metric_counter_keys ⇒ Object
- .load_balancing_metric_duration_keys ⇒ Object
- .load_balancing_roles_metric_counter_keys ⇒ Object
- .load_balancing_roles_metric_duration_keys ⇒ Object
- .load_balancing_roles_metric_keys(metrics) ⇒ Object
Instance Method Summary collapse
- #sql(event) ⇒ Object
-
#transaction(event) ⇒ Object
This event is published from ActiveRecordBaseTransactionMetrics and used to record a database transaction duration when calling ApplicationRecord.transaction {} block.
Class Method Details
.compose_metric_key(metric, db_role = nil, db_config_name = nil) ⇒ Object
251 252 253 |
# File 'lib/gitlab/metrics/subscribers/active_record.rb', line 251 def self.compose_metric_key(metric, db_role = nil, db_config_name = nil) [:db, db_role, db_config_name, metric].compact.join("_").to_sym end |
.db_counter_keys ⇒ Object
189 190 191 |
# File 'lib/gitlab/metrics/subscribers/active_record.rb', line 189 def self.db_counter_keys DB_COUNTERS.map { |c| compose_metric_key(c) } end |
.db_counter_payload ⇒ Object
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/gitlab/metrics/subscribers/active_record.rb', line 81 def self.db_counter_payload return {} unless Gitlab::SafeRequestStore.active? {}.tap do |payload| if Feature.disabled?(:omit_aggregated_db_log_fields, :current_request, type: :ops) db_counter_keys.each do |key| payload[key] = Gitlab::SafeRequestStore[key].to_i end load_balancing_roles_metric_counter_keys.each do |counter| payload[counter] = ::Gitlab::SafeRequestStore[counter].to_i end load_balancing_roles_metric_duration_keys.each do |duration| payload[duration] = ::Gitlab::SafeRequestStore[duration].to_f.round(3) end end load_balancing_metric_counter_keys.each do |counter| payload[counter] = ::Gitlab::SafeRequestStore[counter].to_i end load_balancing_metric_duration_keys.each do |duration| payload[duration] = ::Gitlab::SafeRequestStore[duration].to_f.round(3) end end end |
.load_balancing_metric_counter_keys ⇒ Object
193 194 195 196 197 |
# File 'lib/gitlab/metrics/subscribers/active_record.rb', line 193 def self.load_balancing_metric_counter_keys strong_memoize(:load_balancing_metric_counter_keys) do load_balancing_metric_keys(DB_LOAD_BALANCING_COUNTERS) end end |
.load_balancing_metric_duration_keys ⇒ Object
199 200 201 202 203 |
# File 'lib/gitlab/metrics/subscribers/active_record.rb', line 199 def self.load_balancing_metric_duration_keys strong_memoize(:load_balancing_metric_duration_keys) do load_balancing_metric_keys(DB_LOAD_BALANCING_DURATIONS) end end |
.load_balancing_roles_metric_counter_keys ⇒ Object
205 206 207 208 209 |
# File 'lib/gitlab/metrics/subscribers/active_record.rb', line 205 def self.load_balancing_roles_metric_counter_keys strong_memoize(:load_balancing_roles_metric_counter_keys) do load_balancing_roles_metric_keys(DB_LOAD_BALANCING_COUNTERS) end end |
.load_balancing_roles_metric_duration_keys ⇒ Object
211 212 213 214 215 |
# File 'lib/gitlab/metrics/subscribers/active_record.rb', line 211 def self.load_balancing_roles_metric_duration_keys strong_memoize(:load_balancing_roles_metric_duration_keys) do load_balancing_roles_metric_keys(DB_LOAD_BALANCING_DURATIONS) end end |
.load_balancing_roles_metric_keys(metrics) ⇒ Object
217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/gitlab/metrics/subscribers/active_record.rb', line 217 def self.load_balancing_roles_metric_keys(metrics) counters = [] metrics.each do |metric| DB_LOAD_BALANCING_ROLES.each do |role| counters << compose_metric_key(metric, role) end end counters end |
Instance Method Details
#sql(event) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/gitlab/metrics/subscribers/active_record.rb', line 47 def sql(event) # Mark this thread as requiring a database connection. This is used # by the Gitlab::Metrics::Samplers::ThreadsSampler to count threads # using a connection. Thread.current[:uses_db_connection] = true payload = event.payload return if ignored_query?(payload) db_role = ::Gitlab::Database::LoadBalancing.db_role_for_connection(payload[:connection]) db_config_name = db_config_name(event.payload) cached_query = cached_query?(payload) # 1. Queries executed on replicas are always SELECT queries without the`FOR UPDATE` or the `FOR SHARE` modifier # 2. Cached query is always a SELECT without the`FOR UPDATE` or the `FOR SHARE` modifier # 3. Parse the query and check if it's SELECT select_sql_command = db_role == Gitlab::Database::LoadBalancing::ROLE_REPLICA || cached_query || select_sql_command?(payload) increment(:count, db_config_name: db_config_name) increment(:cached_count, db_config_name: db_config_name) if cached_query increment(:write_count, db_config_name: db_config_name) unless select_sql_command observe(:gitlab_sql_duration_seconds, event) do buckets SQL_DURATION_BUCKET end return if db_role.blank? increment_db_role_counters(db_role, payload, cached_query: cached_query, select_sql_command: select_sql_command) observe_db_role_duration(db_role, event) end |
#transaction(event) ⇒ Object
This event is published from ActiveRecordBaseTransactionMetrics and used to record a database transaction duration when calling ApplicationRecord.transaction {} block.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/gitlab/metrics/subscribers/active_record.rb', line 27 def transaction(event) observe(:gitlab_database_transaction_seconds, event) do buckets TRANSACTION_DURATION_BUCKET end return unless ::Gitlab::SafeRequestStore.active? # transactions uses a Gitlab::Database::Loadbalancing::ConnectionProxy which has a :unknown role # so we only track the overall and per-config txn duration db_config_name = db_config_name(event.payload) increment_log_key(compose_metric_key(:txn_count)) increment_log_key(compose_metric_key(:txn_count, nil, db_config_name)) duration = convert_ms_to_s(event.duration) increment_duration_key(compose_metric_key(:txn_duration_s), duration) increment_duration_key(compose_metric_key(:txn_duration_s, nil, db_config_name), duration) update_max_duration_key(:txn_max_duration_s, duration) update_max_duration_key(:txn_max_duration_s, duration, db_config_name) end |