Module: Gitlab::InstrumentationHelper

Extended by:
InstrumentationHelper
Included in:
GrapeLogging::Loggers::PerfLogger, InstrumentationHelper
Defined in:
lib/gitlab/instrumentation_helper.rb

Constant Summary collapse

DURATION_PRECISION =

microseconds

6

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.enqueue_latency_for_scheduled_job(job) ⇒ Object

Returns the time it took for a scheduled job to be enqueued in seconds, as a float, if the `scheduled_at` and `enqueued_at` fields are available.

  • If the job doesn't contain sufficient information, returns nil

  • If the job has a start time in the future, returns 0

  • If the job contains an invalid start time value, returns nil

Parameters:

  • job (Hash)

    a Sidekiq job, represented as a hash


149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/gitlab/instrumentation_helper.rb', line 149

def self.enqueue_latency_for_scheduled_job(job)
  scheduled_at = job['scheduled_at']
  enqueued_at = job['enqueued_at']

  return unless scheduled_at && enqueued_at

  scheduled_at_time = convert_to_time(scheduled_at)
  enqueued_at_time = convert_to_time(enqueued_at)

  return unless scheduled_at_time && enqueued_at_time

  round_elapsed_time(scheduled_at_time, enqueued_at_time)
end

.queue_duration_for_job(job) ⇒ Object

Returns the queuing duration for a Sidekiq job in seconds, as a float, if the `enqueued_at` field or `created_at` field is available.

  • If the job doesn't contain sufficient information, returns nil

  • If the job has a start time in the future, returns 0

  • If the job contains an invalid start time value, returns nil

Parameters:

  • job (Hash)

    a Sidekiq job, represented as a hash


131
132
133
134
135
136
137
138
139
140
# File 'lib/gitlab/instrumentation_helper.rb', line 131

def self.queue_duration_for_job(job)
  # Old gitlab-shell messages don't provide enqueued_at/created_at attributes
  enqueued_at = job['enqueued_at'] || job['created_at']
  return unless enqueued_at

  enqueued_at_time = convert_to_time(enqueued_at)
  return unless enqueued_at_time

  round_elapsed_time(enqueued_at_time)
end

.round_elapsed_time(start, end_time = Time.now) ⇒ Object


163
164
165
166
167
168
# File 'lib/gitlab/instrumentation_helper.rb', line 163

def self.round_elapsed_time(start, end_time = Time.now)
  # It's possible that if there is clock-skew between two nodes this
  # value may be less than zero. In that event, we record the value
  # as zero.
  [elapsed_by_absolute_time(start, end_time), 0].max.round(DURATION_PRECISION)
end

Instance Method Details

#add_instrumentation_data(payload) ⇒ Object


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/gitlab/instrumentation_helper.rb', line 21

def add_instrumentation_data(payload)
  instrument_gitaly(payload)
  instrument_rugged(payload)
  instrument_redis(payload)
  instrument_elasticsearch(payload)
  instrument_throttle(payload)
  instrument_active_record(payload)
  instrument_external_http(payload)
  instrument_rack_attack(payload)
  instrument_cpu(payload)
  instrument_thread_memory_allocations(payload)
  instrument_load_balancing(payload)
  instrument_pid(payload)
  instrument_uploads(payload)
end

#init_instrumentation_data(request_ip: nil) ⇒ Object


9
10
11
12
13
14
15
16
17
18
19
# File 'lib/gitlab/instrumentation_helper.rb', line 9

def init_instrumentation_data(request_ip: nil)
  # Set `request_start_time` only if this is request
  # This is done, as `request_start_time` imply `request_deadline`
  if request_ip
    Gitlab::RequestContext.instance.client_ip = request_ip
    Gitlab::RequestContext.instance.request_start_time = Gitlab::Metrics::System.real_time
  end

  Gitlab::RequestContext.instance.start_thread_cpu_time = Gitlab::Metrics::System.thread_cpu_time
  Gitlab::RequestContext.instance.thread_memory_allocations = Gitlab::Memory::Instrumentation.start_thread_memory_allocations
end

#instrument_active_record(payload) ⇒ Object


84
85
86
87
88
# File 'lib/gitlab/instrumentation_helper.rb', line 84

def instrument_active_record(payload)
  db_counters = ::Gitlab::Metrics::Subscribers::ActiveRecord.db_counter_payload

  payload.merge!(db_counters)
end

#instrument_cpu(payload) ⇒ Object


97
98
99
100
101
102
# File 'lib/gitlab/instrumentation_helper.rb', line 97

