newrelic_rpm 5.5.0.348 → 5.6.0.349

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
  SHA256:
3
- metadata.gz: b17c73d708623383395fecf3a60a063566a12b59a10d2b18d686deef72f31773
4
- data.tar.gz: f9b9275cf1f9f980175454d8ed5f06a4fa2d173c4edf52e136580c96b2e05eda
3
+ metadata.gz: eafe4315178abb8fe388bdae54e2c201fa080b142d093d0aa66678e2dff39596
4
+ data.tar.gz: 1c7d5d213331e77c5e3c78c1bf58cc956336615aa5d08bc7331a56ca2293a351
5
5
  SHA512:
6
- metadata.gz: 8cc16f8281e2e00829add33da0ba8053afbfe29e56b9e901c40d40cd44be982df5859492a26041aed7593b687316848113dcc02b646816e2812132bda4a86db5
7
- data.tar.gz: 7eecd067c7606152a08e6485c6f0a642f5e73081812b011f89ba8d2b3fdd74df66ee0686e385d078ec4a4286e396a1ee9206bbc9c2585925596b9b7e90101015
6
+ metadata.gz: e8027ef671be103e04bc674a35fccfed2c292abe47873281d0007738a306b88422493283eb04881cb6794478b9c10307db3a89c342d149456bc21e73cffbcf83
7
+ data.tar.gz: 8d6006908631d158b0edc1757c80960a80e7d415599faf5516635fa96dafe16e228e20263dbf1961f82e7cc6483f7ebbdd26f4dc8e8602846bc8e1e6a114ab72
@@ -9,7 +9,9 @@ language: ruby
9
9
  sudo: required
10
10
 
11
11
  before_install:
12
- - sudo apt-get update && sudo apt-get install --only-upgrade openssl && sudo apt-get install --only-upgrade libssl-dev
12
+ # RUBY-2072 Prevent Travis setup failure before our test even starts
13
+ - sudo rm -f /etc/apt/sources.list.d/travis_ci_zeromq3.list
14
+
13
15
  - gem --version
14
16
  - gem update --system
15
17
  - ./test/script/before_install/gemstash_mirror.sh
@@ -19,7 +21,11 @@ install: bundle install
19
21
 
20
22
  addons:
21
23
  apt:
24
+ update: true
22
25
  packages:
26
+ - openssl
27
+ - libssl-dev
28
+ - build-essential
23
29
  - haveged
24
30
 
25
31
  before_script: ./test/script/before_script/install_mongodb.sh
@@ -40,6 +46,7 @@ notifications:
40
46
  rvm:
41
47
  # Run slowest builds first to try and optimize overall cycle time.
42
48
  - jruby-9.1.13.0
49
+ - 2.6.0-preview3
43
50
  - 2.5.0
44
51
  - 2.4.2
45
52
  - 2.3.5
@@ -88,6 +95,24 @@ matrix:
88
95
  fast_finish: true
89
96
  exclude:
90
97
  # Unsupported Rails/Ruby combinations
98
+ # 2.6
99
+ - rvm: 2.6.0-preview3
100
+ env: TYPE=UNIT ENVIRONMENT=rails21
101
+ - rvm: 2.6.0-preview3
102
+ env: TYPE=UNIT ENVIRONMENT=rails22
103
+ - rvm: 2.6.0-preview3
104
+ env: TYPE=UNIT ENVIRONMENT=rails23
105
+ - rvm: 2.6.0-preview3
106
+ env: TYPE=UNIT ENVIRONMENT=rails30
107
+ - rvm: 2.6.0-preview3
108
+ env: TYPE=UNIT ENVIRONMENT=rails31
109
+ - rvm: 2.6.0-preview3
110
+ env: TYPE=UNIT ENVIRONMENT=rails32
111
+ - rvm: 2.6.0-preview3
112
+ env: TYPE=UNIT ENVIRONMENT=rails40
113
+ - rvm: 2.6.0-preview3
114
+ env: TYPE=UNIT ENVIRONMENT=rails41
115
+
91
116
  # 2.5
92
117
  - rvm: 2.5.0
93
118
  env: TYPE=UNIT ENVIRONMENT=rails21
@@ -1,5 +1,55 @@
1
1
  # New Relic Ruby Agent Release Notes #
2
2
 
