newrelic_rpm 3.9.4.245 → 3.9.5.251

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 +57 -0
  3. data/Guardfile +1 -0
  4. data/lib/new_relic/agent/agent.rb +3 -3
  5. data/lib/new_relic/agent/audit_logger.rb +5 -2
  6. data/lib/new_relic/agent/configuration/default_source.rb +11 -5
  7. data/lib/new_relic/agent/error_collector.rb +14 -1
  8. data/lib/new_relic/agent/hostname.rb +22 -1
  9. data/lib/new_relic/agent/instrumentation/middleware_tracing.rb +8 -2
  10. data/lib/new_relic/agent/instrumentation/queue_time.rb +9 -6
  11. data/lib/new_relic/agent/method_tracer.rb +51 -172
  12. data/lib/new_relic/agent/method_tracer_helpers.rb +90 -0
  13. data/lib/new_relic/agent/new_relic_service.rb +33 -11
  14. data/lib/new_relic/agent/new_relic_service/encoders.rb +9 -5
  15. data/lib/new_relic/agent/request_sampler.rb +20 -12
  16. data/lib/new_relic/agent/rules_engine.rb +31 -78
  17. data/lib/new_relic/agent/rules_engine/replacement_rule.rb +76 -0
  18. data/lib/new_relic/agent/rules_engine/segment_terms_rule.rb +48 -0
  19. data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -1
  20. data/lib/new_relic/agent/sql_sampler.rb +39 -10
  21. data/lib/new_relic/agent/stats_engine/metric_stats.rb +1 -0
  22. data/lib/new_relic/agent/stats_engine/stats_hash.rb +7 -13
  23. data/lib/new_relic/agent/system_info.rb +96 -10
  24. data/lib/new_relic/agent/threading/agent_thread.rb +4 -1
  25. data/lib/new_relic/agent/threading/backtrace_node.rb +67 -57
  26. data/lib/new_relic/agent/threading/thread_profile.rb +30 -15
  27. data/lib/new_relic/agent/transaction.rb +11 -4
  28. data/lib/new_relic/environment_report.rb +21 -20
  29. data/lib/new_relic/version.rb +1 -1
  30. data/test/agent_helper.rb +12 -0
  31. data/test/fixtures/cross_agent_tests/README.md +1 -0
  32. data/test/fixtures/cross_agent_tests/proc_cpuinfo/1pack_1core_1logical.txt +3 -0
  33. data/test/fixtures/cross_agent_tests/proc_cpuinfo/1pack_1core_2logical.txt +14 -0
  34. data/test/fixtures/cross_agent_tests/proc_cpuinfo/1pack_2core_2logical.txt +14 -0
  35. data/test/fixtures/cross_agent_tests/proc_cpuinfo/1pack_4core_4logical.txt +28 -0
  36. data/test/fixtures/{proc_cpuinfo.txt → cross_agent_tests/proc_cpuinfo/2pack_12core_24logical.txt} +0 -0
  37. data/test/fixtures/cross_agent_tests/proc_cpuinfo/2pack_20core_40logical.txt +999 -0
  38. data/test/fixtures/cross_agent_tests/proc_cpuinfo/2pack_2core_2logical.txt +51 -0
  39. data/test/fixtures/cross_agent_tests/proc_cpuinfo/2pack_2core_4logical.txt +28 -0
  40. data/test/fixtures/cross_agent_tests/proc_cpuinfo/2pack_4core_4logical.txt +28 -0
  41. data/test/fixtures/cross_agent_tests/proc_cpuinfo/4pack_4core_4logical.txt +103 -0
  42. data/test/fixtures/cross_agent_tests/proc_cpuinfo/8pack_8core_8logical.txt +199 -0
  43. data/test/fixtures/cross_agent_tests/proc_cpuinfo/README.md +24 -0
  44. data/test/fixtures/cross_agent_tests/proc_cpuinfo/Xpack_Xcore_2logical.txt +43 -0
  45. data/test/fixtures/cross_agent_tests/transaction_segment_terms.json +101 -0
  46. data/test/multiverse/lib/multiverse/suite.rb +1 -1
  47. data/test/multiverse/suites/agent_only/agent_run_id_handling_test.rb +40 -0
  48. data/test/multiverse/suites/agent_only/labels_test.rb +9 -14
  49. data/test/multiverse/suites/agent_only/marshaling_test.rb +4 -6
  50. data/test/multiverse/suites/agent_only/rename_rule_test.rb +41 -4
  51. data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +11 -3
  52. data/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +8 -8
  53. data/test/multiverse/suites/rack/example_app.rb +20 -0
  54. data/test/multiverse/suites/rack/http_response_code_test.rb +51 -0
  55. data/test/multiverse/suites/sidekiq/Envfile +13 -6
  56. data/test/multiverse/suites/sidekiq/sidekiq_server.rb +4 -3
  57. data/test/new_relic/agent/audit_logger_test.rb +27 -0
  58. data/test/new_relic/agent/error_collector_test.rb +26 -5
  59. data/test/new_relic/agent/hostname_test.rb +66 -14
  60. data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +8 -12
  61. data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +7 -45
  62. data/test/new_relic/agent/method_tracer_test.rb +52 -1
  63. data/test/new_relic/agent/new_relic_service_test.rb +76 -0
  64. data/test/new_relic/agent/request_sampler_test.rb +7 -0
  65. data/test/new_relic/agent/rules_engine_test.rb +87 -56
  66. data/test/new_relic/agent/sql_sampler_test.rb +50 -14
  67. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +2 -2
  68. data/test/new_relic/agent/stats_engine/samplers_test.rb +1 -1
  69. data/test/new_relic/agent/{stats_hash_test.rb → stats_engine/stats_hash_test.rb} +1 -38
  70. data/test/new_relic/agent/system_info_test.rb +45 -0
  71. data/test/new_relic/agent/threading/agent_thread_test.rb +30 -0
  72. data/test/new_relic/agent/threading/backtrace_node_test.rb +27 -44
  73. data/test/new_relic/agent/threading/thread_profile_test.rb +35 -14
  74. data/test/new_relic/agent/transaction_test.rb +13 -10
  75. data/test/new_relic/environment_report_test.rb +7 -6
  76. data/test/new_relic/fake_collector.rb +10 -6
  77. data/test/new_relic/multiverse_helpers.rb +4 -11
  78. data/test/new_relic/rack/agent_hooks_test.rb +1 -1
  79. data/test/performance/lib/performance/baseline_compare_reporter.rb +24 -7
  80. data/test/performance/lib/performance/result.rb +3 -1
  81. data/test/performance/lib/performance/runner.rb +10 -0
  82. data/test/performance/lib/performance/timer.rb +6 -10
  83. data/test/performance/script/runner +18 -1
  84. data/test/performance/suites/queue_time.rb +21 -0
  85. data/test/performance/suites/stats_hash.rb +34 -0
  86. data/test/performance/suites/thread_profiling.rb +26 -0
  87. metadata +25 -4
  88. metadata.gz.sig +0 -0
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,5 +1,62 @@
1
1
  # New Relic Ruby Agent Release Notes #
