newrelic_rpm 3.9.7.266 → 3.9.8.273

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +44 -1
  3. data/lib/new_relic/agent.rb +31 -0
  4. data/lib/new_relic/agent/agent.rb +34 -5
  5. data/lib/new_relic/agent/configuration/default_source.rb +25 -1
  6. data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
  7. data/lib/new_relic/agent/cross_app_monitor.rb +1 -1
  8. data/lib/new_relic/agent/custom_event_aggregator.rb +2 -4
  9. data/lib/new_relic/agent/error_collector.rb +17 -12
  10. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +9 -8
  11. data/lib/new_relic/agent/instrumentation/grape.rb +67 -0
  12. data/lib/new_relic/agent/new_relic_service.rb +93 -43
  13. data/lib/new_relic/agent/pipe_service.rb +4 -0
  14. data/lib/new_relic/agent/synthetics_event_buffer.rb +42 -0
  15. data/lib/new_relic/agent/system_info.rb +44 -18
  16. data/lib/new_relic/agent/transaction_event_aggregator.rb +9 -2
  17. data/lib/new_relic/agent/utilization_data.rb +77 -0
  18. data/lib/new_relic/agent/vm/mri_vm.rb +3 -3
  19. data/lib/new_relic/rack/agent_hooks.rb +15 -15
  20. data/lib/new_relic/recipes/capistrano3.rb +2 -2
  21. data/lib/new_relic/version.rb +1 -1
  22. data/newrelic_rpm.gemspec +0 -1
  23. data/test/agent_helper.rb +13 -3
  24. data/test/environments/lib/environments/runner.rb +3 -19
  25. data/test/environments/rails42/Gemfile +5 -1
  26. data/test/fixtures/cross_agent_tests/README.md +1 -1
  27. data/test/fixtures/cross_agent_tests/cat_map.json +154 -88
  28. data/test/fixtures/cross_agent_tests/docker_container_id/cases.json +30 -6
  29. data/test/fixtures/cross_agent_tests/docker_container_id/docker-1.1.2-lxc-driver.txt +10 -0
  30. data/test/fixtures/cross_agent_tests/docker_container_id/docker-1.1.2-native-driver-fs.txt +10 -0
  31. data/test/fixtures/cross_agent_tests/docker_container_id/docker-1.1.2-native-driver-systemd.txt +10 -0
  32. data/test/fixtures/cross_agent_tests/docker_container_id/heroku.txt +1 -0
  33. data/test/fixtures/cross_agent_tests/docker_container_id/ubuntu-14.04-lxc-container.txt +10 -0
  34. data/test/fixtures/cross_agent_tests/docker_container_id/{lxc-containers-without-docker.txt → ubuntu-14.04-no-container.txt} +0 -0
  35. data/test/fixtures/cross_agent_tests/docker_container_id/ubuntu-14.10-no-container.txt +10 -0
  36. data/test/multiverse/lib/multiverse/runner.rb +1 -0
  37. data/test/multiverse/lib/multiverse/suite.rb +6 -2
  38. data/test/multiverse/suites/active_record/.gitignore +1 -0
  39. data/test/multiverse/suites/active_record/Envfile +25 -7
  40. data/test/multiverse/suites/active_record/Rakefile +9 -0
  41. data/test/{new_relic/agent/instrumentation → multiverse/suites/active_record}/active_record_test.rb +82 -88
  42. data/test/multiverse/suites/active_record/app/models/models.rb +27 -0
  43. data/test/multiverse/suites/active_record/ar_method_aliasing.rb +5 -46
  44. data/test/multiverse/suites/active_record/before_suite.rb +23 -0
  45. data/test/multiverse/suites/active_record/config/database.rb +79 -0
  46. data/test/multiverse/suites/active_record/config/database.yml +19 -0
  47. data/test/multiverse/suites/active_record/db/migrate/20141105131800_create_users_and_aliases.rb +21 -0
  48. data/test/multiverse/suites/active_record/db/migrate/20141106082200_create_orders_and_shipments.rb +25 -0
  49. data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +4 -1
  50. data/test/multiverse/suites/agent_only/custom_analytics_events_test.rb +53 -0
  51. data/test/multiverse/suites/agent_only/keepalive_test.rb +3 -7
  52. data/test/multiverse/suites/agent_only/utilization_data_collection_test.rb +170 -0
  53. data/test/multiverse/suites/grape/Envfile +15 -0
  54. data/test/multiverse/suites/grape/config/newrelic.yml +18 -0
  55. data/test/multiverse/suites/grape/grape_test.rb +60 -0
  56. data/test/multiverse/suites/grape/grape_test_api.rb +43 -0
  57. data/test/multiverse/suites/grape/unsupported_version_test.rb +31 -0
  58. data/test/multiverse/suites/json/Envfile +3 -1
  59. data/test/multiverse/suites/rack/rack_env_mutation_test.rb +54 -0
  60. data/test/multiverse/suites/rails/Envfile +1 -1
  61. data/test/multiverse/suites/rails/view_instrumentation_test.rb +2 -1
  62. data/test/multiverse/suites/resque/resque_marshalling_test.rb +54 -0
  63. data/test/multiverse/suites/typhoeus/Envfile +4 -4
  64. data/test/new_relic/agent/agent_test.rb +37 -0
  65. data/test/new_relic/agent/configuration/default_source_test.rb +14 -0
  66. data/test/new_relic/agent/custom_event_aggregator_test.rb +3 -3
  67. data/test/new_relic/agent/error_collector/notice_error_test.rb +4 -4
  68. data/test/new_relic/agent/error_collector_test.rb +27 -4
  69. data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +23 -0
  70. data/test/new_relic/agent/new_relic_service_test.rb +208 -103
  71. data/test/new_relic/agent/pipe_service_test.rb +7 -0
  72. data/test/new_relic/agent/synthetics_event_buffer_test.rb +54 -0
  73. data/test/new_relic/agent/synthetics_monitor_test.rb +0 -3
  74. data/test/new_relic/agent/system_info_test.rb +6 -6
  75. data/test/new_relic/agent/transaction_event_aggregator_test.rb +43 -2
  76. data/test/new_relic/agent/utilization_data_test.rb +18 -0
  77. data/test/new_relic/collection_helper_test.rb +0 -1
  78. data/test/new_relic/data_container_tests.rb +11 -7
  79. data/test/new_relic/fake_collector.rb +23 -0
  80. data/test/new_relic/fake_instance_metadata_service.rb +45 -0
  81. data/test/new_relic/license_test.rb +2 -0
  82. data/test/new_relic/marshalling_test_cases.rb +89 -4
  83. data/test/new_relic/transaction_sample_test.rb +1 -0
  84. data/test/test_helper.rb +1 -0
  85. metadata +33 -6
  86. metadata.gz.sig +1 -2
  87. data/test/active_record_fixtures.rb +0 -79
  88. data/test/new_relic/rack/all_test.rb +0 -14
