newrelic_rpm 6.3.0.355 → 6.4.0.356

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -5
  3. data/CHANGELOG.md +44 -0
  4. data/lib/new_relic/agent/commands/agent_command_router.rb +2 -21
  5. data/lib/new_relic/agent/configuration/default_source.rb +1 -29
  6. data/lib/new_relic/agent/configuration/environment_source.rb +4 -2
  7. data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
  8. data/lib/new_relic/agent/connect/request_builder.rb +5 -0
  9. data/lib/new_relic/agent/instrumentation/action_cable_subscriber.rb +24 -42
  10. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +45 -69
  11. data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +70 -53
  12. data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +29 -8
  13. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +33 -47
  14. data/lib/new_relic/agent/instrumentation/active_storage_subscriber.rb +2 -2
  15. data/lib/new_relic/agent/instrumentation/grape.rb +2 -3
  16. data/lib/new_relic/agent/instrumentation/{evented_subscriber.rb → notifications_subscriber.rb} +7 -66
  17. data/lib/new_relic/agent/new_relic_service.rb +0 -4
  18. data/lib/new_relic/agent/threading/backtrace_service.rb +3 -3
  19. data/lib/new_relic/agent/threading/thread_profile.rb +9 -23
  20. data/lib/new_relic/agent/transaction.rb +0 -2
  21. data/lib/new_relic/agent/transaction/trace.rb +3 -8
  22. data/lib/new_relic/agent/transaction/trace_builder.rb +0 -1
  23. data/lib/new_relic/agent/transaction_sampler.rb +1 -5
  24. data/lib/new_relic/rack/browser_monitoring.rb +10 -8
  25. data/lib/new_relic/version.rb +1 -1
  26. data/lib/tasks/config.rake +1 -2
  27. metadata +3 -6
  28. data/lib/new_relic/agent/commands/xray_session.rb +0 -55
  29. data/lib/new_relic/agent/commands/xray_session_collection.rb +0 -161
  30. data/lib/new_relic/agent/transaction/xray_sample_buffer.rb +0 -64
@@ -1,87 +1,104 @@
1
1
  # encoding: utf-8
2
2
  # This file is distributed under New Relic's license terms.
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
- require 'new_relic/agent/instrumentation/evented_subscriber'
4
+ require 'new_relic/agent/instrumentation/notifications_subscriber'
5
5
 
6
6
  # Listen for ActiveSupport::Notifications events for ActionView render
7
7
  # events. Write metric data and transaction trace nodes for each event.
8
8
  module NewRelic
9
9
  module Agent
10
10
  module Instrumentation
11
- class ActionViewSubscriber < EventedSubscriber
11
+ class ActionViewSubscriber < NotificationsSubscriber
12
12
 
13
13
  def start(name, id, payload) #THREAD_LOCAL_ACCESS
14
- event = RenderEvent.new(name, Time.now, nil, id, payload)
15
- push_event(event)
16
- if state.is_execution_traced? && event.recordable?
17
- event.segment = NewRelic::Agent::Tracer.start_segment name: event.metric_name
14
+ parent = segment_stack[id].last
15
+ metric_name = format_metric_name(name, payload, parent)
16
+
17
+ event = ActionViewEvent.new(metric_name, payload[:identifier])
18
+ if state.is_execution_traced? && recordable?(name, metric_name)
19
+ event.finishable = Tracer.start_segment(name: metric_name)
18
20
  end
21
+ push_segment id, event
19
22
  rescue => e
20
23
  log_notification_error(e, name, 'start')
21
24
  end
22
25
 
23
26
  def finish(name, id, payload) #THREAD_LOCAL_ACCESS
24
- event = pop_event(id)
25
- event.segment.finish if event.segment
27
+ event = pop_segment(id)
28
+ event.finish if event
26
29
  rescue => e
27
30
  log_notification_error(e, name, 'finish')
28
31
  end
29
32
 
30
- class RenderEvent < Event
31
- attr_accessor :segment
32
-
33
- RENDER_TEMPLATE_EVENT_NAME = 'render_template.action_view'.freeze
34
- RENDER_PARTIAL_EVENT_NAME = 'render_partial.action_view'.freeze
35
- RENDER_COLLECTION_EVENT_NAME = 'render_collection.action_view'.freeze
33
+ def format_metric_name(event_name, payload, parent)
34
+ return parent.name if parent \
35
+ && (payload[:virtual_path] \
36
+ || (parent.identifier =~ /template$/))
36
37
 
