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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
# frozen_string_literal: true
module Gitlab
module Ci
module Pipeline
class Logger
include ::Gitlab::Utils::StrongMemoize
def self.current_monotonic_time
::Gitlab::Metrics::System.monotonic_time
end
def initialize(project:, destination: Gitlab::AppJsonLogger)
@started_at = current_monotonic_time
@project = project
@destination = destination
@log_conditions = []
yield(self) if block_given?
end
def log_when(&block)
log_conditions.push(block)
end
def instrument(operation, once: false)
return yield unless enabled?
raise ArgumentError, 'block not given' unless block_given?
op_started_at = current_monotonic_time
result = yield
observe("#{operation}_duration_s", current_monotonic_time - op_started_at, once: once)
result
end
def instrument_once_with_sql(operation, &block)
op_start_db_counters = current_db_counter_payload
result = instrument(operation, once: true, &block)
observe_sql_counters(operation, op_start_db_counters, current_db_counter_payload, once: true)
result
end
def observe(operation, value, once: false)
return unless enabled?
if once
observations[operation.to_s] = value
else
observations[operation.to_s].push(value)
end
end
def commit(pipeline:, caller:)
return unless log?
attributes = {
class: self.class.name.to_s,
pipeline_creation_caller: caller,
project_id: project&.id, # project is not available when called from `/ci/lint`
pipeline_persisted: pipeline.persisted?,
pipeline_source: pipeline.source,
pipeline_creation_service_duration_s: age
}
if pipeline.persisted?
attributes[:pipeline_builds_tags_count] = pipeline.tags_count
attributes[:pipeline_builds_distinct_tags_count] = pipeline.distinct_tags_count
attributes[:pipeline_id] = pipeline.id
end
attributes.compact!
attributes.stringify_keys!
attributes.merge!(observations_hash)
destination.info(attributes)
end
def observations_hash
observations.transform_values do |observation|
next if observation.blank?
if observation.is_a?(Array)
{
'count' => observation.size,
'max' => observation.max,
'sum' => observation.sum
}
else
observation
end
end.compact
end
private
attr_reader :project, :destination, :started_at, :log_conditions
delegate :current_monotonic_time, to: :class
def age
current_monotonic_time - started_at
end
def log?
return false unless enabled?
return true if log_conditions.empty?
log_conditions.any? { |cond| cond.call(observations) }
end
def enabled?
strong_memoize(:enabled) do
::Feature.enabled?(:ci_pipeline_creation_logger, project, type: :ops)
end
end
def observations
@observations ||= Hash.new { |hash, key| hash[key] = [] }
end
def observe_sql_counters(operation, start_db_counters, end_db_counters, once: false)
end_db_counters.each do |key, value|
result = value - start_db_counters.fetch(key, 0)
next if result == 0
observe("#{operation}_#{key}", result, once: once)
end
end
def current_db_counter_payload
::Gitlab::Metrics::Subscribers::ActiveRecord.db_counter_payload
end
end
end
end
end
|