@@ -26,6 +26,10 @@ module NewRelic
26
26
  # 1754: v3 (tag 2.3.0)
27
27
  # 534: v2 (shows up in 2.1.0, our first tag)
28
28
 
29
+ # These include Errno connection errors, and all indicate that the
30
+ # underlying TCP connection may be in a bad state.
31
+ CONNECTION_ERRORS = [Timeout::Error, EOFError, SystemCallError, SocketError].freeze
32
+
29
33
  attr_accessor :request_timeout, :agent_id
30
34
  attr_reader :collector, :marshaller, :metric_id_cache
31
35
 
@@ -162,12 +166,20 @@ module NewRelic
162
166
  invoke_remote(:get_xray_metadata, [@agent_id, *xray_ids])
163
167
  end
164
168
 
165
- # Send fine-grained analytic data to the collector.
166
169
  def analytic_event_data(data)
167
170
  invoke_remote(:analytic_event_data, [@agent_id, data],
168
171
  :item_count => data.size)
169
172
  end
170
173
 
174
+ def custom_event_data(data)
175
+ invoke_remote(:custom_event_data, [@agent_id, data],
176
+ :item_count => data.size)
177
+ end
178
+
179
+ def utilization_data(data)
180
+ invoke_remote(:utilization_data, data)
181
+ end
182
+
171
183
  # We do not compress if content is smaller than 64kb. There are
