newrelic_rpm 4.2.0.334 → 4.3.0.335

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eed94154d98e333b8c2c091ff3630815d4165045
4
- data.tar.gz: 4206e75fd386e8f3ea148aba808854a2ec5cb91f
3
+ metadata.gz: 4c39aaf49c14d8f52c0ad1551e36d973c7ec9130
4
+ data.tar.gz: dda64be5f11fe80294aaac0c4435442aabdd69f2
5
5
  SHA512:
6
- metadata.gz: 31f37e060cab1014f3c2163b890eb2e68d8296a06146360187121250e93291eb9fb2399ef0b18e14604ee0b0fc2563e55494844a1bf0705df4199a3b71eb73ef
7
- data.tar.gz: fb5e6ddacced4c1d72e703582da15fa099bddddb32ca7cc0c535aadbd11faa48b76454094d30ac03e13cae234670906f63c57365d360b082864fc7133df24f65
6
+ metadata.gz: 504238d5388bcc1857fe19282a581f5011597c9a21484c321a7696628a2f078b6c232e1f2a11c417440b07db9860892a6a1a6448d1b9c64c61e289096130f1b5
7
+ data.tar.gz: 04b9adc55208fb75aa0437aadf72a7daf7c74730f55b0f3c9658dd38cafb7d5ca3170f80154036eebbe0d6eddacb1c468f54c28e1e0eaeca728698a226a08b02
@@ -2,6 +2,7 @@ services:
2
2
  - mysql
3
3
  - redis-server
4
4
  - memcached
5
+ - rabbitmq
5
6
 
6
7
  language: ruby
7
8
 
@@ -31,7 +32,7 @@ notifications:
31
32
 
32
33
  rvm:
33
34
  # Run slowest builds first to try and optimize overall cycle time.
34
- - jruby-9.1.8.0
35
+ - jruby-9.1.12.0
35
36
  - 2.4.1
36
37
  - 2.3.4
37
38
  - 2.2.7
@@ -140,15 +141,15 @@ matrix:
140
141
  env: TYPE=UNIT ENVIRONMENT=rails51
141
142
 
142
143
  # jruby 9.0
143
- - rvm: jruby-9.1.8.0
144
+ - rvm: jruby-9.1.12.0
144
145
  env: TYPE=UNIT ENVIRONMENT=rails21
145
- - rvm: jruby-9.1.8.0
146
+ - rvm: jruby-9.1.12.0
146
147
  env: TYPE=UNIT ENVIRONMENT=rails22
147
- - rvm: jruby-9.1.8.0
148
+ - rvm: jruby-9.1.12.0
148
149
  env: TYPE=UNIT ENVIRONMENT=rails23
149
- - rvm: jruby-9.1.8.0
150
+ - rvm: jruby-9.1.12.0
150
151
  env: TYPE=UNIT ENVIRONMENT=rails30
151
- - rvm: jruby-9.1.8.0
152
+ - rvm: jruby-9.1.12.0
152
153
  env: TYPE=UNIT ENVIRONMENT=rails31
153
- - rvm: jruby-9.1.8.0
154
+ - rvm: jruby-9.1.12.0
154
155
  env: TYPE=UNIT ENVIRONMENT=rails32
@@ -1,5 +1,49 @@
1
1
  # New Relic Ruby Agent Release Notes #
2
2
 