37
- # Nearly every "render_blah.action_view" event has a child
38
- # in the form of "!render_blah.action_view". The children
39
- # are the ones we want to record. There are a couple
40
- # special cases of events without children.
41
- def recordable?
42
- name[0] == '!' ||
43
- metric_name == 'View/text template/Rendering' ||
44
- metric_name == "View/#{::NewRelic::Agent::UNKNOWN_METRIC}/Partial"
38
+ if payload.key?(:virtual_path)
39
+ identifier = payload[:virtual_path]
40
+ else
41
+ identifier = payload[:identifier]
45
42
  end
46
43
 
47
- def metric_name
48
- if parent && (payload[:virtual_path] ||
49
- (parent.payload[:identifier] =~ /template$/))
50
- return parent.metric_name
51
- elsif payload.key?(:virtual_path)
52
- identifier = payload[:virtual_path]
53
- else
54
- identifier = payload[:identifier]
55
- end
44
+ "View/#{metric_path(event_name, identifier)}/#{metric_action(event_name)}"
45
+ end
56
46
 
57
- # memoize
58
- @metric_name ||= "View/#{metric_path(name, identifier)}/#{metric_action(name)}"
59
- @metric_name
60
- end
47
+ # Nearly every "render_blah.action_view" event has a child
48
+ # in the form of "!render_blah.action_view". The children
49
+ # are the ones we want to record. There are a couple
50
+ # special cases of events without children.
51
+ def recordable?(event_name, metric_name)
52
+ event_name[0] == '!' \
53
+ || metric_name == 'View/text template/Rendering' \
54
+ || metric_name == "View/#{::NewRelic::Agent::UNKNOWN_METRIC}/Partial"
55
+ end
56
+
57
+ RENDER_TEMPLATE_EVENT_NAME = 'render_template.action_view'.freeze
58
+ RENDER_PARTIAL_EVENT_NAME = 'render_partial.action_view'.freeze
59
+ RENDER_COLLECTION_EVENT_NAME = 'render_collection.action_view'.freeze
61
60
 
62
- def metric_path(name, identifier)
63
- # Rails 5 sets identifier to nil for empty collections,
64
- # so do not mistake rendering a collection for rendering a file.
65
- if identifier == nil && name != RENDER_COLLECTION_EVENT_NAME
66
- 'file'
67
- elsif identifier =~ /template$/
68
- identifier
69
- elsif identifier && (parts = identifier.split('/')).size > 1
70
- parts[-2..-1].join('/')
71
- else
72
- ::NewRelic::Agent::UNKNOWN_METRIC
73
- end
61
+ def metric_action(name)
62
+ case name
63
+ when /#{RENDER_TEMPLATE_EVENT_NAME}$/ then 'Rendering'
64
+ when RENDER_PARTIAL_EVENT_NAME then 'Partial'
65
+ when RENDER_COLLECTION_EVENT_NAME then 'Partial'
74
66
  end
67
+ end
75
68
 
76
- def metric_action(name)
77
- case name
78
- when /#{RENDER_TEMPLATE_EVENT_NAME}$/ then 'Rendering'
79
- when RENDER_PARTIAL_EVENT_NAME then 'Partial'
80
- when RENDER_COLLECTION_EVENT_NAME then 'Partial'
81
- end
69
+ def metric_path(name, identifier)
70
+ # Rails 5 sets identifier to nil for empty collections,
71
+ # so do not mistake rendering a collection for rendering a file.
72
+ if identifier.nil? && name != RENDER_COLLECTION_EVENT_NAME
73
+ 'file'
74
+ elsif identifier =~ /template$/
75
+ identifier
76
+ elsif identifier && (parts = identifier.split('/')).size > 1
77
+ parts[-2..-1].join('/')
78
+ else
79
+ ::NewRelic::Agent::UNKNOWN_METRIC
82
80
  end
83
81
  end
84
82
  end
83
+
84
+ # This class holds state information between calls to `start`
85
+ # and `finish` for ActiveSupport events that we do not want to track
86
+ # as a transaction or segment.
87
+ class ActionViewEvent
88
+ attr_reader :name, :identifier
89
+ attr_accessor :finishable
90
+
91
+ def initialize(name, identifier)
92
+ @name = name
93
+ @identifier = identifier
94
+ @finishable = nil
95
+ end
96
+
97
+ def finish
98
+ @finishable.finish if @finishable
99
+ end
100
+ end
85
101
  end
102
+
86
103
  end
87
104
  end
@@ -14,8 +14,15 @@ module NewRelic
14
14
  module Instrumentation
15
15
  module ActiveRecordNotifications
16
16
  module BaseExtensions41