172
184
  # problems with bugs in Ruby in some versions that expose us
173
185
  # to a risk of segfaults if we compress aggressively.
@@ -189,15 +201,17 @@ module NewRelic
189
201
 
190
202
  begin
191
203
  t0 = Time.now
204
+ @in_session = true
192
205
  if NewRelic::Agent.config[:aggressive_keepalive]
193
206
  session_with_keepalive(&block)
194
207
  else
195
208
  session_without_keepalive(&block)
196
209
  end
197
- rescue Timeout::Error
210
+ rescue *CONNECTION_ERRORS => e
198
211
  elapsed = Time.now - t0
199
- ::NewRelic::Agent.logger.warn "Timed out opening connection to collector after #{elapsed} seconds. If this problem persists, please see http://status.newrelic.com"
200
- raise
212
+ raise NewRelic::Agent::ServerConnectionException, "Recoverable error connecting to #{@collector} after #{elapsed} seconds: #{e}"
213
+ ensure
214
+ @in_session = false
201
215
  end
202
216
  end
203
217
 
@@ -217,10 +231,7 @@ module NewRelic
217
231
 
218
232
  def establish_shared_connection
219
233
  unless @shared_tcp_connection
220
- connection = create_http_connection
221
- NewRelic::Agent.logger.debug("Opening shared TCP connection to #{connection.address}:#{connection.port}")
222
- NewRelic::TimerLib.timeout(@request_timeout) { connection.start }
223
- @shared_tcp_connection = connection
234
+ @shared_tcp_connection = create_and_start_http_connection
224
235
  end
225
236
  @shared_tcp_connection
226
237
  end
@@ -233,11 +244,54 @@ module NewRelic
233
244
  end
234
245
  end
235
246
 
247
+ def ssl_cert_store
248
+ path = cert_file_path
249
+ if !@ssl_cert_store || path != @cached_cert_store_path
250
+ ::NewRelic::Agent.logger.debug("Creating SSL certificate store from file at #{path}")
251
+ @ssl_cert_store = OpenSSL::X509::Store.new
252
+ @ssl_cert_store.add_file(path)
253
+ @cached_cert_store_path = path
254
+ end
255
+ @ssl_cert_store
256
+ end
257
+
236
258
  # Return a Net::HTTP connection object to make a call to the collector.
237
259
  # We'll reuse the same handle for cases where we're using keep-alive, or
238
260
  # otherwise create a new one.
239
261
  def http_connection
240
- @shared_tcp_connection || create_http_connection
262
+ if @in_session
263
+ establish_shared_connection
264
+ else
265
+ create_http_connection
266
+ end
267
+ end
268
+
269
+ def setup_connection_for_ssl(conn)
270
+ # Jruby 1.6.8 requires a gem for full ssl support and will throw
271
+ # an error when use_ssl=(true) is called and jruby-openssl isn't
272
+ # installed
273
+ conn.use_ssl = true
274
+ conn.verify_mode = OpenSSL::SSL::VERIFY_PEER
275
+ conn.cert_store = ssl_cert_store
276
+ rescue StandardError, LoadError
277
+ msg = "Agent is configured to use SSL, but SSL is not available in the environment. "
278
+ msg << "Either disable SSL in the agent configuration, or install SSL support."
279
+ raise UnrecoverableAgentException.new(msg)
280
+ end
281
+
282
+ def start_connection(conn)
283
+ NewRelic::Agent.logger.debug("Opening TCP connection to #{conn.address}:#{conn.port}")
284
+ NewRelic::TimerLib.timeout(@request_timeout) { conn.start }
285
+ conn
286
+ end
287
+
288
+ def setup_connection_timeouts(conn)
289
+ # We use Timeout explicitly instead of this
290
+ conn.read_timeout = nil
291
+
292
+ if conn.respond_to?(:keep_alive_timeout) && NewRelic::Agent.config[:aggressive_keepalive]
293
+ conn.keep_alive_timeout = NewRelic::Agent.config[:keep_alive_timeout]
294
+ end
241
295
  end
