summaryrefslogtreecommitdiff
path: root/lib/gitlab/metrics
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/metrics')
-rw-r--r--lib/gitlab/metrics/background_transaction.rb49
-rw-r--r--lib/gitlab/metrics/samplers/ruby_sampler.rb2
-rw-r--r--lib/gitlab/metrics/subscribers/action_cable.rb72
-rw-r--r--lib/gitlab/metrics/subscribers/active_record.rb56
4 files changed, 158 insertions, 21 deletions
diff --git a/lib/gitlab/metrics/background_transaction.rb b/lib/gitlab/metrics/background_transaction.rb
new file mode 100644
index 00000000000..3dda68bf93f
--- /dev/null
+++ b/lib/gitlab/metrics/background_transaction.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Metrics
+ class BackgroundTransaction < Transaction
+ # Separate web transaction instance and background transaction instance
+ BACKGROUND_THREAD_KEY = :_gitlab_metrics_background_transaction
+ BACKGROUND_BASE_LABEL_KEYS = %i(endpoint_id feature_category).freeze
+
+ class << self
+ def current
+ Thread.current[BACKGROUND_THREAD_KEY]
+ end
+
+ def prometheus_metric(name, type, &block)
+ fetch_metric(type, name) do
+ # set default metric options
+ docstring "#{name.to_s.humanize} #{type}"
+
+ evaluate(&block)
+ # always filter sensitive labels and merge with base ones
+ label_keys BACKGROUND_BASE_LABEL_KEYS | (label_keys - ::Gitlab::Metrics::Transaction::FILTERED_LABEL_KEYS)
+ end
+ end
+ end
+
+ def run
+ Thread.current[BACKGROUND_THREAD_KEY] = self
+
+ yield
+ ensure
+ Thread.current[BACKGROUND_THREAD_KEY] = nil
+ end
+
+ def labels
+ @labels ||= {
+ endpoint_id: current_context&.get_attribute(:caller_id),
+ feature_category: current_context&.get_attribute(:feature_category)
+ }
+ end
+
+ private
+
+ def current_context
+ Labkit::Context.current
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/metrics/samplers/ruby_sampler.rb b/lib/gitlab/metrics/samplers/ruby_sampler.rb
index 76175b465e4..3d29d38fa1f 100644
--- a/lib/gitlab/metrics/samplers/ruby_sampler.rb
+++ b/lib/gitlab/metrics/samplers/ruby_sampler.rb
@@ -7,7 +7,7 @@ module Gitlab
module Samplers
class RubySampler < BaseSampler
DEFAULT_SAMPLING_INTERVAL_SECONDS = 60
- GC_REPORT_BUCKETS = [0.005, 0.01, 0.02, 0.04, 0.07, 0.1, 0.5].freeze
+ GC_REPORT_BUCKETS = [0.01, 0.05, 0.1, 0.2, 0.3, 0.5, 1].freeze
def initialize(*)
GC::Profiler.clear
diff --git a/lib/gitlab/metrics/subscribers/action_cable.rb b/lib/gitlab/metrics/subscribers/action_cable.rb
new file mode 100644
index 00000000000..a9355eeae40
--- /dev/null
+++ b/lib/gitlab/metrics/subscribers/action_cable.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Metrics
+ module Subscribers
+ class ActionCable < ActiveSupport::Subscriber
+ include Gitlab::Utils::StrongMemoize
+
+ attach_to :action_cable
+
+ SINGLE_CLIENT_TRANSMISSION = :action_cable_single_client_transmissions_total
+ TRANSMIT_SUBSCRIPTION_CONFIRMATION = :action_cable_subscription_confirmations_total
+ TRANSMIT_SUBSCRIPTION_REJECTION = :action_cable_subscription_rejections_total
+ BROADCAST = :action_cable_broadcasts_total
+
+ def transmit_subscription_confirmation(event)
+ confirm_subscription_counter.increment
+ end
+
+ def transmit_subscription_rejection(event)
+ reject_subscription_counter.increment
+ end
+
+ def transmit(event)
+ transmit_counter.increment
+ end
+
+ def broadcast(event)
+ broadcast_counter.increment
+ end
+
+ private
+
+ def transmit_counter
+ strong_memoize("transmission_counter") do
+ ::Gitlab::Metrics.counter(
+ SINGLE_CLIENT_TRANSMISSION,
+ 'The number of ActionCable messages transmitted to any client in any channel'
+ )
+ end
+ end
+
+ def broadcast_counter
+ strong_memoize("broadcast_counter") do
+ ::Gitlab::Metrics.counter(
+ BROADCAST,
+ 'The number of ActionCable broadcasts emitted'
+ )
+ end
+ end
+
+ def confirm_subscription_counter
+ strong_memoize("confirm_subscription_counter") do
+ ::Gitlab::Metrics.counter(
+ TRANSMIT_SUBSCRIPTION_CONFIRMATION,
+ 'The number of ActionCable subscriptions from clients confirmed'
+ )
+ end
+ end
+
+ def reject_subscription_counter
+ strong_memoize("reject_subscription_counter") do
+ ::Gitlab::Metrics.counter(
+ TRANSMIT_SUBSCRIPTION_REJECTION,
+ 'The number of ActionCable subscriptions from clients rejected'
+ )
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb
index d725d8d7b29..5eefef02507 100644
--- a/lib/gitlab/metrics/subscribers/active_record.rb
+++ b/lib/gitlab/metrics/subscribers/active_record.rb
@@ -9,6 +9,16 @@ module Gitlab
IGNORABLE_SQL = %w{BEGIN COMMIT}.freeze
DB_COUNTERS = %i{db_count db_write_count db_cached_count}.freeze
+ SQL_COMMANDS_WITH_COMMENTS_REGEX = /\A(\/\*.*\*\/\s)?((?!(.*[^\w'"](DELETE|UPDATE|INSERT INTO)[^\w'"])))(WITH.*)?(SELECT)((?!(FOR UPDATE|FOR SHARE)).)*$/i.freeze
+
+ DURATION_BUCKET = [0.05, 0.1, 0.25].freeze
+
+ # This event is published from ActiveRecordBaseTransactionMetrics and
+ # used to record a database transaction duration when calling
+ # ActiveRecord::Base.transaction {} block.
+ def transaction(event)
+ observe(:gitlab_database_transaction_seconds, event)
+ end
def sql(event)
# Mark this thread as requiring a database connection. This is used
@@ -17,51 +27,57 @@ module Gitlab
Thread.current[:uses_db_connection] = true
payload = event.payload
- return if payload[:name] == 'SCHEMA' || IGNORABLE_SQL.include?(payload[:sql])
+ return if ignored_query?(payload)
- increment_db_counters(payload)
+ increment(:db_count)
+ increment(:db_cached_count) if cached_query?(payload)
+ increment(:db_write_count) unless select_sql_command?(payload)
- current_transaction&.observe(:gitlab_sql_duration_seconds, event.duration / 1000.0) do
- buckets [0.05, 0.1, 0.25]
- end
+ observe(:gitlab_sql_duration_seconds, event)
end
def self.db_counter_payload
return {} unless Gitlab::SafeRequestStore.active?
- DB_COUNTERS.map do |counter|
- [counter, Gitlab::SafeRequestStore[counter].to_i]
- end.to_h
+ payload = {}
+ DB_COUNTERS.each do |counter|
+ payload[counter] = Gitlab::SafeRequestStore[counter].to_i
+ end
+ payload
end
private
- def select_sql_command?(payload)
- payload[:sql].match(/\A((?!(.*[^\w'"](DELETE|UPDATE|INSERT INTO)[^\w'"])))(WITH.*)?(SELECT)((?!(FOR UPDATE|FOR SHARE)).)*$/i)
+ def ignored_query?(payload)
+ payload[:name] == 'SCHEMA' || IGNORABLE_SQL.include?(payload[:sql])
end
- def increment_db_counters(payload)
- increment(:db_count)
-
- if payload.fetch(:cached, payload[:name] == 'CACHE')
- increment(:db_cached_count)
- end
+ def cached_query?(payload)
+ payload.fetch(:cached, payload[:name] == 'CACHE')
+ end
- increment(:db_write_count) unless select_sql_command?(payload)
+ def select_sql_command?(payload)
+ payload[:sql].match(SQL_COMMANDS_WITH_COMMENTS_REGEX)
end
def increment(counter)
current_transaction&.increment("gitlab_transaction_#{counter}_total".to_sym, 1)
- if Gitlab::SafeRequestStore.active?
- Gitlab::SafeRequestStore[counter] = Gitlab::SafeRequestStore[counter].to_i + 1
+ Gitlab::SafeRequestStore[counter] = Gitlab::SafeRequestStore[counter].to_i + 1
+ end
+
+ def observe(histogram, event)
+ current_transaction&.observe(histogram, event.duration / 1000.0) do
+ buckets DURATION_BUCKET
end
end
def current_transaction
- ::Gitlab::Metrics::Transaction.current
+ ::Gitlab::Metrics::WebTransaction.current || ::Gitlab::Metrics::BackgroundTransaction.current
end
end
end
end
end
+
+Gitlab::Metrics::Subscribers::ActiveRecord.prepend_if_ee('EE::Gitlab::Metrics::Subscribers::ActiveRecord')