newrelic_rpm 6.1.0.352 → 6.6.0.358

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +34 -96
  4. data/CHANGELOG.md +139 -0
  5. data/lib/new_relic/agent/agent.rb +51 -134
  6. data/lib/new_relic/agent/commands/agent_command_router.rb +2 -21
  7. data/lib/new_relic/agent/configuration/default_source.rb +53 -41
  8. data/lib/new_relic/agent/configuration/environment_source.rb +4 -2
  9. data/lib/new_relic/agent/configuration/event_harvest_config.rb +39 -0
  10. data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
  11. data/lib/new_relic/agent/configuration/manager.rb +13 -1
  12. data/lib/new_relic/agent/configuration/server_source.rb +34 -1
  13. data/lib/new_relic/agent/connect/request_builder.rb +69 -0
  14. data/lib/new_relic/agent/connect/response_handler.rb +61 -0
  15. data/lib/new_relic/agent/error_collector.rb +2 -2
  16. data/lib/new_relic/agent/error_event_aggregator.rb +2 -1
  17. data/lib/new_relic/agent/error_trace_aggregator.rb +1 -0
  18. data/lib/new_relic/agent/event_aggregator.rb +26 -32
  19. data/lib/new_relic/agent/hostname.rb +1 -1
  20. data/lib/new_relic/agent/inbound_request_monitor.rb +2 -2
  21. data/lib/new_relic/agent/instrumentation/action_cable_subscriber.rb +24 -42
  22. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +46 -74
  23. data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +70 -53
  24. data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +168 -0
  25. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +41 -48
  26. data/lib/new_relic/agent/instrumentation/active_storage_subscriber.rb +4 -4
  27. data/lib/new_relic/agent/instrumentation/grape.rb +2 -3
  28. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +76 -0
  29. data/lib/new_relic/agent/instrumentation/{rails5 → rails_notifications}/action_cable.rb +5 -6
  30. data/lib/new_relic/agent/instrumentation/{rails5 → rails_notifications}/action_controller.rb +3 -3
  31. data/lib/new_relic/agent/instrumentation/{rails4 → rails_notifications}/action_view.rb +3 -3
  32. data/lib/new_relic/agent/javascript_instrumentor.rb +1 -1
  33. data/lib/new_relic/agent/new_relic_service.rb +0 -4
  34. data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +0 -1
  35. data/lib/new_relic/agent/parameter_filtering.rb +18 -5
  36. data/lib/new_relic/agent/priority_sampled_buffer.rb +2 -0
  37. data/lib/new_relic/agent/span_event_aggregator.rb +2 -5
  38. data/lib/new_relic/agent/threading/backtrace_service.rb +3 -3
  39. data/lib/new_relic/agent/threading/thread_profile.rb +9 -23
  40. data/lib/new_relic/agent/transaction.rb +0 -2
  41. data/lib/new_relic/agent/transaction/trace.rb +3 -8
  42. data/lib/new_relic/agent/transaction/trace_builder.rb +0 -1
  43. data/lib/new_relic/agent/transaction_event_recorder.rb +3 -3
  44. data/lib/new_relic/agent/transaction_sampler.rb +1 -5
  45. data/lib/new_relic/agent/transaction_time_aggregator.rb +19 -4
  46. data/lib/new_relic/control/class_methods.rb +7 -1
  47. data/lib/new_relic/control/frameworks/{rails5.rb → rails_notifications.rb} +1 -1
  48. data/lib/new_relic/rack/browser_monitoring.rb +10 -8
  49. data/lib/new_relic/version.rb +1 -1
  50. data/lib/tasks/config.rake +1 -2
  51. data/newrelic_rpm.gemspec +2 -9
  52. data/test/agent_helper.rb +18 -5
  53. metadata +18 -51
  54. data/lib/new_relic/agent/commands/xray_session.rb +0 -55
  55. data/lib/new_relic/agent/commands/xray_session_collection.rb +0 -161
  56. data/lib/new_relic/agent/instrumentation/active_record_4.rb +0 -42
  57. data/lib/new_relic/agent/instrumentation/active_record_5.rb +0 -41
  58. data/lib/new_relic/agent/instrumentation/evented_subscriber.rb +0 -104
  59. data/lib/new_relic/agent/instrumentation/rails4/action_controller.rb +0 -32
  60. data/lib/new_relic/agent/instrumentation/rails5/action_view.rb +0 -27
  61. data/lib/new_relic/agent/transaction/xray_sample_buffer.rb +0 -64
  62. data/lib/new_relic/control/frameworks/rails6.rb +0 -14
