newrelic_rpm 3.16.3.323 → 3.17.0.325
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +8 -0
- data/README.md +12 -6
- data/lib/new_relic/agent/audit_logger.rb +1 -1
- data/lib/new_relic/agent/configuration/default_source.rb +15 -1
- data/lib/new_relic/agent/database.rb +5 -2
- data/lib/new_relic/agent/datastores/metric_helper.rb +8 -1
- data/lib/new_relic/agent/instrumentation/active_record.rb +15 -1
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +83 -0
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +16 -1
- data/lib/new_relic/agent/sql_sampler.rb +15 -1
- data/lib/new_relic/agent/threading/agent_thread.rb +1 -1
- data/lib/new_relic/agent/transaction/datastore_segment.rb +32 -5
- data/lib/new_relic/agent/transaction/tracing.rb +2 -2
- data/lib/new_relic/version.rb +2 -2
- data/test/environments/rails40/Gemfile +1 -1
- data/test/environments/rails41/Gemfile +1 -1
- data/test/environments/rails42/Gemfile +1 -1
- data/test/environments/rails50/Gemfile +1 -1
- data/test/fixtures/cross_agent_tests/datastores/README.md +16 -0
- data/test/fixtures/cross_agent_tests/datastores/datastore_instances.json +120 -0
- data/test/new_relic/agent/datastores/metric_helper_test.rb +38 -0
- data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +40 -0
- data/test/new_relic/agent/instrumentation/instance_identification_test.rb +186 -0
- data/test/new_relic/agent/sql_sampler_test.rb +43 -0
- data/test/new_relic/agent/transaction/datastore_segment_test.rb +118 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d92e44197eda26fe761484451437f731e71bbb1
|
4
|
+
data.tar.gz: f1c0e0554ed45e78c7d42b6617a1c98dbb7a3d3f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 92827c74e5109b6d2fd3ba456af3af0d410328b8ff5224a9ee4858e8139fa328cb5128d2fc43c316bca415b5366dca59f691473222c28c620e000c08bd17a79d
|
7
|
+
data.tar.gz: be6bd6121731993cd243c607d21a0eabab546c74c106bcf4a7a37da66a471d68311e5b67df6ca4301a07a0e7253cf20c6aeb4fb32859c34889224e77f26a088b
|
data/CHANGELOG
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# New Relic Ruby Agent Release Notes #
|
2
2
|
|
3
|
+
## v3.17.0 ##
|
4
|
+
|
5
|
+
* Datastore instance reporting for ActiveRecord
|
6
|
+
|
7
|
+
The agent now collects database instance information for ActiveRecord operations,
|
8
|
+
when using the MySQL and Postgres adapters. This information (database server
|
9
|
+
and database name) is displayed in transaction traces and slow query traces.
|
10
|
+
|
3
11
|
## v3.16.3 ##
|
4
12
|
|
5
13
|
* Add `:trace_only` option to `notice_error` API
|
data/README.md
CHANGED
@@ -78,9 +78,11 @@ edit `environment.rb` and add to the initalizer block:
|
|
78
78
|
|
79
79
|
#### Sinatra Installation
|
80
80
|
|
81
|
-
To use the Ruby Agent with a Sinatra app, add
|
81
|
+
To use the Ruby Agent with a Sinatra app, add:
|
82
82
|
|
83
|
-
|
83
|
+
```ruby
|
84
|
+
require 'newrelic_rpm'
|
85
|
+
```
|
84
86
|
|
85
87
|
in your Sinatra app, below the Sinatra require directive.
|
86
88
|
|
@@ -93,13 +95,17 @@ the middleware stack. See the `config.ru` sample below.
|
|
93
95
|
|
94
96
|
#### Other Environments
|
95
97
|
|
96
|
-
You can use the Ruby Agent to monitor any Ruby application.
|
98
|
+
You can use the Ruby Agent to monitor any Ruby application. Add:
|
97
99
|
|
98
|
-
|
100
|
+
```ruby
|
101
|
+
require 'newrelic_rpm'
|
102
|
+
```
|
99
103
|
|
100
|
-
to your startup sequence and then manually start the agent using
|
104
|
+
to your startup sequence and then manually start the agent using:
|
101
105
|
|
102
|
-
|
106
|
+
```ruby
|
107
|
+
NewRelic::Agent.manual_start
|
108
|
+
```
|
103
109
|
|
104
110
|
For information about instrumenting pure Rack applications, see our
|
105
111
|
[Rack middlewares documentation](http://docs.newrelic.com/docs/ruby/rack-middlewares).
|
@@ -40,7 +40,7 @@ module NewRelic
|
|
40
40
|
rescue StandardError, SystemStackError, SystemCallError => e
|
41
41
|
::NewRelic::Agent.logger.warn("Failed writing to audit log", e)
|
42
42
|
rescue Exception => e
|
43
|
-
::NewRelic::Agent.logger.warn("Failed writing to audit log with exception. Re-raising in case of
|
43
|
+
::NewRelic::Agent.logger.warn("Failed writing to audit log with exception. Re-raising in case of interrupt.", e)
|
44
44
|
raise
|
45
45
|
end
|
46
46
|
|
@@ -356,7 +356,7 @@ module NewRelic
|
|
356
356
|
:public => true,
|
357
357
|
:type => Boolean,
|
358
358
|
:allowed_from_server => false,
|
359
|
-
:description => 'When <code>true</code>, the agent captures HTTP request parameters and attaches them to transaction traces and
|
359
|
+
:description => 'When <code>true</code>, the agent captures HTTP request parameters and attaches them to transaction traces, traced errors, and <a href="https://docs.newrelic.com/docs/insights/new-relic-insights/decorating-events/error-event-default-attributes-insights">TransactionError events</a>.'
|
360
360
|
},
|
361
361
|
:config_path => {
|
362
362
|
:default => DefaultSource.config_path,
|
@@ -1602,6 +1602,20 @@ module NewRelic
|
|
1602
1602
|
:type => Fixnum,
|
1603
1603
|
:allowed_from_server => false,
|
1604
1604
|
:description => 'This value represents the total amount of memory available to the host (not the process), in mebibytes (1024 squared or 1,048,576 bytes).'
|
1605
|
+
},
|
1606
|
+
:'datastore_tracer.instance_reporting.enabled' => {
|
1607
|
+
:default => true,
|
1608
|
+
:public => true,
|
1609
|
+
:type => Boolean,
|
1610
|
+
:allowed_from_server => false,
|
1611
|
+
:description => 'If <code>false</code>, the agent will not report datastore instance metrics, nor add <code>host</code> or <code>port_path_or_id</code> parameters to transaction or slow sql traces.'
|
1612
|
+
},
|
1613
|
+
:'datastore_tracer.database_name_reporting.enabled' => {
|
1614
|
+
:default => true,
|
1615
|
+
:public => true,
|
1616
|
+
:type => Boolean,
|
1617
|
+
:allowed_from_server => false,
|
1618
|
+
:description => 'If <code>false</code>, the agent will not add <code>database_name</code> parameter to transaction or slow sql traces.'
|
1605
1619
|
}
|
1606
1620
|
}.freeze
|
1607
1621
|
end
|
@@ -181,16 +181,19 @@ module NewRelic
|
|
181
181
|
class Statement
|
182
182
|
include ExplainPlanHelpers
|
183
183
|
|
184
|
-
attr_accessor :sql, :config, :explainer, :binds, :name
|
184
|
+
attr_accessor :sql, :config, :explainer, :binds, :name, :host, :port_path_or_id, :database_name
|
185
185
|
|
186
186
|
DEFAULT_QUERY_NAME = "SQL".freeze
|
187
187
|
|
188
|
-
def initialize(sql, config={}, explainer=nil, binds=nil, name=DEFAULT_QUERY_NAME)
|
188
|
+
def initialize(sql, config={}, explainer=nil, binds=nil, name=DEFAULT_QUERY_NAME, host=nil, port_path_or_id=nil, database_name=nil)
|
189
189
|
@sql = Database.capture_query(sql)
|
190
190
|
@config = config
|
191
191
|
@explainer = explainer
|
192
192
|
@binds = binds
|
193
193
|
@name = name
|
194
|
+
@host = host
|
195
|
+
@port_path_or_id = port_path_or_id
|
196
|
+
@database_name = database_name
|
194
197
|
end
|
195
198
|
|
196
199
|
# This takes a connection config hash from ActiveRecord or Sequel and
|
@@ -24,6 +24,10 @@ module NewRelic
|
|
24
24
|
"Datastore/operation/#{product}/#{operation}"
|
25
25
|
end
|
26
26
|
|
27
|
+
def self.instance_metric_for(product, host, port_path_or_id)
|
28
|
+
"Datastore/instance/#{product}/#{host}/#{port_path_or_id}"
|
29
|
+
end
|
30
|
+
|
27
31
|
def self.product_suffixed_rollup(product, suffix)
|
28
32
|
"Datastore/#{product}/#{suffix}"
|
29
33
|
end
|
@@ -52,7 +56,7 @@ module NewRelic
|
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
55
|
-
def self.unscoped_metrics_for product, operation, collection=nil
|
59
|
+
def self.unscoped_metrics_for product, operation, collection=nil, host=nil, port_path_or_id=nil
|
56
60
|
suffix = all_suffix
|
57
61
|
|
58
62
|
metrics = [
|
@@ -62,6 +66,9 @@ module NewRelic
|
|
62
66
|
ROLLUP_METRIC
|
63
67
|
]
|
64
68
|
|
69
|
+
if NewRelic::Agent.config[:'datastore_tracer.instance_reporting.enabled'] && host && port_path_or_id
|
70
|
+
metrics.unshift instance_metric_for(product, host, port_path_or_id)
|
71
|
+
end
|
65
72
|
metrics.unshift operation_metric_for(product, operation) if collection
|
66
73
|
|
67
74
|
metrics
|
@@ -50,7 +50,21 @@ module NewRelic
|
|
50
50
|
NewRelic::Helper.correctly_encoded(sql),
|
51
51
|
@config && @config[:adapter])
|
52
52
|
|
53
|
-
|
53
|
+
host = nil
|
54
|
+
port_path_or_id = nil
|
55
|
+
database = nil
|
56
|
+
|
57
|
+
if ActiveRecordHelper::InstanceIdentification.supported_adapter?(@config)
|
58
|
+
if NewRelic::Agent.config[:'datastore_tracer.instance_reporting.enabled']
|
59
|
+
host = ActiveRecordHelper::InstanceIdentification.host(@config)
|
60
|
+
port_path_or_id = ActiveRecordHelper::InstanceIdentification.port_path_or_id(@config)
|
61
|
+
end
|
62
|
+
if NewRelic::Agent.config[:'datastore_tracer.database_name_reporting.enabled']
|
63
|
+
database = @config && @config[:database]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
segment = NewRelic::Agent::Transaction.start_datastore_segment(product, operation, collection, host, port_path_or_id, database)
|
54
68
|
segment._notice_sql(sql, @config, EXPLAINER)
|
55
69
|
|
56
70
|
begin
|
@@ -204,6 +204,89 @@ module NewRelic
|
|
204
204
|
ACTIVE_RECORD_DEFAULT_PRODUCT_NAME)
|
205
205
|
end
|
206
206
|
|
207
|
+
module InstanceIdentification
|
208
|
+
extend self
|
209
|
+
|
210
|
+
LOCALHOST = %w[
|
211
|
+
localhost
|
212
|
+
0.0.0.0
|
213
|
+
127.0.0.1
|
214
|
+
0:0:0:0:0:0:0:1
|
215
|
+
0:0:0:0:0:0:0:0
|
216
|
+
::1
|
217
|
+
::
|
218
|
+
].freeze unless defined?(LOCALHOST)
|
219
|
+
|
220
|
+
PRODUCT_SYMBOLS = {
|
221
|
+
"mysql" => :mysql,
|
222
|
+
"mysql2" => :mysql,
|
223
|
+
"jdbcmysql" => :mysql,
|
224
|
+
|
225
|
+
"postgresql" => :postgres,
|
226
|
+
"jdbcpostgresql" => :postgres
|
227
|
+
}.freeze unless defined?(PRODUCT_SYMBOLS)
|
228
|
+
|
229
|
+
DATASTORE_DEFAULT_PORTS = {
|
230
|
+
:mysql => "3306",
|
231
|
+
:postgres => "5432"
|
232
|
+
}.freeze unless defined?(DATASTORE_DEFAULT_PORTS)
|
233
|
+
|
234
|
+
DEFAULT = "default".freeze unless defined?(DEFAULT)
|
235
|
+
UNKNOWN = "unknown".freeze unless defined?(UNKNOWN)
|
236
|
+
SLASH = "/".freeze unless defined?(SLASH)
|
237
|
+
|
238
|
+
def host(config)
|
239
|
+
return UNKNOWN unless config
|
240
|
+
|
241
|
+
configured_value = config[:host]
|
242
|
+
adapter = PRODUCT_SYMBOLS[config[:adapter]]
|
243
|
+
if configured_value.nil? ||
|
244
|
+
LOCALHOST.include?(configured_value) ||
|
245
|
+
postgres_unix_domain_socket_case?(configured_value, adapter)
|
246
|
+
|
247
|
+
Hostname.get
|
248
|
+
elsif configured_value.empty?
|
249
|
+
UNKNOWN
|
250
|
+
else
|
251
|
+
configured_value
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def port_path_or_id(config)
|
256
|
+
return UNKNOWN unless config
|
257
|
+
|
258
|
+
adapter = PRODUCT_SYMBOLS[config[:adapter]]
|
259
|
+
if config[:socket]
|
260
|
+
config[:socket].empty? ? UNKNOWN : config[:socket]
|
261
|
+
elsif postgres_unix_domain_socket_case?(config[:host], adapter) || mysql_default_case?(config, adapter)
|
262
|
+
DEFAULT
|
263
|
+
elsif config[:port].nil?
|
264
|
+
DATASTORE_DEFAULT_PORTS[adapter] || DEFAULT
|
265
|
+
elsif config[:port].is_a?(Fixnum) || config[:port].to_i != 0
|
266
|
+
config[:port].to_s
|
267
|
+
else
|
268
|
+
UNKNOWN
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
SUPPORTED_ADAPTERS = [:mysql, :postgres].freeze unless defined?(SUPPORTED_ADAPTERS)
|
273
|
+
|
274
|
+
def supported_adapter? config
|
275
|
+
config && SUPPORTED_ADAPTERS.include?(PRODUCT_SYMBOLS[config[:adapter]])
|
276
|
+
end
|
277
|
+
|
278
|
+
private
|
279
|
+
|
280
|
+
def postgres_unix_domain_socket_case?(host, adapter)
|
281
|
+
adapter == :postgres && host && host.start_with?(SLASH)
|
282
|
+
end
|
283
|
+
|
284
|
+
def mysql_default_case?(config, adapter)
|
285
|
+
(adapter == :mysql2 || adapter == :mysql) &&
|
286
|
+
LOCALHOST.include?(config[:host]) &&
|
287
|
+
!config[:port]
|
288
|
+
end
|
289
|
+
end
|
207
290
|
end
|
208
291
|
end
|
209
292
|
end
|
@@ -85,7 +85,22 @@ module NewRelic
|
|
85
85
|
def start_segment
|
86
86
|
product, operation, collection = ActiveRecordHelper.product_operation_collection_for(payload[:name],
|
87
87
|
sql, @config && @config[:adapter])
|
88
|
-
|
88
|
+
|
89
|
+
host = nil
|
90
|
+
port_path_or_id = nil
|
91
|
+
database = nil
|
92
|
+
|
93
|
+
if ActiveRecordHelper::InstanceIdentification.supported_adapter?(@config)
|
94
|
+
if NewRelic::Agent.config[:'datastore_tracer.instance_reporting.enabled']
|
95
|
+
host = ActiveRecordHelper::InstanceIdentification.host(@config)
|
96
|
+
port_path_or_id = ActiveRecordHelper::InstanceIdentification.port_path_or_id(@config)
|
97
|
+
end
|
98
|
+
if NewRelic::Agent.config[:'datastore_tracer.database_name_reporting.enabled']
|
99
|
+
database = @config && @config[:database]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
segment = NewRelic::Agent::Transaction::DatastoreSegment.new product, operation, collection, host, port_path_or_id, database
|
89
104
|
if txn = state.current_transaction
|
90
105
|
segment.transaction = txn
|
91
106
|
end
|
@@ -236,6 +236,20 @@ module NewRelic
|
|
236
236
|
statement.sql
|
237
237
|
end
|
238
238
|
|
239
|
+
def base_params
|
240
|
+
params = {}
|
241
|
+
|
242
|
+
if NewRelic::Agent.config[:'datastore_tracer.instance_reporting.enabled']
|
243
|
+
params[:host] = statement.host if statement.host
|
244
|
+
params[:port_path_or_id] = statement.port_path_or_id if statement.port_path_or_id
|
245
|
+
end
|
246
|
+
if NewRelic::Agent.config[:'datastore_tracer.database_name_reporting.enabled'] && statement.database_name
|
247
|
+
params[:database_name] = statement.database_name
|
248
|
+
end
|
249
|
+
|
250
|
+
params
|
251
|
+
end
|
252
|
+
|
239
253
|
def obfuscate
|
240
254
|
NewRelic::Agent::Database.obfuscate_sql(statement)
|
241
255
|
end
|
@@ -268,7 +282,7 @@ module NewRelic
|
|
268
282
|
|
269
283
|
def initialize(normalized_query, slow_sql, path, uri)
|
270
284
|
super()
|
271
|
-
@params =
|
285
|
+
@params = slow_sql.base_params
|
272
286
|
@sql_id = consistent_hash(normalized_query)
|
273
287
|
set_primary slow_sql, path, uri
|
274
288
|
record_data_point(float(slow_sql.duration))
|
@@ -15,7 +15,7 @@ module NewRelic
|
|
15
15
|
rescue => e
|
16
16
|
::NewRelic::Agent.logger.error("Thread #{label} exited with error", e)
|
17
17
|
rescue Exception => e
|
18
|
-
::NewRelic::Agent.logger.error("Thread #{label} exited with exception. Re-raising in case of
|
18
|
+
::NewRelic::Agent.logger.error("Thread #{label} exited with exception. Re-raising in case of interrupt.", e)
|
19
19
|
raise
|
20
20
|
ensure
|
21
21
|
::NewRelic::Agent.logger.debug("Exiting New Relic thread: #{label}")
|
@@ -10,15 +10,18 @@ module NewRelic
|
|
10
10
|
module Agent
|
11
11
|
class Transaction
|
12
12
|
class DatastoreSegment < Segment
|
13
|
-
attr_reader :product, :operation, :collection, :sql_statement
|
13
|
+
attr_reader :product, :operation, :collection, :sql_statement, :host, :port_path_or_id, :database_name
|
14
14
|
|
15
|
-
def initialize product, operation, collection = nil
|
15
|
+
def initialize product, operation, collection = nil, host = nil, port_path_or_id = nil, database_name=nil
|
16
16
|
@product = product
|
17
17
|
@operation = operation
|
18
18
|
@collection = collection
|
19
19
|
@sql_statement = nil
|
20
|
+
@host = host
|
21
|
+
@port_path_or_id = port_path_or_id
|
22
|
+
@database_name = database_name
|
20
23
|
super Datastores::MetricHelper.scoped_metric_for(product, operation, collection),
|
21
|
-
Datastores::MetricHelper.unscoped_metrics_for(product, operation, collection)
|
24
|
+
Datastores::MetricHelper.unscoped_metrics_for(product, operation, collection, host, port_path_or_id)
|
22
25
|
end
|
23
26
|
|
24
27
|
def notice_sql sql
|
@@ -28,14 +31,38 @@ module NewRelic
|
|
28
31
|
# @api private
|
29
32
|
def _notice_sql sql, config=nil, explainer=nil, binds=nil, name=nil
|
30
33
|
return unless record_sql?
|
31
|
-
@sql_statement = Database::Statement.new sql, config, explainer, binds, name
|
34
|
+
@sql_statement = Database::Statement.new sql, config, explainer, binds, name, host, port_path_or_id, database_name
|
32
35
|
end
|
33
36
|
|
34
37
|
private
|
35
38
|
|
36
39
|
def segment_complete
|
37
|
-
|
40
|
+
add_segment_parameters
|
41
|
+
notice_sql_statement if sql_statement
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_segment_parameters
|
45
|
+
instance_reporting_enabled = NewRelic::Agent.config[:'datastore_tracer.instance_reporting.enabled']
|
46
|
+
db_name_reporting_enabled = NewRelic::Agent.config[:'datastore_tracer.database_name_reporting.enabled']
|
47
|
+
return unless instance_reporting_enabled || db_name_reporting_enabled
|
48
|
+
|
49
|
+
params = {}
|
50
|
+
add_instance_parameters params if instance_reporting_enabled
|
51
|
+
add_database_name_parameter params if db_name_reporting_enabled
|
52
|
+
|
53
|
+
NewRelic::Agent.instance.transaction_sampler.add_node_parameters params
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_instance_parameters params
|
57
|
+
params[:host] = host if host
|
58
|
+
params[:port_path_or_id] = port_path_or_id if port_path_or_id
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_database_name_parameter(params)
|
62
|
+
params[:database_name] = database_name if database_name
|
63
|
+
end
|
38
64
|
|
65
|
+
def notice_sql_statement
|
39
66
|
NewRelic::Agent.instance.transaction_sampler.notice_sql_statement(sql_statement, duration)
|
40
67
|
NewRelic::Agent.instance.sql_sampler.notice_sql_statement(sql_statement.dup, name, duration)
|
41
68
|
end
|
@@ -17,8 +17,8 @@ module NewRelic
|
|
17
17
|
segment
|
18
18
|
end
|
19
19
|
|
20
|
-
def start_datastore_segment product, operation, collection=nil
|
21
|
-
segment = DatastoreSegment.new product, operation, collection
|
20
|
+
def start_datastore_segment product, operation, collection=nil, host=nil, port_path_or_id=nil, database_name=nil
|
21
|
+
segment = DatastoreSegment.new product, operation, collection, host, port_path_or_id, database_name
|
22
22
|
segment.start
|
23
23
|
add_segment segment
|
24
24
|
segment
|
data/lib/new_relic/version.rb
CHANGED
@@ -22,7 +22,7 @@ end
|
|
22
22
|
# us from inadvertently loading minitest 5.3.0 on rbx (we'll require
|
23
23
|
# minitest/unit instead via a different path).
|
24
24
|
gem 'minitest', '~>4.7.5', :require => false
|
25
|
-
gem 'mocha', :require => false
|
25
|
+
gem 'mocha', '1.1', :require => false
|
26
26
|
gem 'rack', '< 2.0.0'
|
27
27
|
gem 'rack-test'
|
28
28
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
## Datastore instance tests
|
2
|
+
|
3
|
+
The datastore instance tests provide attributes similar to what an agent could expect to find regarding a database configuration and specifies the expected [datastore instance metric](https://source.datanerd.us/agents/agent-specs/blob/master/Datastore-Metrics-PORTED.md#datastore-metric-namespace) that should be generated. The table below lists types attributes and whether will will always be included or optionally included in each test case.
|
4
|
+
|
5
|
+
| Name | Present | Description |
|
6
|
+
|---|---|---|
|
7
|
+
| system_hostname | always | the hostname of the machine |
|
8
|
+
| db_hostname | sometimes | the hostname reported by the database adapter |
|
9
|
+
| product | always | the database product for this configuration
|
10
|
+
| port | sometimes | the port reported by the database adapter |
|
11
|
+
| unix_socket | sometimes |the path to a unix domain socket reported by a database adapter |
|
12
|
+
| db_path | sometimes |the path to a filesystem database |
|
13
|
+
| expected\_instance\_metric | always | the instance metric expected to be generated from the given attributes |
|
14
|
+
|
15
|
+
## Implementing the test cases
|
16
|
+
The idea behind these test cases are that you are able to determine a set of configuration properties from a database connection, and based on those properties you should generate the `expected_instance_metric`. Sometimes the properties available are minimal and will mean that you will need to fall back to defaults to obtain some of the information. When there is missing information from a database adapter the guiding principle is to fill in the defaults when they can be inferred, but do not make guesses that could be incorrect or misleading. Some agents may have access to better data and may not need to make inferences. If this applies to your agent then many of these tests will not be applicable.
|
@@ -0,0 +1,120 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"name": "instance metric uses system hostname when db reports localhost",
|
4
|
+
"system_hostname": "datanerd-01",
|
5
|
+
"db_hostname": "localhost",
|
6
|
+
"product": "Postgres",
|
7
|
+
"port": 5432,
|
8
|
+
"expected_instance_metric": "Datastore/instance/Postgres/datanerd-01/5432"
|
9
|
+
},
|
10
|
+
{
|
11
|
+
"name": "instance metric uses system hostname when db reports host as loopback adapter IPv4",
|
12
|
+
"system_hostname": "datanerd-01",
|
13
|
+
"db_hostname": "127.0.0.1",
|
14
|
+
"product": "Postgres",
|
15
|
+
"port": 5252,
|
16
|
+
"expected_instance_metric": "Datastore/instance/Postgres/datanerd-01/5252"
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"name": "instance metric uses system hostname when db reports host as loopback adapter IPv6",
|
20
|
+
"system_hostname": "datanerd-01",
|
21
|
+
"db_hostname": "0:0:0:0:0:0:0:1",
|
22
|
+
"product": "Postgres",
|
23
|
+
"port": 5252,
|
24
|
+
"expected_instance_metric": "Datastore/instance/Postgres/datanerd-01/5252"
|
25
|
+
},
|
26
|
+
{
|
27
|
+
"name": "instance metric uses system hostname when db reports host as loopback adapter IPv6 shorthand",
|
28
|
+
"system_hostname": "datanerd-01",
|
29
|
+
"db_hostname": "::1",
|
30
|
+
"product": "Postgres",
|
31
|
+
"port": 5252,
|
32
|
+
"expected_instance_metric": "Datastore/instance/Postgres/datanerd-01/5252"
|
33
|
+
},
|
34
|
+
{
|
35
|
+
"name": "instance metric uses system hostname when db reports default host IPv4",
|
36
|
+
"system_hostname": "datanerd-01",
|
37
|
+
"db_hostname": "0.0.0.0",
|
38
|
+
"product": "MySQL",
|
39
|
+
"port": 3600,
|
40
|
+
"expected_instance_metric": "Datastore/instance/MySQL/datanerd-01/3600"
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"name": "instance metric uses system hostname when db reports default host IPv6",
|
44
|
+
"system_hostname": "datanerd-01",
|
45
|
+
"db_hostname": "0:0:0:0:0:0:0:0",
|
46
|
+
"product": "MySQL",
|
47
|
+
"port": 5757,
|
48
|
+
"expected_instance_metric": "Datastore/instance/MySQL/datanerd-01/5757"
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"name": "instance metric uses system hostname when db reports default host IPv6 shorthand",
|
52
|
+
"system_hostname": "datanerd-01",
|
53
|
+
"db_hostname": "::",
|
54
|
+
"product": "MySQL",
|
55
|
+
"port": 5757,
|
56
|
+
"expected_instance_metric": "Datastore/instance/MySQL/datanerd-01/5757"
|
57
|
+
},
|
58
|
+
{
|
59
|
+
"name": "instance metric uses db host when not local",
|
60
|
+
"system_hostname": "datanerd-01",
|
61
|
+
"db_hostname": "accounts-db",
|
62
|
+
"product": "MySQL",
|
63
|
+
"port": 8420,
|
64
|
+
"expected_instance_metric": "Datastore/instance/MySQL/accounts-db/8420"
|
65
|
+
},
|
66
|
+
{
|
67
|
+
"name": "detects default UDS case",
|
68
|
+
"system_hostname": "datanerd-01",
|
69
|
+
"db_hostname": "localhost",
|
70
|
+
"product": "MySQL",
|
71
|
+
"expected_instance_metric": "Datastore/instance/MySQL/datanerd-01/default"
|
72
|
+
},
|
73
|
+
{
|
74
|
+
"name": "instance metric uses unix socket path if provided",
|
75
|
+
"system_hostname": "datanerd-01",
|
76
|
+
"db_hostname": "localhost",
|
77
|
+
"product": "MySQL",
|
78
|
+
"unix_socket": "/var/mysql/mysql.sock",
|
79
|
+
"expected_instance_metric": "Datastore/instance/MySQL/datanerd-01//var/mysql/mysql.sock"
|
80
|
+
},
|
81
|
+
{
|
82
|
+
"name": "instance metric reports unknown if host empty",
|
83
|
+
"system_hostname": "datanerd-01",
|
84
|
+
"db_hostname": "",
|
85
|
+
"product": "MySQL",
|
86
|
+
"port": 3600,
|
87
|
+
"expected_instance_metric": "Datastore/instance/MySQL/unknown/3600"
|
88
|
+
},
|
89
|
+
{
|
90
|
+
"name": "instance metric reports unknown if port empty",
|
91
|
+
"system_hostname": "datanerd-01",
|
92
|
+
"db_hostname": "localhost",
|
93
|
+
"product": "MySQL",
|
94
|
+
"port": "",
|
95
|
+
"expected_instance_metric": "Datastore/instance/MySQL/datanerd-01/unknown"
|
96
|
+
},
|
97
|
+
{
|
98
|
+
"name": "instance metric reports unknown if unix_socket empty",
|
99
|
+
"system_hostname": "datanerd-01",
|
100
|
+
"db_hostname": "localhost",
|
101
|
+
"product": "MySQL",
|
102
|
+
"unix_socket": "",
|
103
|
+
"expected_instance_metric": "Datastore/instance/MySQL/datanerd-01/unknown"
|
104
|
+
},
|
105
|
+
{
|
106
|
+
"name": "instance metric with ip v6 host",
|
107
|
+
"system_hostname": "datanerd-01",
|
108
|
+
"db_hostname": "2001:0DB8:AC10:FE01:0000:0000:0000:0000",
|
109
|
+
"product": "Postgres",
|
110
|
+
"port": 5432,
|
111
|
+
"expected_instance_metric": "Datastore/instance/Postgres/2001:0DB8:AC10:FE01:0000:0000:0000:0000/5432"
|
112
|
+
},
|
113
|
+
{
|
114
|
+
"name": "instance metric for filesystem database",
|
115
|
+
"system_hostname": "datanerd-01",
|
116
|
+
"product": "SQLite",
|
117
|
+
"database_path": "/db/all.sqlite3",
|
118
|
+
"expected_instance_metric": "Datastore/instance/SQLite/datanerd-01//db/all.sqlite3"
|
119
|
+
}
|
120
|
+
]
|
@@ -26,6 +26,15 @@ module NewRelic
|
|
26
26
|
assert_equal expected, result
|
27
27
|
end
|
28
28
|
|
29
|
+
def test_instance_metric_for
|
30
|
+
instance_id = "localhost/1337807"
|
31
|
+
host = "localhost"
|
32
|
+
port = "1337807"
|
33
|
+
expected = "Datastore/instance/JonanDB/#{host}/#{port}"
|
34
|
+
result = Datastores::MetricHelper.instance_metric_for(@product, host, port)
|
35
|
+
assert_equal expected, result
|
36
|
+
end
|
37
|
+
|
29
38
|
def test_metrics_for_in_web_context
|
30
39
|
Transaction.stubs(:recording_web_transaction?).returns(true)
|
31
40
|
expected = [
|
@@ -109,6 +118,35 @@ module NewRelic
|
|
109
118
|
assert_equal expected, result
|
110
119
|
end
|
111
120
|
|
121
|
+
def test_unscoped_metrics_for_with_instance_identifier
|
122
|
+
Transaction.stubs(:recording_web_transaction?).returns(false)
|
123
|
+
expected = [
|
124
|
+
"Datastore/instance/JonanDB/localhost/1337807",
|
125
|
+
"Datastore/JonanDB/allOther",
|
126
|
+
"Datastore/JonanDB/all",
|
127
|
+
"Datastore/allOther",
|
128
|
+
"Datastore/all"
|
129
|
+
]
|
130
|
+
|
131
|
+
result = Datastores::MetricHelper.unscoped_metrics_for(@product, @operation, nil, "localhost", "1337807")
|
132
|
+
assert_equal expected, result
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_unscoped_metrics_for_with_instance_identifier_and_instance_reporting_disabled
|
136
|
+
with_config(:'datastore_tracer.instance_reporting.enabled' => false) do
|
137
|
+
Transaction.stubs(:recording_web_transaction?).returns(false)
|
138
|
+
expected = [
|
139
|
+
"Datastore/JonanDB/allOther",
|
140
|
+
"Datastore/JonanDB/all",
|
141
|
+
"Datastore/allOther",
|
142
|
+
"Datastore/all"
|
143
|
+
]
|
144
|
+
|
145
|
+
result = Datastores::MetricHelper.unscoped_metrics_for(@product, @operation, nil, "localhost/1337807")
|
146
|
+
assert_equal expected, result
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
112
150
|
def test_product_operation_collection_for_obeys_collection_and_operation_overrides
|
113
151
|
in_transaction do
|
114
152
|
NewRelic::Agent.with_database_metric_name("Model", "new_method") do
|
@@ -52,6 +52,46 @@ class NewRelic::Agent::Instrumentation::ActiveRecordSubscriberTest < Minitest::T
|
|
52
52
|
)
|
53
53
|
end
|
54
54
|
|
55
|
+
def test_records_datastore_instance_metric_for_supported_adapter
|
56
|
+
config = { :adapter => "mysql", :host => "jonan.gummy_planet", :port => 3306 }
|
57
|
+
@subscriber.stubs(:active_record_config).returns(config)
|
58
|
+
|
59
|
+
simulate_query(2)
|
60
|
+
|
61
|
+
assert_metrics_recorded('Datastore/instance/MySQL/jonan.gummy_planet/3306')
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_does_not_record_datastore_instance_metric_for_unsupported_adapter
|
65
|
+
config = { :adapter => "JonanDB", :host => "jonan.gummy_planet" }
|
66
|
+
@subscriber.stubs(:active_record_config).returns(config)
|
67
|
+
|
68
|
+
simulate_query(2)
|
69
|
+
|
70
|
+
assert_metrics_not_recorded('Datastore/instance/JonanDB/jonan.gummy_planet/default')
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_does_not_record_datastore_instance_metric_if_disabled
|
74
|
+
with_config('datastore_tracer.instance_reporting.enabled' => false) do
|
75
|
+
config = { :host => "jonan.gummy_planet" }
|
76
|
+
@subscriber.stubs(:active_record_config).returns(config)
|
77
|
+
|
78
|
+
simulate_query(2)
|
79
|
+
|
80
|
+
assert_metrics_not_recorded('Datastore/instance/ActiveRecord/jonan.gummy_planet/default')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_does_not_record_database_name_if_disabled
|
85
|
+
config = { :host => "jonan.gummy_planet", :database => "pizza_cube" }
|
86
|
+
@subscriber.stubs(:active_record_config).returns(config)
|
87
|
+
with_config('datastore_tracer.database_name_reporting.enabled' => false) do
|
88
|
+
in_transaction { simulate_query(2) }
|
89
|
+
end
|
90
|
+
sample = NewRelic::Agent.instance.transaction_sampler.last_sample
|
91
|
+
node = find_node_with_name_matching sample, /Datastore\//
|
92
|
+
refute node.params.key?(:database_name)
|
93
|
+
end
|
94
|
+
|
55
95
|
def test_records_nothing_if_tracing_disabled
|
56
96
|
freeze_time
|
57
97
|
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','test_helper'))
|
5
|
+
require 'new_relic/agent/instrumentation/active_record_helper'
|
6
|
+
|
7
|
+
module NewRelic
|
8
|
+
module Agent
|
9
|
+
module Instrumentation
|
10
|
+
module ActiveRecordHelper
|
11
|
+
class InstanceIdentificationTest < Minitest::Test
|
12
|
+
|
13
|
+
def test_for_constructs_id_with_configured_host_and_port
|
14
|
+
config = {
|
15
|
+
:host => "jonan.local",
|
16
|
+
:port => 42
|
17
|
+
}
|
18
|
+
|
19
|
+
host = InstanceIdentification.host(config)
|
20
|
+
ppid = InstanceIdentification.port_path_or_id(config)
|
21
|
+
|
22
|
+
assert_equal "jonan.local", host
|
23
|
+
assert_equal "42", ppid
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_for_constructs_id_with_unspecified_configuration
|
27
|
+
NewRelic::Agent::Hostname.stubs(:get).returns("jonan.pizza_cube")
|
28
|
+
config = {}
|
29
|
+
host = InstanceIdentification.host(config)
|
30
|
+
ppid = InstanceIdentification.port_path_or_id(config)
|
31
|
+
|
32
|
+
assert_equal "jonan.pizza_cube", host
|
33
|
+
assert_equal "default", ppid
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_for_constructs_id_with_weird_configs
|
37
|
+
config = {
|
38
|
+
:host => "",
|
39
|
+
:port => ""
|
40
|
+
}
|
41
|
+
|
42
|
+
host = InstanceIdentification.host(config)
|
43
|
+
ppid = InstanceIdentification.port_path_or_id(config)
|
44
|
+
|
45
|
+
assert_equal "unknown", host
|
46
|
+
assert_equal "unknown", ppid
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_for_constructs_id_with_configured_host_without_port
|
50
|
+
config = { :host => "jonan.gummy_planet" }
|
51
|
+
|
52
|
+
host = InstanceIdentification.host(config)
|
53
|
+
ppid = InstanceIdentification.port_path_or_id(config)
|
54
|
+
|
55
|
+
assert_equal "jonan.gummy_planet", host
|
56
|
+
assert_equal "default", ppid
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_for_constructs_id_with_port_without_host
|
60
|
+
NewRelic::Agent::Hostname.stubs(:get).returns("jonan.pizza_cube")
|
61
|
+
config = { :port => 1337 }
|
62
|
+
|
63
|
+
host = InstanceIdentification.host(config)
|
64
|
+
ppid = InstanceIdentification.port_path_or_id(config)
|
65
|
+
|
66
|
+
assert_equal "jonan.pizza_cube", host
|
67
|
+
assert_equal "1337", ppid
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_for_constructs_id_with_detected_localhost
|
71
|
+
NewRelic::Agent::Hostname.stubs(:get).returns("jonan.pizza_cube")
|
72
|
+
|
73
|
+
%w[localhost 0.0.0.0 127.0.0.1 0:0:0:0:0:0:0:1 0:0:0:0:0:0:0:0 ::1 ::].each do |host|
|
74
|
+
config = { :host => host }
|
75
|
+
|
76
|
+
host = InstanceIdentification.host(config)
|
77
|
+
ppid = InstanceIdentification.port_path_or_id(config)
|
78
|
+
|
79
|
+
assert_equal "jonan.pizza_cube", host
|
80
|
+
assert_equal "default", ppid
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_for_constructs_id_with_default_port
|
85
|
+
config = {
|
86
|
+
:adapter => "mysql",
|
87
|
+
:host => "jonan.gummy_planet"
|
88
|
+
}
|
89
|
+
|
90
|
+
host = InstanceIdentification.host(config)
|
91
|
+
ppid = InstanceIdentification.port_path_or_id(config)
|
92
|
+
|
93
|
+
assert_equal "jonan.gummy_planet", host
|
94
|
+
assert_equal "3306", ppid
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_for_constructs_id_with_postgres_directory
|
98
|
+
NewRelic::Agent::Hostname.stubs(:get).returns("jonan.pizza_cube")
|
99
|
+
config = {
|
100
|
+
:adapter => "postgresql",
|
101
|
+
:host => "/tmp"
|
102
|
+
}
|
103
|
+
|
104
|
+
host = InstanceIdentification.host(config)
|
105
|
+
ppid = InstanceIdentification.port_path_or_id(config)
|
106
|
+
|
107
|
+
assert_equal "jonan.pizza_cube", host
|
108
|
+
assert_equal "default", ppid
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_for_constructs_id_with_mysql_socket
|
112
|
+
NewRelic::Agent::Hostname.stubs(:get).returns("jonan.pizza_cube")
|
113
|
+
%w[ mysql mysql2 jdbcmysql ].each do |adapter|
|
114
|
+
config = {
|
115
|
+
:adapter => adapter,
|
116
|
+
:socket => "/var/run/mysqld.sock"
|
117
|
+
}
|
118
|
+
|
119
|
+
host = InstanceIdentification.host(config)
|
120
|
+
ppid = InstanceIdentification.port_path_or_id(config)
|
121
|
+
|
122
|
+
assert_equal "jonan.pizza_cube", host
|
123
|
+
assert_equal "/var/run/mysqld.sock", ppid
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_supports_supported_adapters
|
128
|
+
%w(mysql mysql2 postgresql).each do |adapter|
|
129
|
+
assert InstanceIdentification.supported_adapter?({:adapter => adapter })
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
SUPPORTED_PRODUCTS = ["Postgres", "MySQL"]
|
134
|
+
|
135
|
+
load_cross_agent_test('datastores/datastore_instances').each do |test|
|
136
|
+
next unless SUPPORTED_PRODUCTS.include?(test['product'])
|
137
|
+
|
138
|
+
define_method :"test_#{test['name'].tr(' ', '_')}" do
|
139
|
+
NewRelic::Agent.drop_buffered_data
|
140
|
+
NewRelic::Agent::Hostname.stubs(:get).returns(test['system_hostname'])
|
141
|
+
|
142
|
+
config = convert_test_case_to_config test
|
143
|
+
|
144
|
+
product, operation, collection = ActiveRecordHelper.product_operation_collection_for "Blog Find", nil , config[:adapter]
|
145
|
+
host = ActiveRecordHelper::InstanceIdentification.host(config)
|
146
|
+
port_path_or_id = ActiveRecordHelper::InstanceIdentification.port_path_or_id(config)
|
147
|
+
|
148
|
+
segment = NewRelic::Agent::Transaction.start_datastore_segment product, operation, collection, host, port_path_or_id
|
149
|
+
segment.finish
|
150
|
+
|
151
|
+
assert_metrics_recorded test['expected_instance_metric']
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
CONFIG_NAMES = {
|
156
|
+
"db_hostname" => :host,
|
157
|
+
"unix_socket" => :socket,
|
158
|
+
"port" => :port,
|
159
|
+
"product" => :adapter
|
160
|
+
}
|
161
|
+
|
162
|
+
def convert_test_case_to_config test_case
|
163
|
+
config = test_case.inject({}) do |memo, (k,v)|
|
164
|
+
if config_key = CONFIG_NAMES[k]
|
165
|
+
memo[config_key] = v
|
166
|
+
end
|
167
|
+
memo
|
168
|
+
end
|
169
|
+
convert_product_to_adapter config
|
170
|
+
config
|
171
|
+
end
|
172
|
+
|
173
|
+
PRODUCT_TO_ADAPTER_NAMES = {
|
174
|
+
"Postgres" => "postgresql",
|
175
|
+
"MySQL" => "mysql",
|
176
|
+
"SQLite" => "sqlite3"
|
177
|
+
}
|
178
|
+
|
179
|
+
def convert_product_to_adapter config
|
180
|
+
config[:adapter] = PRODUCT_TO_ADAPTER_NAMES[config[:adapter]]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -370,6 +370,49 @@ class NewRelic::Agent::SqlSamplerTest < Minitest::Test
|
|
370
370
|
assert_equal expected, trace.to_collector_array(marshaller.default_encoder)
|
371
371
|
end
|
372
372
|
|
373
|
+
def test_to_collector_array_with_database_instance_params
|
374
|
+
statement = NewRelic::Agent::Database::Statement.new("query", nil, nil, nil, nil, "jonan.gummy_planet", "1337", "pizza_cube")
|
375
|
+
slow = NewRelic::Agent::SlowSql.new(statement, "transaction", 1.0)
|
376
|
+
trace = NewRelic::Agent::SqlTrace.new("query", slow, "path", "uri")
|
377
|
+
encoder = NewRelic::Agent::NewRelicService::Encoders::Identity
|
378
|
+
|
379
|
+
params = trace.to_collector_array(encoder).last
|
380
|
+
|
381
|
+
assert_equal "jonan.gummy_planet", params[:host]
|
382
|
+
assert_equal "1337", params[:port_path_or_id]
|
383
|
+
assert_equal "pizza_cube", params[:database_name]
|
384
|
+
end
|
385
|
+
|
386
|
+
def test_to_collector_array_with_instance_reporting_disabled
|
387
|
+
with_config(:'datastore_tracer.instance_reporting.enabled' => false) do
|
388
|
+
statement = NewRelic::Agent::Database::Statement.new("query", nil, nil, nil, nil, "jonan.gummy_planet", "1337", "pizza_cube")
|
389
|
+
slow = NewRelic::Agent::SlowSql.new(statement, "transaction", 1.0)
|
390
|
+
trace = NewRelic::Agent::SqlTrace.new("query", slow, "path", "uri")
|
391
|
+
encoder = NewRelic::Agent::NewRelicService::Encoders::Identity
|
392
|
+
|
393
|
+
params = trace.to_collector_array(encoder).last
|
394
|
+
|
395
|
+
refute params.key? :host
|
396
|
+
refute params.key? :port_path_or_id
|
397
|
+
assert_equal "pizza_cube", params[:database_name]
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def test_to_collector_array_with_database_name_reporting_disabled
|
402
|
+
with_config(:'datastore_tracer.database_name_reporting.enabled' => false) do
|
403
|
+
statement = NewRelic::Agent::Database::Statement.new("query", nil, nil, nil, nil, "jonan.gummy_planet", "1337", "pizza_cube")
|
404
|
+
slow = NewRelic::Agent::SlowSql.new(statement, "transaction", 1.0)
|
405
|
+
trace = NewRelic::Agent::SqlTrace.new("query", slow, "path", "uri")
|
406
|
+
encoder = NewRelic::Agent::NewRelicService::Encoders::Identity
|
407
|
+
|
408
|
+
params = trace.to_collector_array(encoder).last
|
409
|
+
|
410
|
+
assert_equal "jonan.gummy_planet", params[:host]
|
411
|
+
assert_equal "1337", params[:port_path_or_id]
|
412
|
+
refute params.key? :database_name
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
373
416
|
def test_merge_without_existing_trace
|
374
417
|
query = "select * from test"
|
375
418
|
statement = NewRelic::Agent::Database::Statement.new(query, {})
|
@@ -63,6 +63,103 @@ module NewRelic
|
|
63
63
|
]
|
64
64
|
end
|
65
65
|
|
66
|
+
def test_segment_records_expected_metrics_with_instance_identifier
|
67
|
+
Transaction.stubs(:recording_web_transaction?).returns(true)
|
68
|
+
|
69
|
+
segment = DatastoreSegment.new "SQLite", "select", nil, "localhost", "1337807"
|
70
|
+
segment.start
|
71
|
+
advance_time 1
|
72
|
+
segment.finish
|
73
|
+
|
74
|
+
assert_metrics_recorded [
|
75
|
+
"Datastore/instance/SQLite/localhost/1337807",
|
76
|
+
"Datastore/operation/SQLite/select",
|
77
|
+
"Datastore/SQLite/allWeb",
|
78
|
+
"Datastore/SQLite/all",
|
79
|
+
"Datastore/allWeb",
|
80
|
+
"Datastore/all"
|
81
|
+
]
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_segment_does_not_record_instance_id_metrics_when_disabled
|
85
|
+
with_config(:'datastore_tracer.instance_reporting.enabled' => false) do
|
86
|
+
Transaction.stubs(:recording_web_transaction?).returns(true)
|
87
|
+
|
88
|
+
segment = DatastoreSegment.new "SQLite", "select", nil, "localhost/1337807"
|
89
|
+
segment.start
|
90
|
+
advance_time 1
|
91
|
+
segment.finish
|
92
|
+
|
93
|
+
assert_metrics_not_recorded "Datastore/instance/SQLite/localhost/1337807"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_add_instance_identifier_segment_parameter
|
98
|
+
segment = nil
|
99
|
+
|
100
|
+
in_transaction do
|
101
|
+
segment = NewRelic::Agent::Transaction.start_datastore_segment "SQLite", "select", nil, "localhost", "1337807"
|
102
|
+
advance_time 1
|
103
|
+
segment.finish
|
104
|
+
end
|
105
|
+
|
106
|
+
sample = NewRelic::Agent.agent.transaction_sampler.last_sample
|
107
|
+
node = find_node_with_name(sample, segment.name)
|
108
|
+
|
109
|
+
assert_equal "localhost", node.params[:host]
|
110
|
+
assert_equal "1337807", node.params[:port_path_or_id]
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_does_not_add_instance_identifier_segment_parameter_when_disabled
|
114
|
+
with_config(:'datastore_tracer.instance_reporting.enabled' => false) do
|
115
|
+
segment = nil
|
116
|
+
|
117
|
+
in_transaction do
|
118
|
+
segment = NewRelic::Agent::Transaction.start_datastore_segment "SQLite", "select", nil, "localhost", "1337807"
|
119
|
+
advance_time 1
|
120
|
+
segment.finish
|
121
|
+
end
|
122
|
+
|
123
|
+
sample = NewRelic::Agent.agent.transaction_sampler.last_sample
|
124
|
+
node = find_node_with_name(sample, segment.name)
|
125
|
+
|
126
|
+
refute node.params.key? :host
|
127
|
+
refute node.params.key? :port_path_or_id
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_add_database_name_segment_parameter
|
132
|
+
segment = nil
|
133
|
+
|
134
|
+
in_transaction do
|
135
|
+
segment = NewRelic::Agent::Transaction.start_datastore_segment "SQLite", "select", nil, nil, nil, "pizza_cube"
|
136
|
+
advance_time 1
|
137
|
+
segment.finish
|
138
|
+
end
|
139
|
+
|
140
|
+
sample = NewRelic::Agent.agent.transaction_sampler.last_sample
|
141
|
+
node = find_node_with_name(sample, segment.name)
|
142
|
+
|
143
|
+
assert_equal node.params[:database_name], "pizza_cube"
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_does_not_add_database_name_segment_parameter_when_disabled
|
147
|
+
with_config(:'datastore_tracer.database_name_reporting.enabled' => false) do
|
148
|
+
segment = nil
|
149
|
+
|
150
|
+
in_transaction do
|
151
|
+
segment = NewRelic::Agent::Transaction.start_datastore_segment "SQLite", "select", nil, nil, nil, "pizza_cube"
|
152
|
+
advance_time 1
|
153
|
+
segment.finish
|
154
|
+
end
|
155
|
+
|
156
|
+
sample = NewRelic::Agent.agent.transaction_sampler.last_sample
|
157
|
+
node = find_node_with_name(sample, segment.name)
|
158
|
+
|
159
|
+
refute node.params.key? :database_name
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
66
163
|
def test_notice_sql
|
67
164
|
in_transaction do
|
68
165
|
segment = NewRelic::Agent::Transaction.start_datastore_segment "SQLite", "select"
|
@@ -78,6 +175,27 @@ module NewRelic
|
|
78
175
|
end
|
79
176
|
end
|
80
177
|
|
178
|
+
def test_notice_sql_creates_database_statement_with_identifier
|
179
|
+
in_transaction do
|
180
|
+
segment = NewRelic::Agent::Transaction.start_datastore_segment "SQLite", "select", nil, "jonan.gummy_planet", "1337"
|
181
|
+
segment.notice_sql "select * from blogs"
|
182
|
+
segment.finish
|
183
|
+
|
184
|
+
assert_equal "jonan.gummy_planet", segment.sql_statement.host
|
185
|
+
assert_equal "1337", segment.sql_statement.port_path_or_id
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_notice_sql_creates_database_statement_with_database_name
|
190
|
+
in_transaction do
|
191
|
+
segment = NewRelic::Agent::Transaction.start_datastore_segment "SQLite", "select", nil, nil, nil, "pizza_cube"
|
192
|
+
segment.notice_sql "select * from blogs"
|
193
|
+
segment.finish
|
194
|
+
|
195
|
+
assert_equal "pizza_cube", segment.sql_statement.database_name
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
81
199
|
def test_internal_notice_sql
|
82
200
|
explainer = stub(:explainer)
|
83
201
|
in_transaction do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: newrelic_rpm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.17.0.325
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Krajcar
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2016-
|
14
|
+
date: 2016-10-11 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rake
|
@@ -548,6 +548,8 @@ files:
|
|
548
548
|
- test/fixtures/cross_agent_tests/cat_map.json
|
549
549
|
- test/fixtures/cross_agent_tests/data_transport/data_transport.json
|
550
550
|
- test/fixtures/cross_agent_tests/data_transport/data_transport.md
|
551
|
+
- test/fixtures/cross_agent_tests/datastores/README.md
|
552
|
+
- test/fixtures/cross_agent_tests/datastores/datastore_instances.json
|
551
553
|
- test/fixtures/cross_agent_tests/docker_container_id/README.md
|
552
554
|
- test/fixtures/cross_agent_tests/docker_container_id/cases.json
|
553
555
|
- test/fixtures/cross_agent_tests/docker_container_id/docker-0.9.1.txt
|
@@ -1033,6 +1035,7 @@ files:
|
|
1033
1035
|
- test/new_relic/agent/instrumentation/active_record_subscriber_test.rb
|
1034
1036
|
- test/new_relic/agent/instrumentation/controller_instrumentation_test.rb
|
1035
1037
|
- test/new_relic/agent/instrumentation/delayed_job_instrumentation_test.rb
|
1038
|
+
- test/new_relic/agent/instrumentation/instance_identification_test.rb
|
1036
1039
|
- test/new_relic/agent/instrumentation/instrumentation_test.rb
|
1037
1040
|
- test/new_relic/agent/instrumentation/metric_frame_test.rb
|
1038
1041
|
- test/new_relic/agent/instrumentation/middleware_proxy_test.rb
|