Module: OneApm::Agent::Database
- Extended by:
- Database
- Included in:
- Database
- Defined in:
- lib/one_apm/agent/database.rb,
lib/one_apm/agent/database/obfuscator.rb,
lib/one_apm/agent/database/obfuscation_helpers.rb,
lib/one_apm/agent/database/postgres_explain_obfuscator.rb
Defined Under Namespace
Modules: ObfuscationHelpers, PostgresExplainObfuscator
Classes: ConnectionManager, Obfuscator, Statement
Constant Summary
collapse
- OA_MAX_QUERY_LENGTH =
16384
- OA_RECORD_FOR =
[:raw, :obfuscated].freeze
- OA_SUPPORTED_ADAPTERS_FOR_EXPLAIN =
%w[postgres postgresql mysql2 mysql sqlite].freeze
- OA_QUERY_PLAN =
'QUERY PLAN'.freeze
- OA_SQLITE_EXPLAIN_COLUMNS =
%w[addr opcode p1 p2 p3 p4 p5 comment]
- OA_KNOWN_OPERATIONS =
[
'alter',
'select',
'update',
'delete',
'insert',
'create',
'show',
'set',
'exec',
'execute',
'call'
]
Regexp.new('/\*.*?\*/', Regexp::MULTILINE).freeze
Instance Method Summary
collapse
Instance Method Details
#adapter_from_config(config) ⇒ Object
82
83
84
85
86
87
88
|
# File 'lib/one_apm/agent/database.rb', line 82
def adapter_from_config(config)
if config[:adapter]
return config[:adapter].to_s
elsif config[:uri] && config[:uri].to_s =~ /^jdbc:([^:]+):/
return $1
end
end
|
#capture_query(query) ⇒ Object
28
29
30
|
# File 'lib/one_apm/agent/database.rb', line 28
def capture_query(query)
Helper.correctly_encoded(truncate_query(query))
end
|
#close_connections ⇒ Object
78
79
80
|
# File 'lib/one_apm/agent/database.rb', line 78
def close_connections
ConnectionManager.instance.close_connections
end
|
#explain_sql(sql, connection_config, &explainer) ⇒ Object
90
91
92
93
94
95
|
# File 'lib/one_apm/agent/database.rb', line 90
def explain_sql(sql, connection_config, &explainer)
return nil unless sql && connection_config
statement = sql.split(";\n")[0] explain_plan = explain_statement(statement, connection_config, &explainer)
return explain_plan || []
end
|
#explain_statement(statement, config, &explainer) ⇒ Object
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
|
# File 'lib/one_apm/agent/database.rb', line 99
def explain_statement(statement, config, &explainer)
return unless is_select?(statement)
if statement[-3,3] == '...'
OneApm::Manager.logger.debug('Unable to collect explain plan for truncated query.')
return
end
if parameterized?(statement)
OneApm::Manager.logger.debug('Unable to collect explain plan for parameterized query.')
return
end
adapter = adapter_from_config(config)
if !OA_SUPPORTED_ADAPTERS_FOR_EXPLAIN.include?(adapter)
OneApm::Manager.logger.debug("Not collecting explain plan because an unknown connection adapter ('#{adapter}') was used.")
return
end
handle_exception_in_explain do
start = Time.now
plan = explainer.call(config, statement)
OneApm::Manager.record_metric("Supportability/Database/execute_explain_plan", Time.now - start)
return process_resultset(plan, adapter) if plan
end
end
|
#get_connection(config, &connector) ⇒ Object
74
75
76
|
# File 'lib/one_apm/agent/database.rb', line 74
def get_connection(config, &connector)
ConnectionManager.instance.get_connection(config, &connector)
end
|
#handle_exception_in_explain ⇒ Object
200
201
202
203
204
205
206
207
208
209
210
211
|
# File 'lib/one_apm/agent/database.rb', line 200
def handle_exception_in_explain
yield
rescue => e
begin
OneApm::Manager.logger.error("Error getting query plan:", e)
nil
rescue
nil
end
end
|
#is_select?(statement) ⇒ Boolean
237
238
239
|
# File 'lib/one_apm/agent/database.rb', line 237
def is_select?(statement)
parse_operation_from_query(statement) == 'select'
end
|
#obfuscate_sql(sql) ⇒ Object
40
41
42
|
# File 'lib/one_apm/agent/database.rb', line 40
def obfuscate_sql(sql)
Obfuscator.instance.obfuscator.call(sql)
end
|
#parameterized?(statement) ⇒ Boolean
241
242
243
|
# File 'lib/one_apm/agent/database.rb', line 241
def parameterized?(statement)
Obfuscator.instance.obfuscate_single_quote_literals(statement) =~ /\$\d+/
end
|
#parse_operation_from_query(sql) ⇒ Object
229
230
231
232
233
234
235
|
# File 'lib/one_apm/agent/database.rb', line 229
def parse_operation_from_query(sql)
sql = sql.gsub(OA_SQL_COMMENT_REGEX, '')
if sql =~ /(\w+)/
op = $1.downcase
return op if OA_KNOWN_OPERATIONS.include?(op)
end
end
|
#process_explain_results_mysql(results) ⇒ Object
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
# File 'lib/one_apm/agent/database.rb', line 162
def process_explain_results_mysql(results)
return string_explain_plan_results(results) if results.is_a?(String)
= []
values = []
if results.is_a?(Array)
= results.first.keys
results.each do |row|
values << .map { |h| row[h] }
end
else
results.each_hash do |row|
= row.keys
values << .map { |h| row[h] }
end
end
[, values]
end
|
#process_explain_results_mysql2(results) ⇒ Object
180
181
182
183
184
185
186
|
# File 'lib/one_apm/agent/database.rb', line 180
def process_explain_results_mysql2(results)
return string_explain_plan_results(results) if results.is_a?(String)
= results.fields
values = []
results.each { |row| values << row }
[, values]
end
|
#process_explain_results_postgres(results) ⇒ Object
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
# File 'lib/one_apm/agent/database.rb', line 141
def process_explain_results_postgres(results)
if results.is_a?(String)
query_plan_string = results
else
lines = []
results.each { |row| lines << row[OA_QUERY_PLAN] }
query_plan_string = lines.join("\n")
end
unless record_sql_method == :raw
query_plan_string = OneApm::Agent::Database::PostgresExplainObfuscator.obfuscate(query_plan_string)
end
values = query_plan_string.split("\n").map { |line| [line] }
[[OA_QUERY_PLAN], values]
end
|
#process_explain_results_sqlite(results) ⇒ Object
190
191
192
193
194
195
196
197
198
|
# File 'lib/one_apm/agent/database.rb', line 190
def process_explain_results_sqlite(results)
return string_explain_plan_results(results) if results.is_a?(String)
= OA_SQLITE_EXPLAIN_COLUMNS
values = []
results.each do |row|
values << .map { |h| row[h] }
end
[, values]
end
|
#process_resultset(results, adapter) ⇒ Object
126
127
128
129
130
131
132
133
134
135
136
137
|
# File 'lib/one_apm/agent/database.rb', line 126
def process_resultset(results, adapter)
case adapter.to_s
when 'postgres', 'postgresql'
process_explain_results_postgres(results)
when 'mysql2'
process_explain_results_mysql2(results)
when 'mysql'
process_explain_results_mysql(results)
when 'sqlite'
process_explain_results_sqlite(results)
end
end
|
#record_sql_method(config_section = :transaction_tracer) ⇒ Object
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
# File 'lib/one_apm/agent/database.rb', line 48
def record_sql_method(config_section=:transaction_tracer)
case OneApm::Manager.config["#{config_section}.record_sql".to_sym].to_s
when 'off'
:off
when 'none'
:off
when 'false'
:off
when 'raw'
:raw
else
:obfuscated
end
end
|
#set_sql_obfuscator(type, &block) ⇒ Object
44
45
46
|
# File 'lib/one_apm/agent/database.rb', line 44
def set_sql_obfuscator(type, &block)
Obfuscator.instance.set_sql_obfuscator(type, &block)
end
|
#should_collect_explain_plans?(config_section = :transaction_tracer) ⇒ Boolean
69
70
71
72
|
# File 'lib/one_apm/agent/database.rb', line 69
def should_collect_explain_plans?(config_section=:transaction_tracer)
should_record_sql?(config_section) &&
OneApm::Manager.config["#{config_section}.explain_enabled".to_sym]
end
|
#should_record_sql?(config_section = :transaction_tracer) ⇒ Boolean
65
66
67
|
# File 'lib/one_apm/agent/database.rb', line 65
def should_record_sql?(config_section=:transaction_tracer)
OA_RECORD_FOR.include?(record_sql_method(config_section))
end
|
#string_explain_plan_results(results) ⇒ Object
158
159
160
|
# File 'lib/one_apm/agent/database.rb', line 158
def string_explain_plan_results(results)
[nil, [results]]
end
|
#truncate_query(query) ⇒ Object
32
33
34
35
36
37
38
|
# File 'lib/one_apm/agent/database.rb', line 32
def truncate_query(query)
if query.length > (OA_MAX_QUERY_LENGTH - 4)
query[0..OA_MAX_QUERY_LENGTH - 4] + '...'
else
query
end
end
|