242
296
 
243
297
  # Return the Net::HTTP with proxy configuration given the NewRelic::Control::Server object.
@@ -247,30 +301,19 @@ module NewRelic
247
301
  http_class = Net::HTTP::Proxy(proxy_server.name, proxy_server.port,
248
302
  proxy_server.user, proxy_server.password)
249
303
 
250
- http = http_class.new((@collector.ip || @collector.name), @collector.port)
251
- if Agent.config[:ssl]
252
- begin
253
- # Jruby 1.6.8 requires a gem for full ssl support and will throw
254
- # an error when use_ssl=(true) is called and jruby-openssl isn't
255
- # installed
256
- http.use_ssl = true
257
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
258
- http.ca_file = cert_file_path
259
- rescue StandardError, LoadError
260
- msg = "Agent is configured to use SSL, but SSL is not available in the environment. "
261
- msg << "Either disable SSL in the agent configuration, or install SSL support."
262
- raise UnrecoverableAgentException.new(msg)
263
- end
264
- end
265
-
266
- if http.respond_to?(:keep_alive_timeout) && NewRelic::Agent.config[:aggressive_keepalive]
267
- http.keep_alive_timeout = NewRelic::Agent.config[:keep_alive_timeout]
268
- end
304
+ conn = http_class.new((@collector.ip || @collector.name), @collector.port)
305
+ setup_connection_for_ssl(conn) if Agent.config[:ssl]
306
+ setup_connection_timeouts(conn)
269
307
 
270
- ::NewRelic::Agent.logger.debug("Created net/http handle to #{http.address}:#{http.port}")
271
- http
308
+ ::NewRelic::Agent.logger.debug("Created net/http handle to #{conn.address}:#{conn.port}")
309
+ conn
272
310
  end
273
311
 
312
+ def create_and_start_http_connection
313
+ conn = create_http_connection
314
+ start_connection(conn)
315
+ conn
316
+ end
274
317
 
275
318
  # The path to the certificate file used to verify the SSL
276
319
  # connection if verify_peer is enabled
@@ -405,13 +448,27 @@ module NewRelic
405
448
  request.content_type = "application/octet-stream"
406
449
  request.body = opts[:data]
407
450
 
408
- response = nil
409
- http = http_connection
410
- http.read_timeout = nil
411
- NewRelic::TimerLib.timeout(@request_timeout) do
451
+ response = nil
452
+ attempts = 0
453
+ max_attempts = 2
454
+
455
+ begin
456
+ attempts += 1
457
+ conn = http_connection
412
458
  ::NewRelic::Agent.logger.debug "Sending request to #{opts[:collector]}#{opts[:uri]}"
413
- response = http.request(request)
459
+ NewRelic::TimerLib.timeout(@request_timeout) do
460
+ response = conn.request(request)
461
+ end
462
+ rescue *CONNECTION_ERRORS => e
463
+ close_shared_connection
464
+ if attempts < max_attempts
465
+ ::NewRelic::Agent.logger.debug("Retrying request to #{opts[:collector]}#{opts[:uri]} after #{e}")
466
+ retry
467
+ else
468
+ raise ServerConnectionException, "Recoverable error talking to #{@collector} after #{attempts} attempts: #{e}"
469
+ end
414
470
  end
471
+
415
472
  case response
416
473
  when Net::HTTPSuccess
417
474
  true # do nothing
@@ -420,7 +477,7 @@ module NewRelic
420
477
  when Net::HTTPServiceUnavailable
421
478
  raise ServerConnectionException, "Service unavailable (#{response.code}): #{response.message}"