def instrument_cpu(payload)
  cpu_s = ::Gitlab::Metrics::System.thread_cpu_duration(
    ::Gitlab::RequestContext.instance.start_thread_cpu_time)

  payload[:cpu_s] = cpu_s.round(DURATION_PRECISION) if cpu_s
end

#instrument_elasticsearch(payload) ⇒ Object


59
60
61
62
63
64
65
66
67
68
69
# File 'lib/gitlab/instrumentation_helper.rb', line 59

def instrument_elasticsearch(payload)
  # Elasticsearch integration is only available in EE but instrumentation
  # only depends on the Gem which is also available in FOSS.
  elasticsearch_calls = Gitlab::Instrumentation::ElasticsearchTransport.get_request_count

  return if elasticsearch_calls == 0

  payload[:elasticsearch_calls] = elasticsearch_calls
  payload[:elasticsearch_duration_s] = Gitlab::Instrumentation::ElasticsearchTransport.query_time
  payload[:elasticsearch_timed_out_count] = Gitlab::Instrumentation::ElasticsearchTransport.get_timed_out_count
end

#instrument_external_http(payload) ⇒ Object


71
72
73
74
75
76
77
# File 'lib/gitlab/instrumentation_helper.rb', line 71

def instrument_external_http(payload)
  external_http_count = Gitlab::Metrics::Subscribers::ExternalHttp.request_count

  return if external_http_count == 0

  payload.merge! Gitlab::Metrics::Subscribers::ExternalHttp.payload
end

#instrument_gitaly(payload) ⇒ Object


37
38
39
40
41
42
43
44
# File 'lib/gitlab/instrumentation_helper.rb', line 37

def instrument_gitaly(payload)
  gitaly_calls = Gitlab::GitalyClient.get_request_count

  return if gitaly_calls == 0

  payload[:gitaly_calls] = gitaly_calls
  payload[:gitaly_duration_s] = Gitlab::GitalyClient.query_time
end

#instrument_load_balancing(payload) ⇒ Object


114
115
116
117
118
# File 'lib/gitlab/instrumentation_helper.rb', line 114

def instrument_load_balancing(payload)
  load_balancing_payload = ::Gitlab::Metrics::Subscribers::LoadBalancing.load_balancing_payload

  payload.merge!(load_balancing_payload)
end

#instrument_pid(payload) ⇒ Object


104
105
106
# File 'lib/gitlab/instrumentation_helper.rb', line 104

def instrument_pid(payload)
  payload[:pid] = Process.pid
end

#instrument_rack_attack(payload) ⇒ Object


90
91
92
93
94
95
# File 'lib/gitlab/instrumentation_helper.rb', line 90

def instrument_rack_attack(payload)
  rack_attack_redis_count = ::Gitlab::Metrics::Subscribers::RackAttack.payload[:rack_attack_redis_count]
  return if rack_attack_redis_count == 0

  payload.merge!(::Gitlab::Metrics::Subscribers::RackAttack.payload)
end

#instrument_redis(payload) ⇒ Object


55
56
57
# File 'lib/gitlab/instrumentation_helper.rb', line 55

def instrument_redis(payload)
  payload.merge! ::Gitlab::Instrumentation::Redis.payload
end

#instrument_rugged(payload) ⇒ Object


46
47
48
49
50
51
52
53
# File 'lib/gitlab/instrumentation_helper.rb', line 46

def instrument_rugged(payload)
  rugged_calls = Gitlab::RuggedInstrumentation.query_count

  return if rugged_calls == 0

  payload[:rugged_calls] = rugged_calls
  payload[:rugged_duration_s] = Gitlab::RuggedInstrumentation.query_time
end

#instrument_thread_memory_allocations(payload) ⇒ Object


108
109
110
111
112
# File 'lib/gitlab/instrumentation_helper.rb', line 108

def instrument_thread_memory_allocations(payload)
  counters = ::Gitlab::Memory::Instrumentation.measure_thread_memory_allocations(
    ::Gitlab::RequestContext.instance.thread_memory_allocations)
  payload.merge!(counters) if counters
end

#instrument_throttle(payload) ⇒ Object


79
80
81
82
# File 'lib/gitlab/instrumentation_helper.rb', line 79

def instrument_throttle(payload)
  safelist = Gitlab::Instrumentation::Throttle.safelist
  payload[:throttle_safelist] = safelist if safelist.present?
end

#instrument_uploads(payload) ⇒ Object


120
121
122
# File 'lib/gitlab/instrumentation_helper.rb', line 120

def instrument_uploads(payload)
  payload.merge! ::Gitlab::Instrumentation::Uploads.payload
end