Class: Gitlab::Metrics::Subscribers::ActiveRecord

Inherits:
ActiveSupport::Subscriber
  • Object
show all
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

Instance Method Summary collapse

Class Method Details

.db_counter_payloadObject



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/gitlab/metrics/subscribers/active_record.rb', line 75

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

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
# 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_config_name = db_config_name(event.payload)
  cached_query = cached_query?(payload)
  select_sql_command = 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

  db_role = ::Gitlab::Database::LoadBalancing.db_role_for_connection(payload[:connection])
  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