17
+ def self.included(base)
18
+ base.class_eval do
19
+ alias_method :log_without_performance_improvement, :log
20
+ alias_method :log, :log_with_performance_improvement
21
+ end
22
+ end
23
+
17
24
  # https://github.com/rails/rails/blob/4-1-stable/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb#L371
18
- def log(sql, name = "SQL", binds = [], statement_name = nil)
25
+ def log_with_performance_improvement(sql, name = "SQL", binds = [], statement_name = nil)
19
26
  @instrumenter.instrument(
20
27
  "sql.active_record",
21
28
  :sql => sql,
@@ -30,8 +37,15 @@ module NewRelic
30
37
  end
31
38
 
32
39
  module BaseExtensions50
40
+ def self.included(base)
41
+ base.class_eval do
42
+ alias_method :log_without_performance_improvement, :log
43
+ alias_method :log, :log_with_performance_improvement
44
+ end
45
+ end
46
+
33
47
  # https://github.com/rails/rails/blob/5-0-stable/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb#L582
34
- def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
48
+ def log_with_performance_improvement(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
35
49
  @instrumenter.instrument(
36
50
  "sql.active_record",
37
51
  sql: sql,
@@ -47,8 +61,15 @@ module NewRelic
47
61
  end
48
62
 
49
63
  module BaseExtensions51
64
+ def self.included(base)
65
+ base.class_eval do
66
+ alias_method :log_without_performance_improvement, :log
67
+ alias_method :log, :log_with_performance_improvement
68
+ end
69
+ end
70
+
50
71
  # https://github.com/rails/rails/blob/5-1-stable/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb#L603
51
- def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil) # :doc:
72
+ def log_with_performance_improvement(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil) # :doc:
52
73
  @instrumenter.instrument(
53
74
  "sql.active_record",
54
75
  sql: sql,
@@ -87,17 +108,17 @@ DependencyDetection.defer do
87
108
 
88
109
 
89
110
  depends_on do
90
- # If the deprecated :disable_active_record_4 setting is true, and
111
+ # If the deprecated :disable_active_record_4 setting is true, and
91
112
  # the active record version is four, disable!
92
113
  NewRelic::Agent.config[:disable_active_record_4] == false \
93
114
  || ::ActiveRecord::VERSION::MAJOR.to_i != 4
94
115
  end
95
116
 
96
117
  depends_on do
97
- # If the deprecated :disable_active_record_5 setting is true, and
118
+ # If the deprecated :disable_active_record_5 setting is true, and
98
119
  # the active record version is five, disable!
99
120
  NewRelic::Agent.config[:disable_active_record_5] == false \
100
- || ::ActiveRecord::VERSION::MAJOR.to_i != 5
121
+ || ::ActiveRecord::VERSION::MAJOR.to_i != 5
101
122
  end
102
123
 
103
124
 
@@ -116,7 +137,7 @@ DependencyDetection.defer do
116
137
  ::ActiveRecord::Base,
117
138
  ::ActiveRecord::Relation)
118
139
 
119
- # Default to .prepending, unless the ActiveRecord version is <=4
140
+ # Default to .prepending, unless the ActiveRecord version is <=4
120
141
  # **AND** the :prepend_active_record_instrumentation config is false
121
142
  if ::ActiveRecord::VERSION::MAJOR > 4 \
122
143
  || ::NewRelic::Agent.config[:prepend_active_record_instrumentation]
@@ -145,7 +166,7 @@ DependencyDetection.defer do
145
166
  end
146
167
 
147
168
  unless activerecord_extension.nil?
148
- ::ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:prepend, activerecord_extension)
169
+ ::ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, activerecord_extension)
149
170
  end
150
171
  end
151
172
  end
@@ -2,7 +2,7 @@
2
2
  # This file is distributed under New Relic's license terms.
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
  require 'new_relic/agent/instrumentation/active_record_helper'
5
- require 'new_relic/agent/instrumentation/evented_subscriber'
5
+ require 'new_relic/agent/instrumentation/notifications_subscriber'
6
6
 
7
7
  # Listen for ActiveSupport::Notifications events for ActiveRecord query
8
8
  # events. Write metric data, transaction trace nodes and slow sql
@@ -10,7 +10,7 @@ require 'new_relic/agent/instrumentation/evented_subscriber'
10
10
  module NewRelic
11
11
  module Agent
12
12
  module Instrumentation
13
- class ActiveRecordSubscriber < EventedSubscriber
13
+ class ActiveRecordSubscriber < NotificationsSubscriber
14
14
  CACHED_QUERY_NAME = 'CACHE'.freeze
