# frozen_string_literal: true module Gitlab module Metrics module Subscribers class Ldap < ActiveSupport::Subscriber # This namespace is configured in the Net::LDAP library, and appears # at the end of the event key, e.g. `open.net_ldap` attach_to :net_ldap COUNTER = :net_ldap_count DURATION = :net_ldap_duration_s # Assembled from methods that are instrumented inside Net::LDAP OBSERVABLE_EVENTS = %i[ open bind add modify modify_password rename delete search ].freeze class << self # @return [Integer] the total number of LDAP requests def count Gitlab::SafeRequestStore[COUNTER].to_i end # @return [Float] the total duration spent on LDAP requests def duration Gitlab::SafeRequestStore[DURATION].to_f end # Used in Gitlab::InstrumentationHelper to merge the LDAP stats # into the log output # # @return [Hash] a hash of the stored statistics def payload { net_ldap_count: count, net_ldap_duration_s: duration } end end # Called when an event is triggered in ActiveSupport::Notifications # # This method is aliased to the various events triggered by the # Net::LDAP library, as the method will be called by those names # when triggered. # # It stores statistics in the request for output to logs, and also # resubmits the event data into Prometheus for monitoring purposes. def observe_event(event) add_to_request_store(event) expose_metrics(event) end OBSERVABLE_EVENTS.each do |event| alias_method event, :observe_event end private def current_transaction ::Gitlab::Metrics::WebTransaction.current || ::Gitlab::Metrics::BackgroundTransaction.current end # Track these events as statistics for the current requests, for logging purposes def add_to_request_store(event) return unless Gitlab::SafeRequestStore.active? Gitlab::SafeRequestStore[COUNTER] = Gitlab::SafeRequestStore[COUNTER].to_i + 1 Gitlab::SafeRequestStore[DURATION] = Gitlab::SafeRequestStore[DURATION].to_f + event.duration.to_f end # Converts the observed events into Prometheus metrics def expose_metrics(event) return unless current_transaction # event.name will be, for example, `search.net_ldap` # and so we only want the first part, which is the # true name of the event labels = { name: event.name.split(".").first } current_transaction.increment(:gitlab_net_ldap_total, 1, labels) do docstring 'Net::LDAP calls' label_keys labels.keys end current_transaction.observe(:gitlab_net_ldap_duration_seconds, event.duration, labels) do docstring 'Net::LDAP time' buckets [0.001, 0.01, 0.1, 1.0, 2.0, 5.0] label_keys labels.keys end end end end end end