422
479
  when Net::HTTPGatewayTimeOut
423
- raise Timeout::Error, response.message
480
+ raise ServerConnectionException, "Gateway timeout (#{response.code}): #{response.message}"
424
481
  when Net::HTTPRequestEntityTooLarge
425
482
  raise UnrecoverableServerException, '413 Request Entity Too Large'
426
483
  when Net::HTTPUnsupportedMediaType
@@ -429,15 +486,8 @@ module NewRelic
429
486
  raise ServerConnectionException, "Unexpected response from server (#{response.code}): #{response.message}"
430
487
  end
431
488
  response
432
- rescue Timeout::Error, EOFError, SystemCallError, SocketError => e
433
- # These include Errno connection errors, and all signify that the
434
- # connection may be in a bad state, so drop it and re-create if needed.
435
- close_shared_connection
436
- raise NewRelic::Agent::ServerConnectionException, "Recoverable error connecting to #{@collector}: #{e}"
437
489
  end
438
490
 
439
-
440
-
441
491
  # Decompresses the response from the server, if it is gzip
442
492
  # encoded, otherwise returns it verbatim
443
493
  def decompress_response(response)
@@ -32,6 +32,10 @@ module NewRelic
32
32
  write_to_pipe(:analytic_event_data, events) if events
33
33
  end
34
34
 
35
+ def custom_event_data(events)
36
+ write_to_pipe(:custom_event_data, events) if events
37
+ end
38
+
35
39
  def metric_data(unsent_timeslice_data)
36
40
  write_to_pipe(:metric_data, unsent_timeslice_data)
37
41
  {}
@@ -0,0 +1,42 @@
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/event_buffer'
6
+ require 'new_relic/agent/sized_buffer'
7
+
8
+ module NewRelic
9
+ module Agent
10
+ class SyntheticsEventBuffer < SizedBuffer
11
+
12
+ def append_with_reject(x)
13
+ @seen += 1
14
+ if full?
15
+ timestamp = timestamp_for(x)
16
+ latest_event = @items.max_by do |item|
17
+ timestamp_for(item)
18
+ end
19
+
20
+ if timestamp < timestamp_for(latest_event)
21
+ # Make room!
22
+ @items.delete(latest_event)
23
+ return [append_event(x), latest_event]
24
+ else
25
+ return [nil, x]
26
+ end
27
+ else
28
+ return [append_event(x), nil]
29
+ end
30
+ end
31
+
32
+ TIMESTAMP = "timestamp".freeze
33
+
34
+ def timestamp_for(event)
35
+ main_event, _ = event
36
+ main_event[TIMESTAMP]
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+
@@ -24,37 +24,41 @@ module NewRelic
24
24
  if @processor_info.nil?
25
25
  case ruby_os_identifier
26
26
 
27
- when /darwin/, /freebsd/
27
+ when /darwin/
28
28
  @processor_info = {
29
- :num_physical_packages => `sysctl -n hw.packages`.to_i,
30
- :num_physical_cores => `sysctl -n hw.physicalcpu_max`.to_i,
31
- :num_logical_processors => `sysctl -n hw.logicalcpu_max`.to_i
29
+ :num_physical_packages => sysctl_value('hw.packages').to_i,
30
+ :num_physical_cores => sysctl_value('hw.physicalcpu_max').to_i,
31
+ :num_logical_processors => sysctl_value('hw.logicalcpu_max').to_i
32
32
  }
33
33
  # in case those don't work, try backup values
34
34
  if @processor_info[:num_physical_cores] <= 0
35
- @processor_info[:num_physical_cores] = `sysctl -n hw.physicalcpu`.to_i
35
+ @processor_info[:num_physical_cores] = sysctl_value('hw.physicalcpu').to_i
36
36
  end
37
37
  if @processor_info[:num_logical_processors] <= 0
38
- @processor_info[:num_logical_processors] = `sysctl -n hw.logicalcpu`.to_i
38
+ @processor_info[:num_logical_processors] = sysctl_value('hw.logicalcpu').to_i
39
39
  end