15
15
 
16
16
  def initialize
@@ -31,6 +31,7 @@ module NewRelic
31
31
  # we don't expect this to be called more than once, but we're being
32
32
  # defensive.
33
33
  return if defined?(cached?)
34
+
34
35
  if defined?(::ActiveRecord) && ::ActiveRecord::VERSION::STRING >= "5.1.0"
35
36
  def cached?(payload)
36
37
  payload.fetch(:cached, false)
@@ -45,9 +46,10 @@ module NewRelic
45
46
  def start(name, id, payload) #THREAD_LOCAL_ACCESS
46
47
  return if cached?(payload)
47
48
  return unless NewRelic::Agent.tl_is_execution_traced?
49
+
48
50
  config = active_record_config(payload)
49
- event = ActiveRecordEvent.new(name, Time.now, nil, id, payload, @explainer, config)
50
- push_event(event)
51
+ segment = start_segment(config, payload)
52
+ push_segment(id, segment)
51
53
  rescue => e
52
54
  log_notification_error(e, name, 'start')
53
55
  end
@@ -55,8 +57,9 @@ module NewRelic
55
57
  def finish(name, id, payload) #THREAD_LOCAL_ACCESS
56
58
  return if cached?(payload)
57
59
  return unless state.is_execution_traced?
58
- event = pop_event(id)
59
- event.finish
60
+
61
+ segment = pop_segment(id)
62
+ segment.finish if segment
60
63
  rescue => e
61
64
  log_notification_error(e, name, 'finish')
62
65
  end
@@ -99,50 +102,33 @@ module NewRelic
99
102
  connection.instance_variable_get(:@config) if connection
100
103
  end
101
104
 
102
- class ActiveRecordEvent < Event
103
- def initialize(name, start, ending, transaction_id, payload, explainer, config)
104
- super(name, start, ending, transaction_id, payload)
105
- @explainer = explainer
106
- @config = config
107
- @segment = start_segment
108
- end
109
-
110
- def start_segment
111
- product, operation, collection = ActiveRecordHelper.product_operation_collection_for(payload[:name],
112
- sql, @config && @config[:adapter])
113
-
114
- host = nil
115
- port_path_or_id = nil
116
- database = nil
117
-
118
- if ActiveRecordHelper::InstanceIdentification.supported_adapter?(@config)
119
- host = ActiveRecordHelper::InstanceIdentification.host(@config)
120
- port_path_or_id = ActiveRecordHelper::InstanceIdentification.port_path_or_id(@config)
121
- database = @config && @config[:database]
122
- end
123
-
124
- segment = Tracer.start_datastore_segment product: product,
125
- operation: operation,
126
- collection: collection,
127
- host: host,
128
- port_path_or_id: port_path_or_id,
129
- database_name: database
130
-
131
- segment._notice_sql sql, @config, @explainer, payload[:binds], payload[:name]
132
- segment
105
+ def start_segment(config, payload)
106
+ sql = Helper.correctly_encoded payload[:sql]
107
+ product, operation, collection = ActiveRecordHelper.product_operation_collection_for(
108
+ payload[:name],
109
+ sql,
110
+ config && config[:adapter]
111
+ )
112
+
113
+ host = nil
114
+ port_path_or_id = nil
115
+ database = nil
116
+
117
+ if ActiveRecordHelper::InstanceIdentification.supported_adapter?(config)
118
+ host = ActiveRecordHelper::InstanceIdentification.host(config)
119
+ port_path_or_id = ActiveRecordHelper::InstanceIdentification.port_path_or_id(config)
120
+ database = config && config[:database]
133
121
  end
134
122
 
135
- def finish
136
- @segment.finish if @segment
137
- end
123
+ segment = Tracer.start_datastore_segment(product: product,
124
+ operation: operation,
125
+ collection: collection,
126
+ host: host,
127
+ port_path_or_id: port_path_or_id,
128
+ database_name: database)
138
129
 
139
- def state
140
- @state ||= NewRelic::Agent::Tracer.state
141
- end
142
-
143
- def sql
144
- @sql ||= Helper.correctly_encoded payload[:sql]
145
- end
130
+ segment._notice_sql sql, config, @explainer, payload[:binds], payload[:name]
131
+ segment
146
132
  end
147
133
  end
148
134
  end
@@ -1,12 +1,12 @@
1
1
  # encoding: utf-8
2
2
  # This file is distributed under New Relic's license terms.
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
- require 'new_relic/agent/instrumentation/evented_subscriber'
4
+ require 'new_relic/agent/instrumentation/notifications_subscriber'
5
5
 