3
+ ## v5.6.0
4
+
5
+ * Bugfix for transactions with `ActionController::Live`
6
+
7
+ Previously, transactions containing `ActionController::Live` resulted in
8
+ incorrect calculations of capacity analysis as well as error backtraces
9
+ appearing in agent logs in agent versions 5.4 and later. The agent now
10
+ correctly calculates capacity for transactions with `ActionController::Live`.
11
+
12
+ * Add ability to exclude attributes from span events and transaction
13
+ segments
14
+
15
+ Agent versions 5.5 and lower could selectively exclude attributes
16
+ from page views, error traces, transaction traces, and
17
+ transaction events. With agent version 5.6 and higher, you can
18
+ also exclude attributes from span events (via the
19
+ `span_events.include/exclude` options) and from transaction
20
+ segments (via the `transaction_segments.include/exclude` options).
21
+
22
+ As with other attribute destinations, these new options will
23
+ inherit values from the top-level `attributes.include/exclude`
24
+ settings. See the
25
+ [documentation](https://docs.newrelic.com/docs/agents/ruby-agent/attributes/enabling-disabling-attributes-ruby)
26
+ for more information.
27
+
28
+ * Increasing backoff sequence on failing to connect to New Relic
29
+
30
+ If the agent cannot reach New Relic, it will now wait for an
31
+ increasing amount of time after each failed attempt. We are also
32
+ starting with a shorter delay initially, which will help customer
33
+ apps bounce back more quickly from transient network errors.
34
+
35
+ * Truncation of long stack traces
36
+
37
+ Previous versions of the agent would truncate long stack traces to
38
+ 50 frames. To give customers more flexibility, we have added the
39
+ `error_collector.max_backtrace_frames` configuration option.
40
+ Thanks to Patrick Tulskie for the contribution!
41
+
42
+ * Update link in documentation
43
+
44
+ The community forum link in `README.md` now goes to the updated
45
+ location. Thanks to Sam Killgallon for the contribution!
46
+
47
+ * Active Storage instrumentation
48
+
49
+ The agent now provides instrumentation for Active Storage, introduced in
50
+ Rails 5.2. Customers will see Active Storage operations represented as
51
+ segments within transaction traces.
52
+
3
53
  ## v5.5.0
4
54
 
5
55
  * Bugfix for `perform` instrumentation with curb gem
data/README.md CHANGED
@@ -127,7 +127,7 @@ You can find more detailed documentation [on our website](http://newrelic.com/do
127
127
  and specifically in the [Ruby category](http://newrelic.com/docs/ruby).
128
128
 
129
129
  If you can't find what you're looking for there, reach out to us on our [support
130
- site](http://support.newrelic.com/) or our [community forum](http://forum.newrelic.com)
130
+ site](http://support.newrelic.com/) or our [community forum](https://discuss.newrelic.com/)
131
131
  and we'll be happy to help you.
132
132
 
133
133
  Find a bug? Contact us via [support.newrelic.com](http://support.newrelic.com/),
data/config.dot CHANGED
@@ -18,6 +18,7 @@ digraph AgentEnabled {
18
18
  "[error_collector.capture_source]"
19
19
  "[error_collector.enabled]"
20
20
  "[error_collector.ignore_errors]"
21
+ "[error_collector.max_backtrace_frames]"
21
22
  "[browser_monitoring.auto_instrument]"
22
23
  "[license_key]"
23
24
  "[verify_certificate]"
@@ -727,12 +727,14 @@ module NewRelic
727
727
  force || (!connected? && !disconnected?)
728
728
  end
729
729
 
730
- # Retry period is a minute for each failed attempt that
731
- # we've made. This should probably do some sort of sane TCP
732
- # backoff to prevent hammering the server, but a minute for
733
- # each attempt seems to work reasonably well.
730
+ # Per the spec at
731
+ # /agents/agent-specs/Collector-Response-Handling.md, retry
732
+ # connections after a specific backoff sequence to prevent
733
+ # hammering the server.
734
+ CONNECT_RETRY_PERIODS = [15, 15, 30, 60, 120, 300]
735
+
734
736
  def connect_retry_period
735
- [600, connect_attempts * 60].min
737
+ CONNECT_RETRY_PERIODS[connect_attempts] || 300
736
738
  end
737
739
 
738
740
  def note_connect_failure
@@ -64,42 +64,55 @@ module NewRelic
64
64
  class AttributeFilter
65
65
  DST_NONE = 0x0
66
66
 
67
- DST_TRANSACTION_EVENTS = 1 << 0
68
- DST_TRANSACTION_TRACER = 1 << 1
69
- DST_ERROR_COLLECTOR = 1 << 2
70
- DST_BROWSER_MONITORING = 1 << 3
67
+ DST_TRANSACTION_EVENTS = 1 << 0
68
+ DST_TRANSACTION_TRACER = 1 << 1
69
+ DST_ERROR_COLLECTOR = 1 << 2
70
+ DST_BROWSER_MONITORING = 1 << 3
71
+ DST_SPAN_EVENTS = 1 << 4
72
+ DST_TRANSACTION_SEGMENTS = 1 << 5
71
73
 
72
- DST_ALL = 0xF
74
+ DST_ALL = 0x3f
73
75
 
74
76
  attr_reader :rules
75
77
 
76
78
  def initialize(config)
77
79
  @enabled_destinations = DST_NONE
78
80
 
79
- @enabled_destinations |= DST_TRANSACTION_TRACER if config[:'transaction_tracer.attributes.enabled']
80
- @enabled_destinations |= DST_TRANSACTION_EVENTS if config[:'transaction_events.attributes.enabled']
81
- @enabled_destinations |= DST_ERROR_COLLECTOR if config[:'error_collector.attributes.enabled']
82
- @enabled_destinations |= DST_BROWSER_MONITORING if config[:'browser_monitoring.attributes.enabled']
81
+ @enabled_destinations |= DST_TRANSACTION_TRACER if config[:'transaction_tracer.attributes.enabled']
82
+ @enabled_destinations |= DST_TRANSACTION_EVENTS if config[:'transaction_events.attributes.enabled']
83
+ @enabled_destinations |= DST_ERROR_COLLECTOR if config[:'error_collector.attributes.enabled']
84
+ @enabled_destinations |= DST_BROWSER_MONITORING if config[:'browser_monitoring.attributes.enabled']
85
+ @enabled_destinations |= DST_SPAN_EVENTS if config[:'span_events.attributes.enabled']
86
+ @enabled_destinations |= DST_TRANSACTION_SEGMENTS if config[:'transaction_segments.attributes.enabled']
83
87
 
84
88
  @enabled_destinations = DST_NONE unless config[:'attributes.enabled']
85
89
 
86
90
  @rules = []
87
91
 
88
92
  build_rule(config[:'attributes.exclude'], DST_ALL, false)
89
- build_rule(config[:'transaction_tracer.attributes.exclude'], DST_TRANSACTION_TRACER, false)
90
- build_rule(config[:'transaction_events.attributes.exclude'], DST_TRANSACTION_EVENTS, false)
91
- build_rule(config[:'error_collector.attributes.exclude'], DST_ERROR_COLLECTOR, false)
92
- build_rule(config[:'browser_monitoring.attributes.exclude'], DST_BROWSER_MONITORING, false)
93
+ build_rule(config[:'transaction_tracer.attributes.exclude'], DST_TRANSACTION_TRACER, false)
94
+ build_rule(config[:'transaction_events.attributes.exclude'], DST_TRANSACTION_EVENTS, false)
95
+ build_rule(config[:'error_collector.attributes.exclude'], DST_ERROR_COLLECTOR, false)
96
+ build_rule(config[:'browser_monitoring.attributes.exclude'], DST_BROWSER_MONITORING, false)
97
+ build_rule(config[:'span_events.attributes.exclude'], DST_SPAN_EVENTS, false)
98
+ build_rule(config[:'transaction_segments.attributes.exclude'], DST_TRANSACTION_SEGMENTS, false)
93
99
 
94
100
  build_rule(['request.parameters.*'], include_destinations_for_capture_params(config[:capture_params]), true)
95
101
  build_rule(['job.resque.args.*'], include_destinations_for_capture_params(config[:'resque.capture_params']), true)
96
102
  build_rule(['job.sidekiq.args.*'], include_destinations_for_capture_params(config[:'sidekiq.capture_params']), true)
97
103
 
104
+ build_rule(['host', 'port_path_or_id'], DST_TRANSACTION_SEGMENTS, config[:'datastore_tracer.instance_reporting.enabled'])
105
+ build_rule(['database_name'], DST_TRANSACTION_SEGMENTS, config[:'datastore_tracer.database_name_reporting.enabled'])
106
+
98
107
  build_rule(config[:'attributes.include'], DST_ALL, true)
99
- build_rule(config[:'transaction_tracer.attributes.include'], DST_TRANSACTION_TRACER, true)
100
- build_rule(config[:'transaction_events.attributes.include'], DST_TRANSACTION_EVENTS, true)
101
- build_rule(config[:'error_collector.attributes.include'], DST_ERROR_COLLECTOR, true)
102
- build_rule(config[:'browser_monitoring.attributes.include'], DST_BROWSER_MONITORING, true)
108
+ build_rule(config[:'transaction_tracer.attributes.include'], DST_TRANSACTION_TRACER, true)
109
+ build_rule(config[:'transaction_events.attributes.include'], DST_TRANSACTION_EVENTS, true)
110
+ build_rule(config[:'error_collector.attributes.include'], DST_ERROR_COLLECTOR, true)
111
+ build_rule(config[:'browser_monitoring.attributes.include'], DST_BROWSER_MONITORING, true)
112
+ build_rule(config[:'span_events.attributes.include'], DST_SPAN_EVENTS, true)
113
+ build_rule(config[:'transaction_segments.attributes.include'], DST_TRANSACTION_SEGMENTS, true)
114
+
115
+ build_uri_rule(config[:'attributes.exclude'])
103
116
 
104
117
  @rules.sort!
105
118
 
@@ -107,9 +120,35 @@ module NewRelic
107
120
  # filter is re-generated on any significant config change.
108
121
  @high_security = config[:high_security]
109
122
 
123
+ setup_key_cache
110
124
  cache_prefix_blacklist
111
125
  end
112
126
 
127
+ # Note the key_cache is a global cache, accessible by multiple threads,
128
+ # but is intentionally left unsynchronized for liveness. Writes will always
129
+ # involve writing the same boolean value for each key, so there is no
130
+ # worry of one value clobbering another. For reads, if a value hasn't been
131
+ # written to the cache yet, the worst that will happen is that it will run
132
+ # through the filter rules again. Both reads and writes will become
133
+ # eventually consistent.
134
+
135
+ def setup_key_cache
136
+ destinations = [
137
+ DST_TRANSACTION_EVENTS,
138
+ DST_TRANSACTION_TRACER,
139
+ DST_ERROR_COLLECTOR,
140
+ DST_BROWSER_MONITORING,
141
+ DST_SPAN_EVENTS,
142
+ DST_TRANSACTION_SEGMENTS,
143
+ DST_ALL
144
+ ]
145
+
146
+ @key_cache = destinations.inject({}) do |memo, destination|
147
+ memo[destination] = {}
148
+ memo
149
+ end
150
+ end
151
+
113
152
  def include_destinations_for_capture_params(capturing)
114
153
  if capturing
115
154
  DST_TRANSACTION_TRACER | DST_ERROR_COLLECTOR
@@ -125,6 +164,14 @@ module NewRelic
125
164
  end
126
165
  end
127
166
 
167
+ def build_uri_rule(excluded_attributes)
168
+ uri_aliases = %w(uri url request_uri request.uri http.url)
169
+
170
+ if (excluded_attributes & uri_aliases).size > 0
171
+ build_rule(uri_aliases - excluded_attributes, DST_ALL, false)
172
+ end
173
+ end
174
+
128
175
  def apply(attribute_name, default_destinations)
129
176
  return DST_NONE if @enabled_destinations == DST_NONE
130
177
 
@@ -148,6 +195,19 @@ module NewRelic
148
195
  allowed_destinations & requested_destination == requested_destination
149
196
  end
150
197
 
198
+ def allows_key?(key, destination)
199
+ return false unless destination & @enabled_destinations == destination
200
+
201
+ value = @key_cache[destination][key]
202
+
203
+ if value.nil?
204
+ allowed_destinations = apply(key, destination)
205
+ @key_cache[destination][key] = allows?(allowed_destinations, destination)
206
+ else
207
+ value
208
+ end
209
+ end
210
+
151
211
  def high_security?
152
212
  @high_security
153
213
  end
@@ -719,6 +719,14 @@ module NewRelic
719
719
  :allowed_from_server => false,
720
720
  :description => 'If <code>true</code>, disables Action Cable instrumentation.'
721
721
  },
722
+ :disable_active_storage => {
723
+ :default => false,
724
+ :public => true,
725
+ :type => Boolean,
726
+ :dynamic_name => true,
727
+ :allowed_from_server => false,
728
+ :description => 'If <code>true</code>, disables ActiveStorage instrumentation.'
729
+ },
722
730
  :disable_memcached => {
723
731
  :default => value_of(:disable_memcache_instrumentation),
724
732
  :public => true,
@@ -981,6 +989,13 @@ module NewRelic
981
989
  :allowed_from_server => true,
982
990
  :description => 'Specify a comma-delimited list of error classes that the agent should ignore.'
983
991
  },
992
+ :'error_collector.max_backtrace_frames' => {
993
+ :default => 50,
994
+ :public => true,
995
+ :type => Integer,
996
+ :allowed_from_server => false,
997
+ :description => 'Defines the maximum number of frames in an error backtrace. Backtraces over this amount are truncated at the beginning and end.'
998
+ },
984
999
  :'error_collector.capture_events' => {
985
1000
  :default => value_of(:'error_collector.enabled'),
986
1001
  :public => true,
@@ -1505,6 +1520,20 @@ module NewRelic
1505
1520
  :allowed_from_server => false,
1506
1521
  :description => 'If <code>true</code>, the agent captures attributes from browser monitoring.'
1507
1522
  },
1523
+ :'span_events.attributes.enabled' => {
1524
+ :default => true,
1525
+ :public => true,
1526
+ :type => Boolean,
1527
+ :allowed_from_server => false,
1528
+ :description => 'If <code>true</code>, the agent captures attributes on span events.'
1529
+ },
1530
+ :'transaction_segments.attributes.enabled' => {
1531
+ :default => true,
1532
+ :public => true,
1533
+ :type => Boolean,
1534
+ :allowed_from_server => false,
1535
+ :description => 'If <code>true</code>, the agent captures attributes on transaction segments.'
1536
+ },
1508
1537
  :'attributes.exclude' => {
1509
1538
  :default => [],
1510
1539
  :public => true,
@@ -1545,6 +1574,22 @@ module NewRelic
1545
1574
  :transform => DefaultSource.method(:convert_to_list),
1546
1575
  :description => 'Prefix of attributes to exclude from browser monitoring. Allows <code>*</code> as wildcard at end.'
1547
1576
  },
1577
+ :'span_events.attributes.exclude' => {
1578
+ :default => [],
1579
+ :public => true,
1580
+ :type => Array,
1581
+ :allowed_from_server => false,
1582
+ :transform => DefaultSource.method(:convert_to_list),
1583
+ :description => 'Prefix of attributes to exclude from span events. Allows <code>*</code> as wildcard at end.'
1584
+ },
1585
+ :'transaction_segments.attributes.exclude' => {
1586
+ :default => [],
1587
+ :public => true,
1588
+ :type => Array,
1589
+ :allowed_from_server => false,
1590
+ :transform => DefaultSource.method(:convert_to_list),
1591
+ :description => 'Prefix of attributes to exclude from transaction segments. Allows <code>*</code> as wildcard at end.'
1592
+ },
1548
1593
  :'attributes.include' => {
1549
1594
  :default => [],
1550
1595
  :public => true,
@@ -1585,6 +1630,22 @@ module NewRelic
1585
1630
  :transform => DefaultSource.method(:convert_to_list),
1586
1631
  :description => 'Prefix of attributes to include in browser monitoring. Allows <code>*</code> as wildcard at end.'
1587
1632
  },
1633
+ :'span_events.attributes.include' => {
1634
+ :default => [],
1635
+ :public => true,
1636
+ :type => Array,
1637
+ :allowed_from_server => false,
1638
+ :transform => DefaultSource.method(:convert_to_list),
1639
+ :description => 'Prefix of attributes to include on span events. Allows <code>*</code> as wildcard at end.'
1640
+ },
1641
+ :'transaction_segments.attributes.include' => {
1642
+ :default => [],
1643
+ :public => true,
1644
+ :type => Array,
1645
+ :allowed_from_server => false,
1646
+ :transform => DefaultSource.method(:convert_to_list),
1647
+ :description => 'Prefix of attributes to include on transaction segments. Allows <code>*</code> as wildcard at end.'
1648
+ },
1588
1649
  :'custom_attributes.enabled' => {
1589
1650
  :default => true,
1590
1651
  :public => true,
@@ -121,6 +121,20 @@ module NewRelic
121
121
  enabled_fn: method(:not_empty?),
122
122
  disabled_value: [],
123
123
  permitted_fn: nil
124
+ },
125
+ {
126
+ option: :'span_events.attributes.include',
127
+ supported: true,
128
+ enabled_fn: method(:not_empty?),
129
+ disabled_value: [],
130
+ permitted_fn: nil
131
+ },
132
+ {
133
+ option: :'transaction_segments.attributes.include',
134
+ supported: true,
135
+ enabled_fn: method(:not_empty?),
136
+ disabled_value: [],
137
+ permitted_fn: nil
124
138
  }
125
139
  ],
126
140
  "allow_raw_exception_messages" => [
@@ -13,9 +13,6 @@ module NewRelic
13
13
  # made configurable in the future. This is a tradeoff between
14
14
  # memory and data retention
15
15
  MAX_ERROR_QUEUE_LENGTH = 20
16
- # Maximum number of frames in backtraces. May be made configurable
17
- # in the future.
18
- MAX_BACKTRACE_FRAMES = 50
19
16
  EXCEPTION_TAG_IVAR = :'@__nr_seen_exception'
20
17
 
21
18
  attr_reader :error_trace_aggregator, :error_event_aggregator
@@ -216,8 +213,9 @@ module NewRelic
216
213
  nil
217
214
  end
218
215
 
219
- def truncate_trace(trace, keep_frames=MAX_BACKTRACE_FRAMES)
220
- return trace if trace.length < keep_frames || trace.length == 0
216
+ def truncate_trace(trace, keep_frames=nil)
217
+ keep_frames ||= Agent.config[:'error_collector.max_backtrace_frames']
218
+ return trace if !keep_frames || trace.length < keep_frames || trace.length == 0
221
219
 
222
220
  # If keep_frames is odd, we will split things up favoring the top of the trace
223
221
  keep_top = (keep_frames / 2.0).ceil
@@ -0,0 +1,23 @@
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
+ require 'new_relic/agent/instrumentation/active_storage_subscriber'
6
+
7
+ DependencyDetection.defer do
8
+ named :active_storage
9
+
10
+ depends_on do
11
+ defined?(::ActiveStorage) &&
12
+ !NewRelic::Agent::Instrumentation::ActiveStorageSubscriber.subscribed?
13
+ end
14
+
15
+ executes do
16
+ ::NewRelic::Agent.logger.info 'Installing ActiveStorage 5 instrumentation'
17
+ end
18
+
19
+ executes do
20
+ ActiveSupport::Notifications.subscribe(/\.active_storage$/,
21
+ NewRelic::Agent::Instrumentation::ActiveStorageSubscriber.new)
22
+ end
23
+ end
@@ -0,0 +1,59 @@
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 'new_relic/agent/instrumentation/evented_subscriber'
5
+
6
+ module NewRelic
7
+ module Agent
8
+ module Instrumentation
9
+ class ActiveStorageSubscriber < EventedSubscriber
10
+ def start name, id, payload
11
+ return unless state.is_execution_traced?
12
+ start_segment name, id, payload
13
+ rescue => e
14
+ log_notification_error e, name, 'start'
15
+ end
16
+
17
+ def finish name, id, payload
18
+ return unless state.is_execution_traced?
19
+ finish_segment id
20
+ rescue => e
21
+ log_notification_error e, name, 'finish'
22
+ end
23
+
24
+ def start_segment name, id, payload
25
+ segment = Transaction.start_segment name: metric_name(name, payload)
26
+ segment.params[:key] = payload[:key]
27
+ segment.params[:exist] = payload[:exist] if payload.key? :exist
28
+ event_stack[id].push segment
29
+ end
30
+
31
+ def finish_segment id
32
+ segment = event_stack[id].pop
33
+ segment.finish if segment
34
+ end
35
+
36
+ def metric_name name, payload
37
+ service = payload[:service]
38
+ method = method_from_name name
39
+ "Ruby/ActiveStorage/#{service}Service/#{method}"
40
+ end
41
+
42
+ PATTERN = /\Aservice_([^\.]*)\.active_storage\z/
43
+ UNKNOWN = "unknown".freeze
44
+
45
+ METHOD_NAME_MAPPING = Hash.new do |h, k|
46
+ if PATTERN =~ k
47
+ h[k] = $1
48
+ else
49
+ h[k] = UNKNOWN
50
+ end
51
+ end
52
+
53
+ def method_from_name name
54
+ METHOD_NAME_MAPPING[name]
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -57,40 +57,46 @@ module NewRelic
57
57
  def for_external_request_segment(segment)
58
58
  intrinsics = intrinsics_for(segment)
59
59
 
60
- intrinsics[HTTP_URL_KEY] = truncate(segment.uri)
61
60
  intrinsics[COMPONENT_KEY] = segment.library
62
61
  intrinsics[HTTP_METHOD_KEY] = segment.procedure
63
62
  intrinsics[CATEGORY_KEY] = HTTP_CATEGORY
64
63
  intrinsics[SPAN_KIND_KEY] = CLIENT
65
64
 
66
- [intrinsics, EMPTY_HASH, EMPTY_HASH]
65
+ agent_attributes = {}
66
+
67
+ if allowed?(HTTP_URL_KEY)
68
+ agent_attributes[HTTP_URL_KEY] = truncate(segment.uri)
69
+ end
70
+
71
+ [intrinsics, EMPTY_HASH, agent_attributes]
67
72
  end
68
73
 
69
74
  def for_datastore_segment(segment)
70
75
  intrinsics = intrinsics_for(segment)
71
76
 
72
77
  intrinsics[COMPONENT_KEY] = segment.product
78
+ intrinsics[SPAN_KIND_KEY] = CLIENT
79
+ intrinsics[CATEGORY_KEY] = DATASTORE_CATEGORY
80
+
81
+ agent_attributes = {}
73
82
 
74
- if segment.database_name
75
- intrinsics[DB_INSTANCE_KEY] = truncate(segment.database_name)
83
+ if segment.database_name && allowed?(DB_INSTANCE_KEY)
84
+ agent_attributes[DB_INSTANCE_KEY] = truncate(segment.database_name)
76
85
  end
77
- if segment.host && segment.port_path_or_id
78
- intrinsics[PEER_ADDRESS_KEY] = truncate("#{segment.host}:#{segment.port_path_or_id}")
86
+ if segment.host && segment.port_path_or_id && allowed?(PEER_ADDRESS_KEY)
87
+ agent_attributes[PEER_ADDRESS_KEY] = truncate("#{segment.host}:#{segment.port_path_or_id}")
79
88
  end
80
- if segment.host
81
- intrinsics[PEER_HOSTNAME_KEY] = truncate(segment.host)
89
+ if segment.host && allowed?(PEER_HOSTNAME_KEY)
90
+ agent_attributes[PEER_HOSTNAME_KEY] = truncate(segment.host)
82
91
  end
83
92
 
84
- intrinsics[SPAN_KIND_KEY] = CLIENT
85
- intrinsics[CATEGORY_KEY] = DATASTORE_CATEGORY
86
-
87
- if segment.sql_statement
88
- intrinsics[DB_STATEMENT_KEY] = truncate(segment.sql_statement.safe_sql, 2000)
89
- elsif segment.nosql_statement
90
- intrinsics[DB_STATEMENT_KEY] = truncate(segment.nosql_statement, 2000)
93
+ if segment.sql_statement && allowed?(DB_STATEMENT_KEY)
94
+ agent_attributes[DB_STATEMENT_KEY] = truncate(segment.sql_statement.safe_sql, 2000)
95
+ elsif segment.nosql_statement && allowed?(DB_STATEMENT_KEY)
96
+ agent_attributes[DB_STATEMENT_KEY] = truncate(segment.nosql_statement, 2000)
91
97
  end
92
98
 
93
- [intrinsics, EMPTY_HASH, EMPTY_HASH]
99
+ [intrinsics, EMPTY_HASH, agent_attributes]
94
100
  end
95
101
 
96
102
  private
@@ -139,6 +145,10 @@ module NewRelic
139
145
  value
140
146
  end
141
147
  end
148
+
149
+ def allowed?(key)
150
+ NewRelic::Agent.instance.attribute_filter.allows_key?(key, AttributeFilter::DST_SPAN_EVENTS)
151
+ end
142
152
  end
143
153
  end
144
154
  end
@@ -288,6 +288,8 @@ module NewRelic
288
288
  @sampled = nil
289
289
  @priority = nil
290
290
 
291
+ @starting_thread_id = Thread.current.object_id
292
+
291
293
  @attributes = Attributes.new(NewRelic::Agent.instance.attribute_filter)
292
294
 
293
295
  merge_request_parameters(@filtered_params)
@@ -541,7 +543,7 @@ module NewRelic
541
543
 
542
544
  outermost_frame.finish
543
545
 
544
- NewRelic::Agent::TransactionTimeAggregator.transaction_stop(@end_time)
546
+ NewRelic::Agent::TransactionTimeAggregator.transaction_stop(@end_time, @starting_thread_id)
545
547
 
546
548
  commit!(outermost_frame.name) unless @ignore_this_transaction
547
549
  end
@@ -109,13 +109,11 @@ module NewRelic
109
109
  end
110
110
 
111
111
  def add_instance_parameters
112
- return unless NewRelic::Agent.config[:'datastore_tracer.instance_reporting.enabled']
113
112
  params[:host] = host if host
114
113
  params[:port_path_or_id] = port_path_or_id if port_path_or_id
115
114
  end
116
115
 
117
116
  def add_database_name_parameter
118
- return unless NewRelic::Agent.config[:'datastore_tracer.database_name_reporting.enabled']
119
117
  params[:database_name] = database_name if database_name
120
118
  end
121
119
 
@@ -21,8 +21,10 @@ module NewRelic
21
21
  @entry_timestamp = relative_start
22
22
  @metric_name = metric_name || UNKNOWN_NODE_NAME
23
23
  @exit_timestamp = relative_end
24
- @children = nil
25
- @params = params
24
+ @children = nil
25
+ @params = params.select do |p|
26
+ NewRelic::Agent.instance.attribute_filter.allows_key? p, AttributeFilter::DST_TRANSACTION_SEGMENTS
27
+ end if params
26
28
  @parent_node = parent
27
29
  end
28
30
 
@@ -23,37 +23,37 @@ module NewRelic
23
23
  h[k] = TransactionStats.new nil, 0.0
24
24
  end
25
25
 
26
- def reset!(now = Time.now)
27
- @harvest_cycle_started_at = now
26
+ def reset!(timestamp = Time.now)
27
+ @harvest_cycle_started_at = timestamp
28
28
  @stats.clear
29
29
  end
30
30
 
31
- def transaction_start(now = Time.now)
31
+ def transaction_start(timestamp = Time.now)
32
32
  @lock.synchronize do
33
- set_transaction_start_time now
33
+ set_transaction_start_time timestamp
34
34
  end
35
35
  end
36
36
 
37
- def transaction_stop(now = Time.now)
37
+ def transaction_stop(timestamp = Time.now, starting_thread_id = current_thread)
38
38
  @lock.synchronize do
39
- record_elapsed_transaction_time_until now
40
- set_transaction_start_time nil
39
+ record_elapsed_transaction_time_until timestamp, starting_thread_id
40
+ set_transaction_start_time nil, starting_thread_id
41
41
  end
42
42
  end
43
43
 
44
44
  INSTANCE_BUSY_METRIC = 'Instance/Busy'.freeze
45
45
 
46
- def harvest!(now = Time.now)
46
+ def harvest!(timestamp = Time.now)
47
47
  active_threads = 0
48
48
  result = @lock.synchronize do
49
49
  # Sum up the transaction times spent in each thread
50
50
  elapsed_transaction_time = @stats.inject(0.0) do |total, (thread_id, entry)|
51
- total + transaction_time_in_thread(thread_id, entry, now)
51
+ total + transaction_time_in_thread(timestamp, thread_id, entry)
52
52
  end
53
53
 
54
54
  active_threads = @stats.size
55
- elapsed_harvest_time = (now - @harvest_cycle_started_at) * active_threads
56
- @harvest_cycle_started_at = now
55
+ elapsed_harvest_time = (timestamp - @harvest_cycle_started_at) * active_threads
56
+ @harvest_cycle_started_at = timestamp
57
57
 
58
58
  # Clear out the stats for all threads, _except_ the live ones
59
59
  # that have transactions still open (we'll count the rest of
@@ -81,12 +81,16 @@ module NewRelic
81
81
  :transaction_stop,
82
82
  :harvest!
83
83
 
84
- class <<self
84
+ class << self
85
85
  private
86
86
 
87
- def record_elapsed_transaction_time_until(timestamp, thread_id: current_thread)
88
- @stats[thread_id].elapsed_transaction_time +=
89
- (timestamp - (@stats[thread_id].transaction_started_at || 0.0))
87
+ def record_elapsed_transaction_time_until(timestamp, thread_id = current_thread)
88
+ if @stats[thread_id].transaction_started_at
89
+ @stats[thread_id].elapsed_transaction_time +=
90
+ (timestamp - (@stats[thread_id].transaction_started_at || 0.0))
91
+ else
92
+ log_missing_elapsed_transaction_time
93
+ end
90
94
  end
91
95
 
92
96
  def in_transaction?(thread_id = current_thread)
@@ -104,27 +108,33 @@ module NewRelic
104
108
  false
105
109
  end
106
110
 
107
- def set_transaction_start_time(timestamp)
108
- @stats[current_thread].transaction_started_at = timestamp
111
+ def set_transaction_start_time(timestamp, thread_id = current_thread)
112
+ @stats[thread_id].transaction_started_at = timestamp
109
113
  end
110
114
 
111
- def split_transaction_at_harvest(now, thread_id: nil)
115
+ def split_transaction_at_harvest(timestamp, thread_id = nil)
112
116
  raise ArgumentError, 'thread_id required' unless thread_id
113
- @stats[thread_id].transaction_started_at = now
117
+ @stats[thread_id].transaction_started_at = timestamp
114
118
  @stats[thread_id].elapsed_transaction_time = 0.0
115
119
  end
116
120
 
117
- def transaction_time_in_thread thread_id, entry, now
121
+ def transaction_time_in_thread timestamp, thread_id, entry
118
122
  return entry.elapsed_transaction_time unless in_transaction? thread_id
119
123
 
120
124
  # Count the portion of the transaction that's elapsed so far,...
121
- elapsed = record_elapsed_transaction_time_until now, thread_id: thread_id
125
+ elapsed = record_elapsed_transaction_time_until timestamp, thread_id
122
126
 
123
127
  # ...then readjust the transaction start time to the next harvest
124
- split_transaction_at_harvest now, thread_id: thread_id
128
+ split_transaction_at_harvest timestamp, thread_id
125
129
 
126
130
  elapsed
127
131
  end
132
+
133
+ def log_missing_elapsed_transaction_time
134
+ state = NewRelic::Agent::TransactionState.tl_get
135
+ transaction_name = state.current_transaction.best_name
136
+ NewRelic::Agent.logger.warn("Unable to calculate elapsed transaction time for #{transaction_name}")
137
+ end
128
138
  end
129
139
  end
130
140
  end
@@ -11,7 +11,7 @@ module NewRelic
11
11
  end
12
12
 
13
13
  MAJOR = 5
14
- MINOR = 5
14
+ MINOR = 6
15
15
  TINY = 0
16
16
 
17
17
  begin
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: 5.5.0.348
4
+ version: 5.6.0.349
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Wear
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2018-11-05 00:00:00.000000000 Z
14
+ date: 2018-12-08 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rake
@@ -273,6 +273,8 @@ files:
273
273
  - lib/new_relic/agent/instrumentation/active_record_helper.rb
274
274
  - lib/new_relic/agent/instrumentation/active_record_prepend.rb
275
275
  - lib/new_relic/agent/instrumentation/active_record_subscriber.rb
276
+ - lib/new_relic/agent/instrumentation/active_storage.rb
277
+ - lib/new_relic/agent/instrumentation/active_storage_subscriber.rb
276
278
  - lib/new_relic/agent/instrumentation/acts_as_solr.rb
277
279
  - lib/new_relic/agent/instrumentation/authlogic.rb
278
280
  - lib/new_relic/agent/instrumentation/bunny.rb