@@ -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
@@ -25,11 +25,11 @@ module NewRelic
25
25
  segment = Tracer.start_segment name: metric_name(name, payload)
26
26
  segment.params[:key] = payload[:key]
27
27
  segment.params[:exist] = payload[:exist] if payload.key? :exist
28
- event_stack[id].push segment
28
+ push_segment id, segment
29
29
  end
30
30
 
31
31
  def finish_segment id
32
- segment = event_stack[id].pop
32
+ segment = pop_segment id
33
33
  segment.finish if segment
34
34
  end
35
35
 
@@ -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
@@ -0,0 +1,76 @@
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
+ module NewRelic
6
+ module Agent
7
+ module Instrumentation
8
+ class NotificationsSubscriber
9
+ def initialize
10
+ @queue_key = ['NewRelic', self.class.name, object_id].join('-')
11
+ end
12
+
13
+ def self.subscribed?
14
+ find_all_subscribers.find{|s| s.instance_variable_get(:@delegate).class == self }
15
+ end
16
+
17
+ def self.find_all_subscribers
18
+ # TODO: need to talk to Rails core about an API for this,
19
+ # rather than digging through Listener ivars
20
+ instance_variable_names = [:@subscribers, :@string_subscribers, :@other_subscribers]
21
+ all_subscribers = []
22
+
23
+ notifier = ActiveSupport::Notifications.notifier
24
+
25
+ instance_variable_names.each do |name|
26
+ if notifier.instance_variable_defined?(name)
27
+ subscribers = notifier.instance_variable_get(name)
28
+ if subscribers.is_a? Array
29
+ # Rails 5 @subscribers, and Rails 6 @other_subscribers is a
30
+ # plain array of subscriber objects
31
+ all_subscribers += subscribers
32
+ elsif subscribers.is_a? Hash
33
+ # Rails 6 @string_subscribers is a Hash mapping the pattern
34
+ # string of a subscriber to an array of subscriber objects
35
+ subscribers.values.each { |array| all_subscribers += array }
36
+ end
37
+ end
38
+ end
39
+
40
+ all_subscribers
41
+ end
42
+
43
+ def self.subscribe(pattern)
44
+ if !subscribed?
45
+ ActiveSupport::Notifications.subscribe(pattern, new)
46
+ end
47
+ end
48
+
49
+ def log_notification_error(error, name, event_type)
50
+ # These are important enough failures that we want the backtraces
51
+ # logged at error level, hence the explicit log_exception call.
52
+ NewRelic::Agent.logger.error("Error during #{event_type} callback for event '#{name}':")
53
+ NewRelic::Agent.logger.log_exception(:error, error)
54
+ end
55
+
56
+ def push_segment(id, segment)
57
+ segment_stack[id].push segment
58
+ end
59
+
60
+ def pop_segment(id)
61
+ segment = segment_stack[id].pop
62
+ segment
63
+ end
64
+
65
+ def segment_stack
66
+ Thread.current[@queue_key] ||= Hash.new {|h,id| h[id] = [] }
67
+ end
68
+
69
+ def state
70
+ NewRelic::Agent::Tracer.state
71
+ end
72
+ end
73
+
74
+ end
75
+ end
76
+ end
@@ -5,11 +5,11 @@ require 'new_relic/agent/instrumentation/action_cable_subscriber'
5
5
  require 'new_relic/agent/prepend_supportability'