6
6
  module NewRelic
7
7
  module Agent
8
8
  module Instrumentation
9
- class ActiveStorageSubscriber < EventedSubscriber
9
+ class ActiveStorageSubscriber < NotificationsSubscriber
10
10
  def start name, id, payload
11
11
  return unless state.is_execution_traced?
12
12
  start_segment name, id, payload
@@ -133,9 +133,8 @@ DependencyDetection.defer do
133
133
  endpoint = env[::NewRelic::Agent::Instrumentation::GrapeInstrumentation::API_ENDPOINT]
134
134
  version = env[::NewRelic::Agent::Instrumentation::GrapeInstrumentation::API_VERSION]
135
135
 
136
- # Since 1.2.0, how to obtain the class name is changed.
137
- class_name = self.class.respond_to?(:base) ? self.class.base.name : self.class.name
138
- ::NewRelic::Agent::Instrumentation::GrapeInstrumentation.handle_transaction(endpoint, class_name, version)
136
+ api_class = (self.class.respond_to?(:base) && self.class.base) || self.class
137
+ ::NewRelic::Agent::Instrumentation::GrapeInstrumentation.handle_transaction(endpoint, api_class.name, version)
139
138
  rescue => e
140
139
  ::NewRelic::Agent.logger.warn("Error in Grape instrumentation", e)
141
140
  end
@@ -5,7 +5,7 @@
5
5
  module NewRelic
6
6
  module Agent
7
7
  module Instrumentation
8
- class EventedSubscriber
8
+ class NotificationsSubscriber
9
9
  def initialize
10
10
  @queue_key = ['NewRelic', self.class.name, object_id].join('-')
11
11
  end
@@ -46,16 +46,6 @@ module NewRelic
46
46
  end
47
47
  end
48
48
 
49
- def start(name, id, payload)
50
- event = ActiveSupport::Notifications::Event.new(name, Time.now, nil, id, payload)
51
- push_event(event)
52
- return event
53
- end
54
-
55
- def finish(name, id, payload)
56
- pop_event(id)
57
- end
58
-
59
49
  def log_notification_error(error, name, event_type)
60
50
  # These are important enough failures that we want the backtraces
61
51
  # logged at error level, hence the explicit log_exception call.
@@ -63,30 +53,16 @@ module NewRelic
63
53
  NewRelic::Agent.logger.log_exception(:error, error)
64
54
  end
65
55
 
66
- def push_event(event)
67
- parent = event_stack[event.transaction_id].last
68
- if parent && event.respond_to?(:parent=)
69
- event.parent = parent
70
- parent << event
71
- end
72
- event_stack[event.transaction_id].push event
56
+ def push_segment(id, segment)
57
+ segment_stack[id].push segment
73
58
  end
74
59
 
75
- def pop_event(transaction_id)
76
- event = event_stack[transaction_id].pop
77
-
78
- if event.respond_to?(:finish!)
79
- # ActiveSupport version 6 and greater use a finish! method rather
80
- # that allowing us to set the end directly
81
- event.finish!
82
- else
83
- event.end = Time.now
84
- end
85
-
86
- return event
60
+ def pop_segment(id)
61
+ segment = segment_stack[id].pop
62
+ segment
87
63
  end
88
64
 
89
- def event_stack
65
+ def segment_stack
90
66
  Thread.current[@queue_key] ||= Hash.new {|h,id| h[id] = [] }
91
67
  end
92
68
 
@@ -95,41 +71,6 @@ module NewRelic
95
71
  end
96
72
  end
97
73
 
98
- # Taken from ActiveSupport::Notifications::Event, pasted here
99
- # with a couple minor additions so we don't have a hard
100
- # dependency on ActiveSupport::Notifications.
101
- #
102
- # Represents an instrumentation event, provides timing and metric
103
- # name information useful when recording metrics.
104
- class Event
105
- attr_reader :name, :time, :transaction_id, :payload, :children
106
- attr_accessor :end, :parent, :frame
107
-
108
- def initialize(name, start, ending, transaction_id, payload)
109
- @name = name
110
- @payload = payload.dup
111
- @time = start
112
- @transaction_id = transaction_id
113
- @end = ending
114
- @children = []
115
- end
116
-
117
- def metric_name
118
- raise NotImplementedError
119
- end
120
-
121
- def duration
122
- self.end - time
123
- end
124
-
125
- def <<(event)
126
- @children << event
127
- end
128
-
129
- def parent_of?(event)
130
- @children.include? event
131
- end
132
- end
133
74
  end
134
75
  end
135
76
  end