diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-16 18:25:58 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-16 18:25:58 +0000 |
commit | a5f4bba440d7f9ea47046a0a561d49adf0a1e6d4 (patch) | |
tree | fb69158581673816a8cd895f9d352dcb3c678b1e /lib/gitlab/metrics | |
parent | d16b2e8639e99961de6ddc93909f3bb5c1445ba1 (diff) | |
download | gitlab-ce-a5f4bba440d7f9ea47046a0a561d49adf0a1e6d4.tar.gz |
Add latest changes from gitlab-org/gitlab@14-0-stable-eev14.0.0-rc42
Diffstat (limited to 'lib/gitlab/metrics')
-rw-r--r-- | lib/gitlab/metrics/exporter/web_exporter.rb | 3 | ||||
-rw-r--r-- | lib/gitlab/metrics/requests_rack_middleware.rb | 13 | ||||
-rw-r--r-- | lib/gitlab/metrics/samplers/database_sampler.rb | 4 | ||||
-rw-r--r-- | lib/gitlab/metrics/samplers/ruby_sampler.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/metrics/samplers/unicorn_sampler.rb | 73 | ||||
-rw-r--r-- | lib/gitlab/metrics/subscribers/active_record.rb | 57 | ||||
-rw-r--r-- | lib/gitlab/metrics/subscribers/external_http.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/metrics/transaction.rb | 23 | ||||
-rw-r--r-- | lib/gitlab/metrics/web_transaction.rb | 25 |
9 files changed, 84 insertions, 118 deletions
diff --git a/lib/gitlab/metrics/exporter/web_exporter.rb b/lib/gitlab/metrics/exporter/web_exporter.rb index 558454eaa1c..756e6b0641a 100644 --- a/lib/gitlab/metrics/exporter/web_exporter.rb +++ b/lib/gitlab/metrics/exporter/web_exporter.rb @@ -30,8 +30,7 @@ module Gitlab # application: https://gitlab.com/gitlab-org/gitlab/issues/35343 self.readiness_checks = [ WebExporter::ExporterCheck.new(self), - Gitlab::HealthChecks::PumaCheck, - Gitlab::HealthChecks::UnicornCheck + Gitlab::HealthChecks::PumaCheck ] end diff --git a/lib/gitlab/metrics/requests_rack_middleware.rb b/lib/gitlab/metrics/requests_rack_middleware.rb index 19a835b9fc4..b99261b5c4d 100644 --- a/lib/gitlab/metrics/requests_rack_middleware.rb +++ b/lib/gitlab/metrics/requests_rack_middleware.rb @@ -15,7 +15,6 @@ module Gitlab HEALTH_ENDPOINT = /^\/-\/(liveness|readiness|health|metrics)\/?$/.freeze - FEATURE_CATEGORY_HEADER = 'X-Gitlab-Feature-Category' FEATURE_CATEGORY_DEFAULT = 'unknown' # These were the top 5 categories at a point in time, chosen as a @@ -67,18 +66,16 @@ module Gitlab def call(env) method = env['REQUEST_METHOD'].downcase method = 'INVALID' unless HTTP_METHODS.key?(method) - started = Time.now.to_f + started = Gitlab::Metrics::System.monotonic_time health_endpoint = health_endpoint?(env['PATH_INFO']) status = 'undefined' - feature_category = nil begin status, headers, body = @app.call(env) - elapsed = Time.now.to_f - started - feature_category = headers&.fetch(FEATURE_CATEGORY_HEADER, nil) + elapsed = Gitlab::Metrics::System.monotonic_time - started - unless health_endpoint + if !health_endpoint && Gitlab::Metrics.record_duration_for_status?(status) RequestsRackMiddleware.http_request_duration_seconds.observe({ method: method }, elapsed) end @@ -104,6 +101,10 @@ module Gitlab HEALTH_ENDPOINT.match?(CGI.unescape(path)) end + + def feature_category + ::Gitlab::ApplicationContext.current_context_attribute(:feature_category) + end end end end diff --git a/lib/gitlab/metrics/samplers/database_sampler.rb b/lib/gitlab/metrics/samplers/database_sampler.rb index 0a0ac6c5386..5d7f434b660 100644 --- a/lib/gitlab/metrics/samplers/database_sampler.rb +++ b/lib/gitlab/metrics/samplers/database_sampler.rb @@ -45,8 +45,8 @@ module Gitlab def labels_for_class(klass) { - host: klass.connection_config[:host], - port: klass.connection_config[:port], + host: klass.connection_db_config.host, + port: klass.connection_db_config.configuration_hash[:port], class: klass.to_s } end diff --git a/lib/gitlab/metrics/samplers/ruby_sampler.rb b/lib/gitlab/metrics/samplers/ruby_sampler.rb index 3d29d38fa1f..b1c5e9800da 100644 --- a/lib/gitlab/metrics/samplers/ruby_sampler.rb +++ b/lib/gitlab/metrics/samplers/ruby_sampler.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'prometheus/client/support/unicorn' - module Gitlab module Metrics module Samplers diff --git a/lib/gitlab/metrics/samplers/unicorn_sampler.rb b/lib/gitlab/metrics/samplers/unicorn_sampler.rb deleted file mode 100644 index 2fa324f3fea..00000000000 --- a/lib/gitlab/metrics/samplers/unicorn_sampler.rb +++ /dev/null @@ -1,73 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Metrics - module Samplers - class UnicornSampler < BaseSampler - DEFAULT_SAMPLING_INTERVAL_SECONDS = 5 - - def metrics - @metrics ||= init_metrics - end - - def init_metrics - { - unicorn_active_connections: ::Gitlab::Metrics.gauge(:unicorn_active_connections, 'Unicorn active connections', {}, :max), - unicorn_queued_connections: ::Gitlab::Metrics.gauge(:unicorn_queued_connections, 'Unicorn queued connections', {}, :max), - unicorn_workers: ::Gitlab::Metrics.gauge(:unicorn_workers, 'Unicorn workers') - } - end - - def enabled? - # Raindrops::Linux.tcp_listener_stats is only present on Linux - unicorn_with_listeners? && Raindrops::Linux.respond_to?(:tcp_listener_stats) - end - - def sample - Raindrops::Linux.tcp_listener_stats(tcp_listeners).each do |addr, stats| - set_unicorn_connection_metrics('tcp', addr, stats) - end - Raindrops::Linux.unix_listener_stats(unix_listeners).each do |addr, stats| - set_unicorn_connection_metrics('unix', addr, stats) - end - - metrics[:unicorn_workers].set({}, unicorn_workers_count) - end - - private - - def tcp_listeners - @tcp_listeners ||= Unicorn.listener_names.grep(%r{\A[^/]+:\d+\z}) - end - - def set_unicorn_connection_metrics(type, addr, stats) - labels = { socket_type: type, socket_address: addr } - - metrics[:unicorn_active_connections].set(labels, stats.active) - metrics[:unicorn_queued_connections].set(labels, stats.queued) - end - - def unix_listeners - @unix_listeners ||= Unicorn.listener_names - tcp_listeners - end - - def unicorn_with_listeners? - defined?(Unicorn) && Unicorn.listener_names.any? - end - - def unicorn_workers_count - http_servers.sum(&:worker_processes) - end - - # Traversal of ObjectSpace is expensive, on fully loaded application - # it takes around 80ms. The instances of HttpServers are not a subject - # to change so we can cache the list of servers. - def http_servers - return [] unless Gitlab::Runtime.unicorn? - - @http_servers ||= ObjectSpace.each_object(::Unicorn::HttpServer).to_a - end - end - end - end -end diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb index 3db3317e833..9f7884e1364 100644 --- a/lib/gitlab/metrics/subscribers/active_record.rb +++ b/lib/gitlab/metrics/subscribers/active_record.rb @@ -14,6 +14,14 @@ module Gitlab SQL_DURATION_BUCKET = [0.05, 0.1, 0.25].freeze TRANSACTION_DURATION_BUCKET = [0.1, 0.25, 1].freeze + DB_LOAD_BALANCING_COUNTERS = %i{ + db_replica_count db_replica_cached_count db_replica_wal_count + db_primary_count db_primary_cached_count db_primary_wal_count + }.freeze + DB_LOAD_BALANCING_DURATIONS = %i{db_primary_duration_s db_replica_duration_s}.freeze + + SQL_WAL_LOCATION_REGEX = /(pg_current_wal_insert_lsn\(\)::text|pg_last_wal_replay_lsn\(\)::text)/.freeze + # This event is published from ActiveRecordBaseTransactionMetrics and # used to record a database transaction duration when calling # ActiveRecord::Base.transaction {} block. @@ -39,23 +47,56 @@ module Gitlab observe(:gitlab_sql_duration_seconds, event) do buckets SQL_DURATION_BUCKET end + + if ::Gitlab::Database::LoadBalancing.enable? + db_role = ::Gitlab::Database::LoadBalancing.db_role_for_connection(payload[:connection]) + return if db_role.blank? + + increment_db_role_counters(db_role, payload) + observe_db_role_duration(db_role, event) + end end def self.db_counter_payload return {} unless Gitlab::SafeRequestStore.active? - payload = {} - DB_COUNTERS.each do |counter| - payload[counter] = Gitlab::SafeRequestStore[counter].to_i + {}.tap do |payload| + DB_COUNTERS.each do |counter| + payload[counter] = Gitlab::SafeRequestStore[counter].to_i + end + + if ::Gitlab::SafeRequestStore.active? && ::Gitlab::Database::LoadBalancing.enable? + DB_LOAD_BALANCING_COUNTERS.each do |counter| + payload[counter] = ::Gitlab::SafeRequestStore[counter].to_i + end + DB_LOAD_BALANCING_DURATIONS.each do |duration| + payload[duration] = ::Gitlab::SafeRequestStore[duration].to_f.round(3) + end + end end - payload end - def self.known_payload_keys - DB_COUNTERS + private + + def wal_command?(payload) + payload[:sql].match(SQL_WAL_LOCATION_REGEX) + end + + def increment_db_role_counters(db_role, payload) + increment("db_#{db_role}_count".to_sym) + increment("db_#{db_role}_cached_count".to_sym) if cached_query?(payload) + increment("db_#{db_role}_wal_count".to_sym) if !cached_query?(payload) && wal_command?(payload) end - private + def observe_db_role_duration(db_role, event) + observe("gitlab_sql_#{db_role}_duration_seconds".to_sym, event) do + buckets ::Gitlab::Metrics::Subscribers::ActiveRecord::SQL_DURATION_BUCKET + end + + duration = event.duration / 1000.0 + duration_key = "db_#{db_role}_duration_s".to_sym + ::Gitlab::SafeRequestStore[duration_key] = (::Gitlab::SafeRequestStore[duration_key].presence || 0) + duration + end def ignored_query?(payload) payload[:name] == 'SCHEMA' || IGNORABLE_SQL.include?(payload[:sql]) @@ -86,5 +127,3 @@ module Gitlab end end end - -Gitlab::Metrics::Subscribers::ActiveRecord.prepend_mod_with('Gitlab::Metrics::Subscribers::ActiveRecord') diff --git a/lib/gitlab/metrics/subscribers/external_http.rb b/lib/gitlab/metrics/subscribers/external_http.rb index 0df64f2897e..60a1b084345 100644 --- a/lib/gitlab/metrics/subscribers/external_http.rb +++ b/lib/gitlab/metrics/subscribers/external_http.rb @@ -14,8 +14,6 @@ module Gitlab COUNTER = :external_http_count DURATION = :external_http_duration_s - KNOWN_PAYLOAD_KEYS = [COUNTER, DURATION].freeze - def self.detail_store ::Gitlab::SafeRequestStore[DETAIL_STORE] ||= [] end diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb index 3ebafb5c5e4..97cc8bed564 100644 --- a/lib/gitlab/metrics/transaction.rb +++ b/lib/gitlab/metrics/transaction.rb @@ -13,8 +13,6 @@ module Gitlab THREAD_KEY = :_gitlab_metrics_transaction - SMALL_BUCKETS = [0.1, 0.25, 0.5, 1.0, 2.5, 5.0].freeze - # The series to store events (e.g. Git pushes) in. EVENT_SERIES = 'events' @@ -39,29 +37,10 @@ module Gitlab def initialize @methods = {} - - @started_at = nil - @finished_at = nil - end - - def duration - @finished_at ? (@finished_at - @started_at) : 0.0 end def run - Thread.current[THREAD_KEY] = self - - @started_at = System.monotonic_time - - yield - ensure - @finished_at = System.monotonic_time - - observe(:gitlab_transaction_duration_seconds, duration) do - buckets SMALL_BUCKETS - end - - Thread.current[THREAD_KEY] = nil + raise NotImplementedError end # Tracks a business level event diff --git a/lib/gitlab/metrics/web_transaction.rb b/lib/gitlab/metrics/web_transaction.rb index ee9e6f449d3..3ebfcc43b0b 100644 --- a/lib/gitlab/metrics/web_transaction.rb +++ b/lib/gitlab/metrics/web_transaction.rb @@ -6,12 +6,29 @@ module Gitlab CONTROLLER_KEY = 'action_controller.instance' ENDPOINT_KEY = 'api.endpoint' ALLOWED_SUFFIXES = Set.new(%w[json js atom rss xml zip]) + SMALL_BUCKETS = [0.1, 0.25, 0.5, 1.0, 2.5, 5.0].freeze def initialize(env) super() @env = env end + def run + Thread.current[THREAD_KEY] = self + + started_at = System.monotonic_time + + status, _, _ = retval = yield + + finished_at = System.monotonic_time + duration = finished_at - started_at + record_duration_if_needed(status, duration) + + retval + ensure + Thread.current[THREAD_KEY] = nil + end + def labels return @labels if @labels @@ -27,6 +44,14 @@ module Gitlab private + def record_duration_if_needed(status, duration) + return unless Gitlab::Metrics.record_duration_for_status?(status) + + observe(:gitlab_transaction_duration_seconds, duration) do + buckets SMALL_BUCKETS + end + end + def labels_from_controller controller = @env[CONTROLLER_KEY] |