blob: 6defe9ae4432119804ff999ca36d02b826b73eaa (
plain)
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
144
145
146
147
148
149
150
151
152
153
154
155
|
# frozen_string_literal: true
module Gitlab
module Database
module Transaction
class Context
attr_reader :context
LOG_SAVEPOINTS_THRESHOLD = 1 # 1 `SAVEPOINT` created in a transaction
LOG_DURATION_S_THRESHOLD = 120 # transaction that is running for 2 minutes or longer
LOG_EXTERNAL_HTTP_COUNT_THRESHOLD = 50 # 50 external HTTP requests executed within transaction
LOG_EXTERNAL_HTTP_DURATION_S_THRESHOLD = 1 # 1 second spent in HTTP requests in total within transaction
LOG_THROTTLE_DURATION = 1
def initialize
@context = {}
end
def set_start_time
@context[:start_time] = current_timestamp
end
def set_depth(depth)
@context[:depth] = [@context[:depth].to_i, depth].max
end
def increment_savepoints
@context[:savepoints] = @context[:savepoints].to_i + 1
end
def increment_rollbacks
@context[:rollbacks] = @context[:rollbacks].to_i + 1
end
def increment_releases
@context[:releases] = @context[:releases].to_i + 1
end
def track_sql(sql)
(@context[:queries] ||= []).push(sql)
end
def track_backtrace(backtrace)
cleaned_backtrace = Gitlab::BacktraceCleaner.clean_backtrace(backtrace)
(@context[:backtraces] ||= []).push(cleaned_backtrace)
end
def initialize_external_http_tracking
@context[:external_http_count_start] = external_http_requests_count_total
@context[:external_http_duration_start] = external_http_requests_duration_total
end
def duration
return unless @context[:start_time].present?
current_timestamp - @context[:start_time]
end
def savepoints_threshold_exceeded?
@context[:savepoints].to_i >= LOG_SAVEPOINTS_THRESHOLD
end
def duration_threshold_exceeded?
duration.to_i >= LOG_DURATION_S_THRESHOLD
end
def external_http_requests_threshold_exceeded?
external_http_requests_count >= LOG_EXTERNAL_HTTP_COUNT_THRESHOLD ||
external_http_requests_duration >= LOG_EXTERNAL_HTTP_DURATION_S_THRESHOLD
end
def should_log?
return false if logged_already?
savepoints_threshold_exceeded? || duration_threshold_exceeded? ||
external_http_requests_threshold_exceeded?
end
def commit
log(:commit)
end
def rollback
log(:rollback)
end
def backtraces
@context[:backtraces].to_a
end
def external_http_requests_count
@requests_count ||= external_http_requests_count_total - @context[:external_http_count_start].to_i
end
def external_http_requests_duration
@requests_duration ||= external_http_requests_duration_total - @context[:external_http_duration_start].to_f
end
private
def queries
@context[:queries].to_a.join("\n")
end
def current_timestamp
::Gitlab::Metrics::System.monotonic_time
end
def logged_already?
return false if @context[:last_log_timestamp].nil?
(current_timestamp - @context[:last_log_timestamp].to_i) < LOG_THROTTLE_DURATION
end
def set_last_log_timestamp
@context[:last_log_timestamp] = current_timestamp
end
def log(operation)
return unless should_log?
set_last_log_timestamp
attributes = {
class: self.class.name,
result: operation,
duration_s: duration,
depth: @context[:depth].to_i,
savepoints_count: @context[:savepoints].to_i,
rollbacks_count: @context[:rollbacks].to_i,
releases_count: @context[:releases].to_i,
external_http_requests_count: external_http_requests_count,
external_http_requests_duration: external_http_requests_duration,
sql: queries,
savepoint_backtraces: backtraces
}
application_info(attributes)
end
def application_info(attributes)
Gitlab::AppJsonLogger.info(attributes)
end
def external_http_requests_count_total
::Gitlab::Metrics::Subscribers::ExternalHttp.request_count.to_i
end
def external_http_requests_duration_total
::Gitlab::Metrics::Subscribers::ExternalHttp.duration.to_f
end
end
end
end
end
|