1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
80
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
108
|
# 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<Integer, Float>] 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] = self.class.count + 1
Gitlab::SafeRequestStore[DURATION] = self.class.duration + convert_to_seconds(event.duration)
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 }
duration = convert_to_seconds(event.duration)
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, 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
def convert_to_seconds(duration_f)
(BigDecimal(duration_f.to_s) / BigDecimal("1000.0")).to_f
end
end
end
end
end
|