40
40
  if @processor_info[:num_logical_processors] <= 0
41
- @processor_info[:num_logical_processors] = `sysctl -n hw.ncpu`.to_i
42
- end
43
- if @processor_info[:num_logical_processors] <= 0
44
- @processor_info[:num_logical_processors] = `sysctl -n hw.availcpu`.to_i
45
- end
46
- if @processor_info[:num_logical_processors] <= 0
47
- @processor_info[:num_logical_processors] = `sysctl -n hw.activecpu`.to_i
41
+ @processor_info[:num_logical_processors] = sysctl_value('hw.ncpu').to_i
48
42
  end
49
43
 
50
44
  when /linux/
51
45
  cpuinfo = proc_try_read('/proc/cpuinfo')
52
46
  @processor_info = cpuinfo ? parse_cpuinfo(cpuinfo) : {}
47
+
48
+ when /freebsd/
49
+ @processor_info = {
50
+ :num_physical_packages => nil,
51
+ :num_physical_cores => nil,
52
+ :num_logical_processors => sysctl_value('hw.ncpu').to_i
53
+ }
53
54
  end
54
55
 
55
56
  # give nils for obviously wrong values
56
57
  @processor_info.keys.each do |key|
57
- @processor_info[key] = nil if @processor_info[key] <= 0
58
+ value = @processor_info[key]
59
+ if value.is_a?(Numeric) && value <= 0
60
+ @processor_info[key] = nil
61
+ end
58
62
  end
59
63
  end
60
64
 
@@ -63,6 +67,11 @@ module NewRelic
63
67
  {}
64
68
  end
65
69
 
70
+ def self.sysctl_value(name)
71
+ # make sure to redirect stderr so we don't spew if the name is unknown
72
+ `sysctl -n #{name} 2>/dev/null`
73
+ end
74
+
66
75
  def self.parse_cpuinfo(cpuinfo)
67
76
  # Build a hash of the form
68
77
  # { [phys_id, core_id] => num_logical_processors_on_this_core }
@@ -135,8 +144,22 @@ module NewRelic
135
144
 
136
145
  def self.parse_docker_container_id(cgroup_info)
137
146
  cpu_cgroup = parse_cgroup_ids(cgroup_info)['cpu']
138
- return unless cpu_cgroup && cpu_cgroup =~ %r{^/docker/(.*)}
139
- return $1
147
+ return unless cpu_cgroup
148
+
149
+ case cpu_cgroup
150
+ # docker native driver w/out systemd (fs)
151
+ when %r{^/docker/([0-9a-f]+)$} then $1
152
+ # docker native driver with systemd
153
+ when %r{^/system\.slice/docker-([0-9a-f]+)\.scope$} then $1
154
+ # docker lxc driver
155
+ when %r{^/lxc/([0-9a-f]+)$} then $1
156
+ # not in any cgroup
157
+ when '/' then nil
158
+ # in a cgroup, but we don't recognize its format
159
+ else
160
+ ::NewRelic::Agent.logger.debug("Ignoring unrecognized cgroup ID format: '#{cpu_cgroup}'")
161
+ nil
162
+ end
140
163
  end
141
164
 
142
165
  def self.parse_cgroup_ids(cgroup_info)
@@ -145,8 +168,11 @@ module NewRelic
145
168
  cgroup_info.split("\n").each do |line|
146
169
  parts = line.split(':')
147
170
  next unless parts.size == 3
148
- _, type, cgroup_id = parts
149
- cgroup_ids[type] = cgroup_id
171
+ _, subsystems, cgroup_id = parts
172
+ subsystems = subsystems.split(',')
173
+ subsystems.each do |subsystem|
174
+ cgroup_ids[subsystem] = cgroup_id
175
+ end
150
176
  end
151
177
 
152
178
  cgroup_ids
@@ -39,7 +39,7 @@ class NewRelic::Agent::TransactionEventAggregator
39
39
  @notified_full = false