6
6
 
7
7
  DependencyDetection.defer do
8
- @name = :rails5_action_cable
8
+ @name = :action_cable_notifications
9
9
 
10
10
  depends_on do
11
11
  defined?(::Rails::VERSION::MAJOR) &&
12
- ::Rails::VERSION::MAJOR.to_i == 5 &&
12
+ ::Rails::VERSION::MAJOR.to_i >= 5 &&
13
13
  defined?(::ActionCable)
14
14
  end
15
15
 
@@ -19,7 +19,7 @@ DependencyDetection.defer do
19
19
  end
20
20
 
21
21
  executes do
22
- ::NewRelic::Agent.logger.info 'Installing Rails 5 Action Cable instrumentation'
22
+ ::NewRelic::Agent.logger.info 'Installing notifications based Action Cable instrumentation'
23
23
  end
24
24
 
25
25
  executes do
@@ -28,9 +28,8 @@ DependencyDetection.defer do
28
28
  NewRelic::Agent::Instrumentation::ActionCableSubscriber.new)
29
29
 
30
30
  ActiveSupport.on_load(:action_cable) do
31
- ::NewRelic::Agent::PrependSupportability.record_metrics_for(
32
- ::ActionCable::Engine,
33
- ::ActionCable::RemoteConnections)
31
+ ::NewRelic::Agent::PrependSupportability.record_metrics_for(::ActionCable::Engine) if defined?(::ActionCable::Engine)
32
+ ::NewRelic::Agent::PrependSupportability.record_metrics_for(::ActionCable::RemoteConnections) if defined?(::ActionCable::RemoteConnections)
34
33
  end
35
34
  end
36
35
  end
@@ -6,10 +6,10 @@ require 'new_relic/agent/prepend_supportability'
6
6
 
7
7
 
8
8
  DependencyDetection.defer do
9
- @name = :rails5_controller
9
+ @name = :action_controller_notifications
10
10
 
11
11
  depends_on do
12
- defined?(::Rails::VERSION::MAJOR) && ::Rails::VERSION::MAJOR.to_i == 5
12
+ defined?(::Rails::VERSION::MAJOR) && ::Rails::VERSION::MAJOR.to_i >= 4
13
13
  end
14
14
 
15
15
  depends_on do
@@ -17,7 +17,7 @@ DependencyDetection.defer do
17
17
  end
18
18
 
19
19
  executes do
20
- ::NewRelic::Agent.logger.info 'Installing Rails 5 Controller instrumentation'
20
+ ::NewRelic::Agent.logger.info 'Installing notifications based Action Controller instrumentation'
21
21
  end
22
22
 
23
23
  executes do
@@ -5,10 +5,10 @@ require 'new_relic/agent/instrumentation/action_view_subscriber'
5
5
  require 'new_relic/agent/prepend_supportability'
6
6
 
7
7
  DependencyDetection.defer do
8
- @name = :rails4_view
8
+ @name = :action_view_notifications
9
9
 
10
10
  depends_on do
11
- defined?(::Rails::VERSION::MAJOR) && ::Rails::VERSION::MAJOR.to_i == 4
11
+ defined?(::Rails::VERSION::MAJOR) && ::Rails::VERSION::MAJOR.to_i >= 4
12
12
  end
13
13
 
14
14
  depends_on do
@@ -17,7 +17,7 @@ DependencyDetection.defer do
17
17
  end
18
18
 
19
19
  executes do
20
- ::NewRelic::Agent.logger.info 'Installing Rails 4 view instrumentation'
20
+ NewRelic::Agent.logger.info 'Installing notification based Action View instrumentation'
21
21
  end
22
22
 
23
23
  executes do