3
+ ## v4.3.0 ##
4
+
5
+ * Instrumentation for the Bunny AMQP Client
6
+
7
+ The Bunny AMQP Client is now automatically instrumented. The agent will
8
+ report data for messages sent and received by an application. Data on messages
9
+ is available in both APM and Insights. Applications connected through a
10
+ RabbitMQ exchange will now also be visible on Service Maps as part of Cross
11
+ Application Tracing. See the [message queues documentation page](https://docs.newrelic.com/docs/agents/ruby-agent/features/message-queues)
12
+ for more details.
13
+
14
+ * Safely normalize external hostnames
15
+
16
+ The agent has been updated to check for nil host values before downcasing the
17
+ hostname. Thanks Rafael Valério for the contribution!
18
+
19
+ * PageView events will not be generated for ignored transactions
20
+
21
+ The agent now checks if transaction is ignored before injecting the New Relic
22
+ Browser Agent. This will prevent PageView events from being generated for
23
+ ignored transactions.
24
+
25
+ * Datastores required explicitly in agent
26
+
27
+ The agent has been modified to explicity `require` the Datastores module
28
+ whereas previously there were situations where the module could be
29
+ implicitly defined. Thanks Kevin Griffin for the contribution!
30
+
31
+ * Clear transaction state after forking
32
+
33
+ Previously, if a transaction was started and the process forks, the transaction
34
+ state survived the fork and `#after_fork` call in thread local storage. Now,
35
+ this state is cleared by `#after_fork`.
36
+
37
+ * Postgis adapter reports as Postgres for datastores
38
+
39
+ The agent now maps the Postgis adapter to Postgres for datastore metrics.
40
+ Thanks Vojtěch Vondra for the contribution!
41
+
42
+ * Deprecate `:trace_only` option
43
+
44
+ The `NewRelic::Agent.notice_error` API has been updated to deprecate the
45
+ `:trace_only` option in favor of `:expected`.
46
+
3
47
  ## v4.2.0 ##
4
48
 
5
49
  * Sinatra 2.0 and Padrino 0.14.x Support
@@ -47,6 +47,7 @@ module NewRelic
47
47
  require 'new_relic/agent/busy_calculator'
48
48
  require 'new_relic/agent/sampler'
49
49
  require 'new_relic/agent/database'
50
+ require 'new_relic/agent/datastores'
50
51
  require 'new_relic/agent/pipe_channel_manager'
51
52
  require 'new_relic/agent/configuration'
52
53
  require 'new_relic/agent/rules_engine'
@@ -211,7 +212,7 @@ module NewRelic
211
212
  # @param [Exception] exception Error you wish to send
212
213
  # @param [Hash] options Modify how New Relic processes the error
213
214
  # @option options [Hash] :custom_params Custom parameters to attach to the trace
214
- # @option options [Boolean] :trace_only Only record the error trace
215
+ # @option options [Boolean] :expected Only record the error trace
215
216
  # (do not affect error rate or Apdex status)
216
217
  # @option options [String] :uri Request path, minus request params or query string
217
218
  # (usually not needed)
@@ -235,6 +236,13 @@ module NewRelic
235
236
  # @api public
236
237
  #
237
238
  def notice_error(exception, options={})
239
+
240
+ if options.has_key?(:trace_only)
241
+ NewRelic::Agent.logger.log_once(:warn, :trace_only_deprecated,
242
+ 'Passing the :trace_only option to NewRelic::Agent.notice_error is deprecated. Please use :expected instead.')
243
+ options[:expected] = options.delete(:trace_only)
244
+ end
245
+
238
246
  Transaction.notice_error(exception, options)
239
247
  nil # don't return a noticed error datastructure. it can only hurt.
240
248
  end
@@ -543,6 +543,7 @@ module NewRelic
543
543
  @transaction_event_recorder.drop_buffered_data
544
544
  @custom_event_aggregator.reset!
545
545
  @sql_sampler.reset!
546
+ TransactionState.tl_clear
546
547
  end
547
548
 
548
549
  # Clear out state for any objects that we know lock from our parents
@@ -874,6 +874,13 @@ module NewRelic
874
874
  :allowed_from_server => false,
875
875
  :description => 'Disables installation of Redis instrumentation. Standard key to use is disable_redis.'
876
876
  },
877
+ :'message_tracer.segment_parameters.enabled' => {
878
+ :default => true,
879
+ :public => true,
880
+ :type => Boolean,
881
+ :allowed_from_server => true,
882
+ :description => 'If <code>true</code>, the agent will collect metadata about messages and attach them as segment parameters.'
883
+ },
877
884
  :'slow_sql.enabled' => {
878
885
  :default => value_of(:'transaction_tracer.enabled'),
879
886
  :public => true,
@@ -1230,6 +1237,14 @@ module NewRelic
1230
1237
  :allowed_from_server => false,
1231
1238
  :description => 'If <code>true</code>, disables instrumentation for ActiveRecord 5.'
1232
1239
  },