2
2
 
3
+ ## v3.9.5 ##
4
+
5
+ * Per-dyno data on Heroku
6
+
7
+ When running on Heroku, data from the agent can now be broken out by dyno
8
+ name, allowing you to more easily see what's happening on a per-dyno level.
9
+ Dynos on Heroku are now treated in the same way that distinct hosts on other
10
+ platforms work.
11
+
12
+ By default, 'scheduler' and 'run' dyno names will be aggregated into
13
+ 'scheduler.*' and 'run.*' to avoid unbounded growth in the number of reported
14
+ hostnames.
15
+
16
+ Read more about this feature on our Heroku docs page:
17
+ https://docs.newrelic.com/docs/agents/ruby-agent/miscellaneous/ruby-agent-heroku
18
+
19
+ * HTTP response codes in Insights events
20
+
21
+ The Ruby agent will now capture HTTP response codes from Rack applications
22
+ (including Rails and Sinatra apps) and include them under the httpResponseCode
23
+ attribute on events sent to Insights.
24
+
25
+ * Stricter limits on memory usage of metrics and SQL traces
26
+
27
+ The agent now imposes stricter limits on the number of distinct SQL traces and
28
+ metrics that it will buffer in memory at any point in time, leading to more
29
+ predictable memory consumption even in exceptional circumstances.
30
+
31
+ * Improved reliability of thread profiling
32
+
33
+ Several issues that would previously have prevented the successful completion
34
+ and transmission of thread profiles to New Relic's servers have been fixed.
35
+
36
+ These issues were related to the use of recursion in processing thread
37
+ profiles, and have been addressed by both limiting the maximum depth of the
38
+ backtraces recorded in thread profiles, and eliminating the agent's use of
39
+ recursion in processing profile data.
40
+
41
+ * Allow tracing Rails view helpers with add_method_tracer
42
+
43
+ Previously, attempting to trace a Rails view helper method using
44
+ add_method_tracer on the view helper module would lead to a NoMethodError
45
+ when the traced method was called (undefined method `trace_execution_scoped').
46
+ This has been fixed.
47
+
48
+ This issue was an instance of the Ruby 'dynamic module inclusion' or 'double
49
+ inclusion' problem. Usage of add_method_tracer now no longer relies upon the
50
+ target class having actually picked up the trace_execution_scoped method from
51
+ the NewRelic::Agent::MethodTracer module.
52
+
53
+ * Improved performance of queue time parsing
54
+
55
+ The number of objects allocated while parsing the front-end timestamps on
56
+ incoming HTTP requests has been significantly reduced.
57
+
58
+ Thanks to Aleksei Magusev for the contribution!
59
+
3
60
  ## v3.9.4 ##
4
61
 
5
62
  * Allow agent to use alternate certificate stores
data/Guardfile CHANGED
@@ -4,4 +4,5 @@ guard :minitest, :test_folders => ['test/new_relic'], :all_after_pass => false d
4
4
  watch(%r{^test/rum/.*}) { "test/new_relic/rack/browser_monitoring_test.rb" }
5
5
  watch('test/test_helper.rb') { "test/new_relic" }
6
6
  watch('test/agent_helper.rb') { "test/new_relic" }
7
+ watch('lib/new_relic/agent/configuration/default_source.rb') { "test/new_relic/agent/configuration/orphan_configuration_test.rb" }
7
8
  end
@@ -770,7 +770,7 @@ module NewRelic
770
770
  :agent_version => NewRelic::VERSION::STRING,
771
771
  :environment => @environment_report,
772
772
  :settings => Agent.config.to_collector_hash,
773
- :high_security => Agent.config[:high_security],
773
+ :high_security => Agent.config[:high_security]
774
774
  }
775
775
  end
776
776
 
@@ -811,8 +811,8 @@ module NewRelic
811
811
  Agent.config.replace_or_add_config(server_config)
812
812
  log_connection!(config_data) if @service
813
813
 
814
- @transaction_rules = RulesEngine.from_specs(config_data['transaction_name_rules'])
815
- @stats_engine.metric_rules = RulesEngine.from_specs(config_data['metric_name_rules'])
814
+ @transaction_rules = RulesEngine.create_transaction_rules(config_data)
815
+ @stats_engine.metric_rules = RulesEngine.create_metric_rules(config_data)
816
816
 
817
817
  # If you're adding something else here to respond to the server-side config,
818
818
  # use Agent.instance.events.subscribe(:finished_configuring) callback instead!
@@ -35,8 +35,11 @@ module NewRelic
35
35
  @log.info("REQUEST: #{uri}")
36
36
  @log.info("REQUEST BODY: #{request_body}")
37
37
  end
38
- rescue SystemCallError => e
39
- ::NewRelic::Agent.logger.warn("Failed writing to audit log: #{e}")
38
+ rescue StandardError, SystemStackError, SystemCallError => e
39
+ ::NewRelic::Agent.logger.warn("Failed writing to audit log", e)
40
+ rescue Exception => e
41
+ ::NewRelic::Agent.logger.warn("Failed writing to audit log with exception. Re-raising in case of interupt.", e)
42
+ raise
40
43
  end
41
44
 
42
45
  def setup_logger
@@ -659,7 +659,7 @@ module NewRelic
659
659
  :default => true,
660
660
  :public => true,
661
661
  :type => Boolean,
662
- :description => 'Enable or disable the collection of explain plans.'
662
+ :description => 'Enable or disable the collection of explain plans in transaction traces. This setting will also apply to explain plans in Slow SQL traces if slow_sql.explain_enabled is not set separately.'
663
663
  },
664
664
  :'transaction_tracer.stack_trace_threshold' => {
665
665
  :default => 0.5,
@@ -709,7 +709,7 @@ module NewRelic
709
709
  :default => DefaultSource.slow_sql_explain_enabled,
710
710
  :public => true,
711
711
  :type => Boolean,
712
- :description => 'Enable or disable the collection of explain plans in slow SQL queries.'
712
+ :description => 'Enable or disable the collection of explain plans in slow SQL queries. If this setting is omitted, the transaction_tracer.explain_enabled setting will be applied as the default setting for explain plans in Slow SQL as well.'
713
713
  },
714
714
  :'slow_sql.record_sql' => {
715
715
  :default => DefaultSource.slow_sql_record_sql,
@@ -1032,12 +1032,18 @@ module NewRelic
1032
1032
  :type => Boolean,
1033
1033
  :description => 'Defines whether the agent will wrap third-party middlewares in instrumentation (regardless of whether they are installed via Rack::Builder or Rails).'
1034
1034
  },
1035
- :use_heroku_dyno_names => {
1036
- :default => false,
1037
- :public => false,
1035
+ :'heroku.use_dyno_names' => {
1036
+ :default => true,
1037
+ :public => true,
1038
1038
  :type => Boolean,
1039
1039
  :description => 'Controls whether or not we use the heroku dyno name as the hostname.'
1040
1040
  },
1041
+ :'heroku.dyno_name_prefixes_to_shorten' => {
1042
+ :default => ['scheduler', 'run'],
1043
+ :public => true,
1044
+ :type => Array,
1045
+ :description => 'List of prefixes for heroku dyno names (such as "scheduler") to report as hostname without trailing dot and process ID.'
1046
+ },
1041
1047
  :labels => {
1042
1048
  :default => '',
1043
1049
  :public => true,
@@ -133,6 +133,19 @@ module NewRelic
133
133
  end
134
134
  end
135
135
 
136
+ def aggregated_metric_names(txn)
137
+ metric_names = ["Errors/all"]
138
+ return metric_names unless txn
139
+
140
+ if txn.recording_web_transaction?
141
+ metric_names << "Errors/allWeb"
142
+ else
143
+ metric_names << "Errors/allOther"
144
+ end
145
+
146
+ metric_names
147
+ end
148
+
136
149
  # Increments a statistic that tracks total error rate
137
150
  # Be sure not to double-count same exception. This clears per harvest.
138
151
  def increment_error_count!(exception, options={}) #THREAD_LOCAL_ACCESS
@@ -142,7 +155,7 @@ module NewRelic
142
155
  return if seen?(txn, exception)
143
156
  tag_as_seen(txn, exception)
144
157
 
145
- metric_names = ["Errors/all"]
158
+ metric_names = aggregated_metric_names(txn)
146
159
  blamed_metric = blamed_metric_name(txn, options)
147
160
  metric_names << blamed_metric if blamed_metric
148
161
 
@@ -6,12 +6,33 @@ module NewRelic
6
6
  module Agent
7
7
  module Hostname
8
8
  def self.get
9
- if (dyno_name = ENV['DYNO']) && ::NewRelic::Agent.config[:use_heroku_dyno_names]
9
+ dyno_name = ENV['DYNO']
10
+ if dyno_name && ::NewRelic::Agent.config[:'heroku.use_dyno_names']
11
+ matching_prefix = heroku_dyno_name_prefix(dyno_name)
12
+ dyno_name = "#{matching_prefix}.*" if matching_prefix
10
13
  dyno_name
11
14
  else
12
15
  Socket.gethostname
13
16
  end
14
17
  end
18
+
19
+ def self.heroku_dyno_name_prefix(dyno_name)
20
+ get_dyno_prefixes.find do |dyno_prefix|
21
+ dyno_name.start_with?(dyno_prefix + ".")
22
+ end
23
+ end
24
+
25
+ # TODO: Once config transforms are in, use those instead of handcoding
26
+ def self.get_dyno_prefixes
27
+ dyno_prefixes = ::NewRelic::Agent.config[:'heroku.dyno_name_prefixes_to_shorten'] || []
28
+ if dyno_prefixes.is_a?(String)
29
+ dyno_prefixes = dyno_prefixes.split(',')
30
+ elsif !dyno_prefixes.respond_to?(:find)
31
+ ::NewRelic::Agent.logger.warn("Ignoring invalid setting found for 'heroku.dyno_name_prefixes_to_shorten', #{dyno_prefixes}.")
32
+ dyno_prefixes = []
33
+ end
34
+ dyno_prefixes
35
+ end
15
36
  end
16
37
  end
17
38
  end
@@ -52,10 +52,16 @@ module NewRelic
52
52
  begin
53
53
  Transaction.start(state, category, opts)
54
54
  if target == self
55
- traced_call(env)
55
+ result = traced_call(env)
56
56
  else
57
- target.call(env)
57
+ result = target.call(env)
58
58
  end
59
+
60
+ if result.is_a?(Array)
61
+ state.current_transaction.http_response_code = result[0]
62
+ end
63
+
64
+ result
59
65
  rescue => e
60
66
  NewRelic::Agent.notice_error(e)
61
67
  raise
@@ -16,13 +16,15 @@ module NewRelic
16
16
  ALL_QUEUE_METRIC = 'WebFrontend/QueueTime'.freeze
17
17
  # any timestamps before this are thrown out and the parser
18
18
  # will try again with a larger unit (2000/1/1 UTC)
19
- EARLIEST_ACCEPTABLE_TIMESTAMP = 946684800
19
+ EARLIEST_ACCEPTABLE_TIME = Time.at(946684800)
20
20
 
21
21
  CANDIDATE_HEADERS = [
22
22
  REQUEST_START_HEADER,
23
23
  QUEUE_START_HEADER,
24
24
  MIDDLEWARE_START_HEADER
25
25
  ].freeze
26
+
27
+ DIVISORS = [1_000_000, 1_000, 1]
26
28
  end
27
29
 
28
30
  module_function
@@ -62,17 +64,18 @@ module NewRelic
62
64
  end
63
65
 
64
66
  def parse_timestamp(string)
65
- cut_off = Time.at(EARLIEST_ACCEPTABLE_TIMESTAMP)
66
- [1_000_000, 1_000, 1].map do |divisor|
67
+ DIVISORS.each do |divisor|
67
68
  begin
68
- Time.at(string.to_f / divisor)
69
+ t = Time.at(string.to_f / divisor)
70
+ return t if t > EARLIEST_ACCEPTABLE_TIME
69
71
  rescue RangeError
70
72
  # On Ruby versions built with a 32-bit time_t, attempting to
71
73
  # instantiate a Time object in the far future raises a RangeError,
72
74
  # in which case we know we've chosen the wrong divisor.
73
- nil
74
75
  end
75
- end.compact.find { |candidate| candidate > cut_off }
76
+ end
77
+
78
+ nil
76
79
  end
77
80
  end
78
81
  end
@@ -3,6 +3,8 @@
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
 
5
5
  require 'new_relic/control'
6
+ require 'new_relic/agent/method_tracer_helpers'
7
+
6
8
  module NewRelic
7
9
  module Agent
8
10
  # This module contains class methods added to support installing custom
@@ -49,18 +51,22 @@ module NewRelic
49
51
  clazz.extend ClassMethods
50
52
  end
51
53
 
52
- # Deprecated: original method preserved for API backward compatibility.
53
- # Use either #trace_execution_scoped or #trace_execution_unscoped
54
+ # Trace a given block with stats and keep track of the caller.
55
+ # See NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer for a description of the arguments.
56
+ # +metric_names+ is either a single name or an array of metric names.
57
+ # If more than one metric is passed, the +produce_metric+ option only applies to the first. The
58
+ # others are always recorded. Only the first metric is pushed onto the scope stack.
59
+ #
60
+ # Generally you pass an array of metric names if you want to record the metric under additional
61
+ # categories, but generally this *should never ever be done*. Most of the time you can aggregate
62
+ # on the server.
54
63
  #
55
64
  # @api public
56
- # @deprecated
57
65
  #
58
- def trace_method_execution(metric_names, push_scope, produce_metric, deduct_call_time_from_parent, &block) #:nodoc:
59
- if push_scope
60
- trace_execution_scoped(metric_names, :metric => produce_metric,
61
- :deduct_call_time_from_parent => deduct_call_time_from_parent, &block)
62
- else
63
- trace_execution_unscoped(metric_names, &block)
66
+ def trace_execution_scoped(metric_names, options={}) #THREAD_LOCAL_ACCESS
67
+ NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(metric_names, options) do
68
+ # Using an implicit block avoids object allocation for a &block param
69
+ yield
64
70
  end
65
71
  end
66
72
 
@@ -79,7 +85,22 @@ module NewRelic
79
85
  yield
80
86
  ensure
81
87
  duration = (Time.now - t0).to_f # for some reason this is 3 usec faster than Time - Time
82
- stat_engine.tl_record_unscoped_metrics(metric_names, duration)
88
+ NewRelic::Agent.instance.stats_engine.tl_record_unscoped_metrics(metric_names, duration)
89
+ end
90
+ end
91
+
92
+ # Deprecated: original method preserved for API backward compatibility.
93
+ # Use either #trace_execution_scoped or #trace_execution_unscoped
94
+ #
95
+ # @api public
96
+ # @deprecated
97
+ #
98
+ def trace_method_execution(metric_names, push_scope, produce_metric, deduct_call_time_from_parent, &block) #:nodoc:
99
+ if push_scope
100
+ trace_execution_scoped(metric_names, :metric => produce_metric,
101
+ :deduct_call_time_from_parent => deduct_call_time_from_parent, &block)
102
+ else
103
+ trace_execution_unscoped(metric_names, &block)
83
104
  end
84
105
  end
85
106
 
@@ -96,147 +117,27 @@ module NewRelic
96
117
 
97
118
  alias trace_method_execution_no_scope trace_execution_unscoped #:nodoc:
98
119
 
99
- # Refactored out of the previous trace_execution_scoped
100
- # method, most methods in this module relate to code used in
101
- # the #trace_execution_scoped method in this module
102
- module TraceExecutionScoped
103
- extend self
104
-
105
- # Shorthand to return the NewRelic::Agent.instance
106
- def agent_instance
107
- NewRelic::Agent.instance
108
- end
109
-
110
- # Shorthand to return the current statistics engine
111
- def stat_engine
112
- agent_instance.stats_engine
113
- end
114
-
115
- # returns a scoped metric stat for the specified name
116
- def get_stats_scoped(first_name, scoped_metric_only)
117
- stat_engine.get_stats(first_name, true, scoped_metric_only)
118
- end
119
-
120
- # Shorthand method to get stats from the stat engine
121
- def get_stats_unscoped(name)
122
- stat_engine.get_stats_no_scope(name)
123
- end
124
-
125
- # Helper for setting a hash key if the hash key is nil,
126
- # instead of the default ||= behavior which sets if it is
127
- # false as well
128
- def set_if_nil(hash, key)
129
- hash[key] = true if hash[key].nil?
130
- end
131
-
132
- # helper for logging errors to the newrelic_agent.log
133
- # properly. Logs the error at error level
134
- def log_errors(code_area)
135
- yield
136
- rescue => e
137
- ::NewRelic::Agent.logger.error("Caught exception in #{code_area}.", e)
138
- end
139
-
140
- # provides the header for our traced execution scoped
141
- # method - gets the initial time, sets the tracing flag if
142
- # needed, and pushes the frame onto the metric stack
143
- # logs any errors that occur and returns the start time and
144
- # the frame so that we can check for it later, to maintain
145
- # sanity. If the frame stack becomes unbalanced, this
146
- # transaction loses meaning.
147
- def trace_execution_scoped_header(state, t0)
148
- log_errors(:trace_execution_scoped_header) do
149
- stack = state.traced_method_stack
150
- stack.push_frame(state, :method_tracer, t0)
151
- end
152
- end
153
-
154
- def record_metrics(state, first_name, other_names, duration, exclusive, options)
155
- # The default value for :scoped_metric is true, so set it as true
156
- # if it was unset.
157
- record_scoped_metric = options.has_key?(:scoped_metric) ? options[:scoped_metric] : true
158
-
159
- if options[:metric]
160
- if record_scoped_metric
161
- stat_engine.record_scoped_and_unscoped_metrics(state, first_name, other_names, duration, exclusive)
162
- else
163
- metrics = [first_name].concat(other_names)
164
- stat_engine.record_unscoped_metrics(state, metrics, duration, exclusive)
165
- end
166
- else
167
- stat_engine.record_unscoped_metrics(state, other_names, duration, exclusive)
168
- end
169
- end
170
-
171
- # Handles the end of the #trace_execution_scoped method -
172
- # calculating the time taken, popping the tracing flag if
173
- # needed, deducting time taken by children, and tracing the
174
- # subsidiary unscoped metrics if any
175
- #
176
- # this method fails safely if the header does not manage to
177
- # push the scope onto the stack - it simply does not trace
178
- # any metrics.
179
- def trace_execution_scoped_footer(state, t0, first_name, metric_names, expected_frame, options, t1=Time.now.to_f)
180
- log_errors(:trace_method_execution_footer) do
181
- if expected_frame
182
- stack = state.traced_method_stack
183
- frame = stack.pop_frame(state, expected_frame, first_name, t1, !!options[:metric])
184
- duration = t1 - t0
185
- if duration < 1_000_000_000 # roughly 31 years
186
- if duration < 0
187
- ::NewRelic::Agent.logger.log_once(:warn, "metric_duration_negative:#{first_name}",
188
- "Metric #{first_name} has negative duration: #{duration} s")
189
- end
190
-
191
- exclusive = duration - frame.children_time
192
- if exclusive < 0
193
- ::NewRelic::Agent.logger.log_once(:warn, "metric_exclusive_negative:#{first_name}",
194
- "Metric #{first_name} has negative exclusive time: duration = #{duration} s, child_time = #{frame.children_time}")
195
- end
196
-
197
- record_metrics(state, first_name, metric_names, duration, exclusive, options)
198
- else
199
- ::NewRelic::Agent.logger.log_once(:warn, "too_huge_metric:#{first_name}",
200
- "Ignoring metric #{first_name} with unacceptably large duration: #{duration} s")
201
- end
202
- end
203
- end
204
- end
205
- end
206
- include TraceExecutionScoped
207
-
208
- # Trace a given block with stats and keep track of the caller.
209
- # See NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer for a description of the arguments.
210
- # +metric_names+ is either a single name or an array of metric names.
211
- # If more than one metric is passed, the +produce_metric+ option only applies to the first. The
212
- # others are always recorded. Only the first metric is pushed onto the scope stack.
213
120
  #
214
- # Generally you pass an array of metric names if you want to record the metric under additional
215
- # categories, but generally this *should never ever be done*. Most of the time you can aggregate
216
- # on the server.
121
+ # This method is deprecated and exists only for backwards-compatibility
122
+ # reasons. Usages should be replaced with calls to
123
+ # NewRelic::Agent.record_metric.
217
124
  #
218
125
  # @api public
126
+ # @deprecated
219
127
  #
220
- def trace_execution_scoped(metric_names, options={}) #THREAD_LOCAL_ACCESS
221
- state = NewRelic::Agent::TransactionState.tl_get
222
- return yield unless state.is_execution_traced?
223
-
224
- metric_names = Array(metric_names)
225
- first_name = metric_names.shift
226
- return yield if first_name.nil?
227
-
228
- set_if_nil(options, :metric)
229
- additional_metrics_callback = options[:additional_metrics_callback]
230
- start_time = Time.now.to_f
231
- expected_scope = trace_execution_scoped_header(state, start_time)
128
+ def get_stats_scoped(first_name, scoped_metric_only)
129
+ NewRelic::Agent.instance.stats_engine.get_stats(first_name, true, scoped_metric_only)
130
+ end
232
131
 
233
- begin
234
- result = yield
235
- metric_names += Array(additional_metrics_callback.call) if additional_metrics_callback
236
- result
237
- ensure
238
- trace_execution_scoped_footer(state, start_time, first_name, metric_names, expected_scope, options)
239
- end
132
+ # This method is deprecated and exists only for backwards-compatibility
133
+ # reasons. Usages should be replaced with calls to
134
+ # NewRelic::Agent.record_metric.
135
+ #
136
+ # @api public
137
+ # @deprecated
138
+ #
139
+ def get_stats_unscoped(name)
140
+ NewRelic::Agent.instance.stats_engine.get_stats_no_scope(name)
240
141
  end
241
142
 
242
143
  # Defines methods used at the class level, for adding instrumentation
@@ -324,11 +225,9 @@ module NewRelic
324
225
  # instrumentation into effectively one method call overhead
325
226
  # when the agent is disabled
326
227
  def assemble_code_header(method_name, metric_name_code, options)
327
- header = "return #{_untraced_method_name(method_name, metric_name_code)}(*args, &block) unless NewRelic::Agent.tl_is_execution_traced?\n"
328
-
329
- header += options[:code_header].to_s
330
-
331
- header
228
+ header = "return #{_untraced_method_name(method_name, metric_name_code)}(*args, &block) unless NewRelic::Agent.tl_is_execution_traced?\n"
229
+ header += options[:code_header].to_s
230
+ header
332
231
  end
333
232
 
334
233
  # returns an eval-able string that contains the traced
@@ -351,29 +250,9 @@ module NewRelic
351
250
  # returns an eval-able string that contains the tracing code
352
251
  # for a fully traced metric including scoping
353
252
  def method_with_push_scope(method_name, metric_name_code, options)
354
- # At this point, we expect 'self' to point to a Class or Module that
355
- # has included the NewRelic::Agent::MethodTracer module, which means
356
- # it should have an instance method defined called
357
- # 'trace_execution_scoped'.
358
- #
359
- # If this is not the case, assume that
360
- # we're relying on the fact that MethodTracer is included into the
361
- # Module class by init_plugin, and try to call
362
- # trace_execution_scoped as a class rather than instance method.
363
- #
364
- # The inclusion of MethodTracer into Module will be going away in
365
- # the future, so if we detect people relying on that behavior, warn
366
- # and record a supportability metric.
367
- if self.method_defined?(:trace_execution_scoped)
368
- klass = 'self'
369
- else
370
- NewRelic::Agent.logger.warn("Called add_method_tracer from #{self} without including the NewRelic::Agent::MethodTracer module. This is deprecated and will stop working in the future. Please see http://docs.newrelic.com/docs/ruby/ruby-custom-metric-collection for examples of correct add_method_tracer usage.")
371
- NewRelic::Agent.increment_metric("Supportability/usage/improper_add_method_tracer")
372
- klass = 'self.class'
373
- end
374
253
  "def #{_traced_method_name(method_name, metric_name_code)}(*args, &block)
375
254
  #{options[:code_header]}
376
- result = #{klass}.trace_execution_scoped(\"#{metric_name_code}\",
255
+ result = ::NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(\"#{metric_name_code}\",
377
256
  :metric => #{options[:metric]}) do
378
257
  #{_untraced_method_name(method_name, metric_name_code)}(*args, &block)
379
258
  end