@@ -14,7 +14,7 @@ module NewRelic
14
14
  RUM_KEY_LENGTH = 13
15
15
 
16
16
  def initialize(event_listener)
17
- event_listener.subscribe(:finished_configuring, &method(:log_configuration))
17
+ event_listener.subscribe(:initial_configuration_complete, &method(:log_configuration))
18
18
  end
19
19
 
20
20
  def log_configuration
@@ -163,10 +163,6 @@ module NewRelic
163
163
  invoke_remote(:agent_command_results, [@agent_id, results])
164
164
  end
165
165
 
166
- def get_xray_metadata(xray_ids)
167
- invoke_remote(:get_xray_metadata, [@agent_id, *xray_ids])
168
- end
169
-
170
166
  def analytic_event_data(data)
171
167
  _, items = data
172
168
  invoke_remote(:analytic_event_data, [@agent_id, *data],
@@ -39,7 +39,6 @@ module NewRelic
39
39
 
40
40
  def load(data)
41
41
  if data.nil? || data.empty?
42
- ::NewRelic::Agent.logger.error "Empty JSON response from collector: '#{data.inspect}'"
43
42
  return nil
44
43
  end
45
44
 
@@ -7,16 +7,29 @@ module NewRelic
7
7
  module ParameterFiltering
8
8
  extend self
9
9
 
10
+ ACTION_DISPATCH_PARAMETER_FILTER = "action_dispatch.parameter_filter".freeze
11
+
12
+ RAILS_FILTER_CLASS = if defined?(ActiveSupport::ParameterFilter)
13
+ ActiveSupport::ParameterFilter
14
+ elsif defined?(ActionDispatch::Http::ParameterFilter)
15
+ ActionDispatch::Http::ParameterFilter
16
+ else
17
+ nil
18
+ end
19
+
10
20
  def apply_filters(env, params)
11
- params = filter_using_rails(env, params)
21
+ if filters = env[ACTION_DISPATCH_PARAMETER_FILTER]
22
+ params = filter_using_rails(params, filters)
23
+ end
12
24
  params = filter_rack_file_data(env, params)
13
25
  params
14
26
  end
15
27
 
16
- def filter_using_rails(env, params)
17
- return params unless defined?(ActionDispatch::Http::ParameterFilter) && env.key?("action_dispatch.parameter_filter")
18
- filters = env["action_dispatch.parameter_filter"]
19
- ActionDispatch::Http::ParameterFilter.new(filters).filter(params)
28
+ def filter_using_rails(params, filters)
29
+ return params if RAILS_FILTER_CLASS.nil?
30
+
31
+ pre_filtered_params = filter_rails_request_parameters(params)
32
+ RAILS_FILTER_CLASS.new(filters).filter(pre_filtered_params)
20
33
  end
21
34
 
22
35
  def filter_rack_file_data(env, params)
@@ -22,6 +22,8 @@ module NewRelic
22
22
  def append(priority: nil, event: nil, &blk)
23
23
  increment_seen
24
24
 
25
+ return if @capacity == 0
26
+
25
27
  if @seen == @capacity
26
28
  @items = Heap.new(@items) { |x| priority_for(x) }
27
29
  end
@@ -12,11 +12,8 @@ module NewRelic
12
12
  class SpanEventAggregator < EventAggregator
13
13
  named :SpanEventAggregator
14
14
  capacity_key :'span_events.max_samples_stored'
15
-
16
- enabled_fn -> {
17
- NewRelic::Agent.config[:'span_events.enabled'] &&
18
- NewRelic::Agent.config[:'distributed_tracing.enabled']
19
- }
15
+ enabled_keys :'span_events.enabled',
16
+ :'distributed_tracing.enabled'
20
17
 
21
18
  def record priority: nil, event:nil, &blk
22
19
  unless(event || priority && blk)
@@ -36,8 +36,8 @@ module NewRelic
36
36
  @worker_loop = NewRelic::Agent::WorkerLoop.new
37
37
 
38
38
  # Memoize overhead % to avoid getting stale OR looked up every poll
39
- @overhead_percent_threshold = NewRelic::Agent.config[:'xray_session.max_profile_overhead']
40
- NewRelic::Agent.config.register_callback(:'xray_session.max_profile_overhead') do |new_value|
39
+ @overhead_percent_threshold = NewRelic::Agent.config[:'thread_profiler.max_profile_overhead']
40
+ NewRelic::Agent.config.register_callback(:'thread_profiler.max_profile_overhead') do |new_value|
41
41
  @overhead_percent_threshold = new_value
42
42
  end
43
43
 
@@ -213,7 +213,7 @@ module NewRelic
213
213
  if @buffer[thread].length < MAX_BUFFER_LENGTH
214
214
  @buffer[thread] << [timestamp, backtrace]
215
215
  else
216
- NewRelic::Agent.increment_metric('Supportability/XraySessions/DroppedBacktraces')
216
+ NewRelic::Agent.increment_metric('Supportability/ThreadProfiler/DroppedBacktraces')
217
217
  end
218
218
  end
219
219
  end
@@ -16,7 +16,7 @@ module NewRelic
16
16
 
17
17
  attr_reader :profile_id, :traces, :sample_period,
18
18
  :duration, :poll_count, :backtrace_count, :failure_count,
19
- :created_at, :xray_id, :command_arguments, :profile_agent_code
19
+ :created_at, :command_arguments, :profile_agent_code
20
20
  attr_accessor :finished_at
21
21
 
22
22
  def initialize(command_arguments={})
@@ -25,7 +25,6 @@ module NewRelic
25
25
  @duration = command_arguments.fetch('duration', 120)
26
26
  @sample_period = command_arguments.fetch('sample_period', 0.1)
27
27
  @profile_agent_code = command_arguments.fetch('profile_agent_code', false)
28
- @xray_id = command_arguments.fetch('x_ray_id', nil)
29
28
  @finished = false
30
29
 
31
30
  @traces = {
@@ -51,14 +50,6 @@ module NewRelic
51
50
  @poll_count += 1
52
51
  end
53
52
 
54
- def sample_count
55
- xray? ? @backtrace_count : @poll_count
56
- end
57
-
58
- def xray?
59
- !!@xray_id
60
- end
61
-
62
53
  def empty?
63
54
  @backtrace_count == 0
64
55
  end
@@ -121,26 +112,21 @@ module NewRelic
121
112
  def to_collector_array(encoder)
122
113
  encoded_trace_tree = encoder.encode(generate_traces, :skip_normalization => true)
123
114
  result = [
124
- int(self.profile_id),
125
- float(self.created_at),
126
- float(self.finished_at),
127
- int(self.sample_count),
115
+ int(profile_id),
116
+ float(created_at),
117
+ float(finished_at),
118
+ int(poll_count),
128
119
  encoded_trace_tree,
129
- int(self.unique_thread_count),
120
+ int(unique_thread_count),
130
121
  0 # runnable thread count, which we don't track
131
122
  ]
132
- result << int(@xray_id) if xray?
133
123
  result
134
124
  end
135
125
 
136
126
  def to_log_description
137
- id = if xray?
138
- "@xray_id: #{xray_id}"
139
- else
140
- "@profile_id: #{profile_id}"
141
- end
142
-
143
- "#<ThreadProfile:#{object_id} #{id} @command_arguments=#{@command_arguments.inspect}>"
127
+ "#<ThreadProfile:#{object_id} "\
128
+ "@profile_id: #{profile_id} "\
129
+ "@command_arguments=#{@command_arguments.inspect}>"
144
130
  end
145
131
 
146
132
  end
@@ -355,8 +355,6 @@ module NewRelic
355
355
 
356
356
  # For common interface with Trace
357
357
  alias_method :transaction_name, :best_name
358
-
359
- attr_accessor :xray_session_id
360
358
  # End common interface
361
359
 
362
360
  def promoted_transaction_name(name)
@@ -11,7 +11,7 @@ module NewRelic
11
11
  class FinishedTraceError < StandardError; end
12
12
 
13
13
  attr_reader :start_time, :root_node
14
- attr_accessor :transaction_name, :guid, :xray_session_id, :attributes,
14
+ attr_accessor :transaction_name, :guid, :attributes,
15
15
  :node_count, :finished, :threshold, :profile
16
16
 
17
17
  ROOT = "ROOT".freeze
@@ -40,11 +40,6 @@ module NewRelic
40
40
  self.root_node.duration
41
41
  end
42
42
 
43
- def forced?
44
- return true if NewRelic::Coerce.int_or_nil(xray_session_id)
45
- false
46
- end
47
-
48
43
  def synthetics_resource_id
49
44
  intrinsic_attributes = attributes.intrinsic_attributes_for(NewRelic::Agent::AttributeFilter::DST_TRANSACTION_TRACER)
50
45
  intrinsic_attributes[:synthetics_resource_id]
@@ -148,8 +143,8 @@ module NewRelic
148
143
  encoder.encode(trace_tree(attributes_hash)),
149
144
  NewRelic::Coerce.string(self.guid),
150
145
  nil,
151
- forced?,
152
- NewRelic::Coerce.int_or_nil(xray_session_id),
146
+ false, # forced?,
147
+ nil, # NewRelic::Coerce.int_or_nil(xray_session_id),
153
148
  NewRelic::Coerce.string(self.synthetics_resource_id)
154
149
  ]
155
150
  end
@@ -48,7 +48,6 @@ module NewRelic
48
48
  trace.guid = transaction.guid
49
49
  trace.attributes = transaction.attributes
50
50
  trace.threshold = transaction.threshold
51
- trace.xray_session_id = transaction.xray_session_id
52
51
  trace.finished = true
53
52
  end
54
53
  end
@@ -14,9 +14,9 @@ module NewRelic
14
14
  attr_reader :transaction_event_aggregator
15
15
  attr_reader :synthetics_event_aggregator
16
16
 
17
- def initialize
18
- @transaction_event_aggregator = NewRelic::Agent::TransactionEventAggregator.new
19
- @synthetics_event_aggregator = NewRelic::Agent::SyntheticsEventAggregator.new
17
+ def initialize events
18
+ @transaction_event_aggregator = NewRelic::Agent::TransactionEventAggregator.new events
19
+ @synthetics_event_aggregator = NewRelic::Agent::SyntheticsEventAggregator.new events
20
20
  end
21
21
 
22
22
  def record payload
@@ -4,7 +4,6 @@
4
4
 
5
5
  require 'new_relic/agent/transaction/slowest_sample_buffer'
6
6
  require 'new_relic/agent/transaction/synthetics_sample_buffer'
7
- require 'new_relic/agent/transaction/xray_sample_buffer'
8
7
  require 'new_relic/agent/transaction/trace_builder'
9
8
 
10
9
  module NewRelic
@@ -19,13 +18,10 @@ module NewRelic
19
18
  #
20
19
  # @api public
21
20
  class TransactionSampler
22
- attr_reader :last_sample, :xray_sample_buffer
21
+ attr_reader :last_sample
23
22
 
24
23
  def initialize
25
- @xray_sample_buffer = NewRelic::Agent::Transaction::XraySampleBuffer.new
26
-
27
24
  @sample_buffers = []
28
- @sample_buffers << @xray_sample_buffer
29
25
  @sample_buffers << NewRelic::Agent::Transaction::SlowestSampleBuffer.new
30
26
  @sample_buffers << NewRelic::Agent::Transaction::SyntheticsSampleBuffer.new
31
27