1240
+ :disable_bunny => {
1241
+ :default => false,
1242
+ :public => true,
1243
+ :type => Boolean,
1244
+ :dynamic_name => true,
1245
+ :allowed_from_server => false,
1246
+ :description => 'If <code>true</code>, disables instrumentation for the bunny gem.'
1247
+ },
1233
1248
  :disable_curb => {
1234
1249
  :default => false,
1235
1250
  :public => true,
@@ -33,12 +33,12 @@ module NewRelic
33
33
  debug("Wiring up Cross Application Tracing to events after finished configuring")
34
34
 
35
35
  events.subscribe(:before_call) do |env| #THREAD_LOCAL_ACCESS
36
- if should_process_request(env)
36
+ if id = decoded_id(env) and should_process_request?(id)
37
37
  state = NewRelic::Agent::TransactionState.tl_get
38
38
 
39
- save_client_cross_app_id(state, env)
39
+ state.client_cross_app_id = id
40
40
  save_referring_transaction_info(state, env)
41
- set_transaction_attributes(state)
41
+ CrossAppTracing.assign_intrinsic_transaction_attributes state
42
42
  end
43
43
  end
44
44
 
@@ -50,14 +50,6 @@ module NewRelic
50
50
 
51
51
  end
52
52
 
53
- def save_client_cross_app_id(state, request_headers)
54
- state.client_cross_app_id = decoded_id(request_headers)
55
- end
56
-
57
- def clear_client_cross_app_id(state)
58
- state.client_cross_app_id = nil
59
- end
60
-
61
53
  def save_referring_transaction_info(state, request_headers)
62
54
  txn_header = request_headers[NEWRELIC_TXN_HEADER_KEY] or return
63
55
  txn_info = deserialize_header(txn_header, NEWRELIC_TXN_HEADER)
@@ -93,30 +85,19 @@ module NewRelic
93
85
  content_length = content_length_from_request(request_headers)
94
86
 
95
87
  set_response_headers(state, response_headers, timings, content_length)
96
- set_metrics(state.client_cross_app_id, timings)
97
88
  end
98
89
  end
99
- clear_client_cross_app_id(state)
100
90
  end
101
91
  end
102
92
 
103
- def should_process_request(request_headers)
104
- return cross_app_enabled? && trusts?(request_headers)
93
+ def should_process_request? id
94
+ return cross_app_enabled? && CrossAppTracing.trusts?(id)
105
95
  end
106
96
 
107
97
  def cross_app_enabled?
108
98
  NewRelic::Agent::CrossAppTracing.cross_app_enabled?
109
99
  end
110
100
 
111
- # Expects an ID of format "12#345", and will only accept that!
112
- def trusts?(request)
113
- id = decoded_id(request)
114
- split_id = id.match(/(\d+)#\d+/)
115
- return false if split_id.nil?
116
-
117
- NewRelic::Agent.config[:trusted_account_ids].include?(split_id.captures.first.to_i)
118
- end
119
-
120
101
  def set_response_headers(state, response_headers, timings, content_length)
121
102
  response_headers[NEWRELIC_APPDATA_HEADER] = build_payload(state, timings, content_length)
122
103
  end
@@ -133,26 +114,6 @@ module NewRelic
133
114
  payload = obfuscator.obfuscate(::JSON.dump(payload))
134
115
  end
135
116
 
136
- def set_transaction_attributes(state)
137
- # We expect to get the before call to set the id (if we have it) before
138
- # this, and then write our custom parameter when the transaction starts
139
- return unless txn = state.current_transaction
140
-
141
- if state.client_cross_app_id
142
- txn.attributes.add_intrinsic_attribute(:client_cross_process_id, state.client_cross_app_id)
143
- end
144
-
145
- referring_guid = client_referring_transaction_guid(state)
146
- if referring_guid
147
- txn.attributes.add_intrinsic_attribute(:referring_transaction_guid, referring_guid)
148
- end
149
- end
150
-
151
- def set_metrics(id, timings)
152
- metric_name = "ClientApplication/#{id}/all"
153
- NewRelic::Agent.record_metric(metric_name, timings.app_time_in_seconds)
154
- end
155
-
156
117
  def decoded_id(request)
157
118
  encoded_id = request[NEWRELIC_ID_HEADER_KEY]
158
119
  return "" if encoded_id.nil?
@@ -21,6 +21,10 @@ module NewRelic
21
21
  # The cross app synthetics header
22
22
  NR_SYNTHETICS_HEADER = 'X-NewRelic-Synthetics'.freeze
23
23
 
24
+ NR_MESSAGE_BROKER_ID_HEADER = 'NewRelicID'.freeze
25
+ NR_MESSAGE_BROKER_TXN_HEADER = 'NewRelicTransaction'.freeze
26
+ NR_MESSAGE_BROKER_SYNTHETICS_HEADER = 'NewRelicSynthetics'.freeze
27
+
24
28
  ###############
25
29
  module_function
26
30
  ###############
@@ -101,6 +105,45 @@ module NewRelic
101
105
  def valid_cross_app_id?(xp_id)
102
106
  !!(xp_id =~ /\A\d+#\d+\z/)
103
107
  end
108
+
109
+ def insert_message_headers headers, txn_guid, trip_id, path_hash, synthetics_header
110
+ headers[NR_MESSAGE_BROKER_ID_HEADER] = obfuscator.obfuscate(NewRelic::Agent.config[:cross_process_id])
111
+ headers[NR_MESSAGE_BROKER_TXN_HEADER] = obfuscator.obfuscate(::JSON.dump([txn_guid, false, trip_id, path_hash]))
112
+ headers[NR_MESSAGE_BROKER_SYNTHETICS_HEADER] = synthetics_header if synthetics_header
113
+ end
114
+
115
+ def message_has_crossapp_request_header? headers
116
+ !!headers[NR_MESSAGE_BROKER_ID_HEADER]
117
+ end
118
+
119
+ def reject_messaging_cat_headers headers
120
+ headers.reject {|k,_| k == NR_MESSAGE_BROKER_ID_HEADER || k == NR_MESSAGE_BROKER_TXN_HEADER}
121
+ end
122
+
123
+ def trusts? id
124
+ split_id = id.match(/(\d+)#\d+/)
125
+ return false if split_id.nil?
126
+
127
+ NewRelic::Agent.config[:trusted_account_ids].include? split_id.captures.first.to_i
128
+ end
129
+
130
+ def trusted_valid_cross_app_id? id
131
+ valid_cross_app_id?(id) && trusts?(id)
132
+ end
133
+
134
+ def assign_intrinsic_transaction_attributes state
135
+ # We expect to get the before call to set the id (if we have it) before
136
+ # this, and then write our custom parameter when the transaction starts
137
+ return unless transaction = state.current_transaction
138
+
139
+ if state.client_cross_app_id
140
+ transaction.attributes.add_intrinsic_attribute(:client_cross_process_id, state.client_cross_app_id)
141
+ end
142
+
143
+ if referring_guid = state.referring_transaction_info && state.referring_transaction_info[0]
144
+ transaction.attributes.add_intrinsic_attribute(:referring_transaction_guid, referring_guid)
145
+ end
146
+ end
104
147
  end
105
148
  end
106
149
  end
@@ -199,7 +199,7 @@ module NewRelic
199
199
 
200
200
  state = ::NewRelic::Agent::TransactionState.tl_get
201
201
 
202
- unless options.delete(:trace_only)
202
+ unless options.delete(:expected)
203
203
  increment_error_count!(state, exception, options)
204
204
  end
205
205
 
@@ -37,7 +37,7 @@ module NewRelic
37
37
  uri = ::URI.parse(url)
38
38
  end
39
39
  end
40
- uri.host.downcase!
40
+ uri.host.downcase! unless uri.host.nil?
41
41
  uri
42
42
  end
43
43
 
@@ -156,6 +156,9 @@ module NewRelic
156
156
 
157
157
  # https://rubygems.org/gems/activerecord-jdbcpostgresql-adapter
158
158
  "jdbcpostgresql" => "Postgres",
159
+
160
+ # https://rubygems.org/gems/activerecord-postgis-adapter
161
+ "postgis" => "Postgres",
159
162
 
160
163
  # https://rubygems.org/gems/activerecord-jdbcsqlite3-adapter
161
164
  "jdbcsqlite3" => "SQLite",
@@ -197,7 +200,8 @@ module NewRelic
197
200
  "jdbcmysql" => :mysql,
198
201
 
199
202
  "postgresql" => :postgres,
200
- "jdbcpostgresql" => :postgres
203
+ "jdbcpostgresql" => :postgres,
204
+ "postgis" => :postgres
201
205
  }.freeze
202
206
 
203
207
  DATASTORE_DEFAULT_PORTS = {
@@ -0,0 +1,146 @@
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
+
5
+ DependencyDetection.defer do
6
+ named :bunny
7
+
8
+ depends_on do
9
+ defined?(Bunny)
10
+ end
11
+
12
+ executes do
13
+ ::NewRelic::Agent.logger.info 'Installing Bunny instrumentation'
14
+ require 'new_relic/agent/cross_app_tracing'
15
+ require 'new_relic/agent/messaging'
16
+ require 'new_relic/agent/transaction/message_broker_segment'
17
+ end
18
+
19
+ executes do
20
+ module Bunny
21
+ class Exchange
22
+ alias_method :publish_without_new_relic, :publish
23
+
24
+ def publish payload, opts = {}
25
+ begin
26
+ destination = NewRelic::Agent::Instrumentation::Bunny.exchange_name(name)
27
+ opts[:headers] ||= {} if NewRelic::Agent::CrossAppTracing.cross_app_enabled?
28
+
29
+ segment = NewRelic::Agent::Messaging.start_amqp_publish_segment(
30
+ library: NewRelic::Agent::Instrumentation::Bunny::LIBRARY,
31
+ destination_name: destination,
32
+ headers: opts[:headers],
33
+ routing_key: opts[:routing_key] || opts[:key],
34
+ reply_to: opts[:reply_to],
35
+ correlation_id: opts[:correlation_id],
36
+ exchange_type: type
37
+ )
38
+ rescue => e
39
+ NewRelic::Agent.logger.error "Error starting message broker segment in Bunny::Exchange#publish", e
40
+ end
41
+
42
+ begin
43
+ publish_without_new_relic payload, opts
44
+ ensure
45
+ segment.finish if segment
46
+ end
47
+ end
48
+ end
49
+
50
+ class Queue
51
+ alias_method :pop_without_new_relic, :pop
52
+
53
+ def pop(opts = {:manual_ack => false}, &block)
54
+ t0 = Time.now
55
+ msg = pop_without_new_relic opts, &block
56
+
57
+ begin
58
+ exchange_name = NewRelic::Agent::Instrumentation::Bunny.exchange_name(msg.first.exchange)
59
+
60
+ segment = NewRelic::Agent::Messaging.start_amqp_consume_segment(
61
+ library: NewRelic::Agent::Instrumentation::Bunny::LIBRARY,
62
+ destination_name: exchange_name,
63
+ delivery_info: msg[0],
64
+ message_properties: msg[1],
65
+ exchange_type: channel.exchanges[msg.first.exchange].type,
66
+ queue_name: name,
67
+ start_time: t0
68
+ )
69
+
70
+ rescue => e
71
+ NewRelic::Agent.logger.error "Error starting message broker segment in Bunny::Queue#pop", e
72
+ ensure
73
+ segment.finish if segment
74
+ end
75
+
76
+ msg
77
+ end
78
+
79
+ alias_method :purge_without_new_relic, :purge
80
+
81
+ def purge *args
82
+ begin
83
+ type = server_named? ? :temporary_queue : :queue
84
+ segment = NewRelic::Agent::Transaction.start_message_broker_segment(
85
+ action: :purge,
86
+ library: NewRelic::Agent::Instrumentation::Bunny::LIBRARY,
87
+ destination_type: type,
88
+ destination_name: name
89
+ )
90
+ rescue => e
91
+ NewRelic::Agent.logger.error "Error starting message broker segment in Bunny::Queue#purge", e
92
+ end
93
+
94
+ begin
95
+ purge_without_new_relic(*args)
96
+ ensure
97
+ segment.finish if segment
98
+ end
99
+ end
100
+ end
101
+
102
+ class Consumer
103
+ alias_method :call_without_new_relic, :call
104
+
105
+ def call *args
106
+ delivery_info, message_properties, _ = args
107
+ NewRelic::Agent::Messaging.wrap_amqp_consume_transaction(
108
+ library: NewRelic::Agent::Instrumentation::Bunny::LIBRARY,
109
+ destination_name: NewRelic::Agent::Instrumentation::Bunny.exchange_name(delivery_info.exchange),
110
+ delivery_info: delivery_info,
111
+ message_properties: message_properties,
112
+ exchange_type: NewRelic::Agent::Instrumentation::Bunny.exchange_type(delivery_info, channel),
113
+ queue_name: queue.name) do
114
+
115
+ call_without_new_relic(*args)
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ module NewRelic
124
+ module Agent
125
+ module Instrumentation
126
+ module Bunny
127
+ LIBRARY = 'RabbitMQ'.freeze
128
+ DEFAULT = 'Default'.freeze
129
+ SLASH = '/'.freeze
130
+
131
+ class << self
132
+ def exchange_name name
133
+ name.empty? ? DEFAULT : name
134
+ end
135
+
136
+ def exchange_type delivery_info, channel
137
+ if di_exchange = delivery_info[:exchange]
138
+ return :direct if di_exchange.empty?
139
+ return channel.exchanges[delivery_info[:exchange]].type if channel.exchanges[di_exchange]
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end