40
40
 
41
41
  @samples = ::NewRelic::Agent::SampledBuffer.new(NewRelic::Agent.config[:'analytics_events.max_samples_stored'])
42
- @synthetics_samples = ::NewRelic::Agent::SizedBuffer.new(NewRelic::Agent.config[:'synthetics.events_limit'])
42
+ @synthetics_samples = ::NewRelic::Agent::SyntheticsEventBuffer.new(NewRelic::Agent.config[:'synthetics.events_limit'])
43
43
 
44
44
  event_listener.subscribe( :transaction_finished, &method(:on_transaction_finished) )
45
45
  self.register_config_callbacks
@@ -152,8 +152,15 @@ class NewRelic::Agent::TransactionEventAggregator
152
152
 
153
153
  def append_event(event)
154
154
  main_event, _ = event
155
+
155
156
  if main_event.include?(SYNTHETICS_RESOURCE_ID_KEY)
156
- @synthetics_samples.append(event)
157
+ # Try adding to synthetics buffer. If anything is rejected, give it a
158
+ # shot in the main transaction events (where it may get sampled)
159
+ result, rejected = @synthetics_samples.append_with_reject(event)
160
+
161
+ if rejected
162
+ @samples.append(rejected)
163
+ end
157
164
  else
158
165
  @samples.append(event)
159
166
  end
@@ -0,0 +1,77 @@
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
+ class UtilizationData
8
+
9
+ REMOTE_DATA_VALID_CHARS = /^[0-9a-zA-Z_ .\/-]$/.freeze
10
+
11
+ def harvest!
12
+ [hostname, container_id, cpu_count, instance_type]
13
+ end
14
+
15
+ # No persistent data, so no need for merging or resetting
16
+ def merge!(*_); end
17
+ def reset!(*_); end
18
+
19
+ def hostname
20
+ NewRelic::Agent::Hostname.get
21
+ end
22
+
23
+ def container_id
24
+ ::NewRelic::Agent::SystemInfo.docker_container_id
25
+ end
26
+
27
+ def cpu_count
28
+ ::NewRelic::Agent::SystemInfo.clear_processor_info
29
+ ::NewRelic::Agent::SystemInfo.num_logical_processors
30
+ end
31
+
32
+ def instance_type
33
+ Timeout::timeout(1) do
34
+ remote_fetch('instance-type')
35
+ end
36
+ rescue Timeout::Error
37
+ NewRelic::Agent.logger.debug("UtilizationData timed out fetching remote keys.")
38
+ nil
39
+ rescue StandardError, LoadError => e
40
+ NewRelic::Agent.logger.debug("UtilizationData encountered error fetching remote keys:\n#{e}")
41
+ nil
42
+ end
43
+
44
+ INSTANCE_HOST = '169.254.169.254'
45
+ API_VERSION = '2008-02-01'
46
+
47
+ def remote_fetch(remote_key)
48
+ uri = URI("http://#{INSTANCE_HOST}/#{API_VERSION}/meta-data/#{remote_key}")
49
+ request = Net::HTTP::get(uri)
50
+
51
+ data = validate_remote_data(request)
52
+
53
+ if request && data.nil?
54
+ NewRelic::Agent.logger.warn("Fetching instance metadata for #{remote_key.inspect} returned invalid data: #{request.inspect}")
55
+ end
56
+
57
+ data
58
+ end
59
+
60
+ def validate_remote_data(data_str)
61
+ return nil unless data_str.kind_of?(String)
62
+ return nil unless data_str.size <= 255
63
+
64
+ data_str.each_char do |ch|
65
+ next if ch =~ REMOTE_DATA_VALID_CHARS
66
+ code_point = ch[0].ord # this works in Ruby 1.8.7 - 2.1.2
67
+ next if code_point >= 0x80
68
+
69
+ return nil # it's in neither set of valid characters
70
+ end
71
+
72
+ data_str
73
+ end
74
+
75
+ end
76
+ end
77
+ end