ghazel-newrelic_rpm 3.1.0.1 → 3.4.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +120 -35
- data/LICENSE +29 -2
- data/README.rdoc +2 -2
- data/bin/mongrel_rpm +0 -0
- data/bin/newrelic +0 -0
- data/bin/newrelic_cmd +0 -0
- data/lib/new_relic/agent.rb +50 -38
- data/lib/new_relic/agent/agent.rb +459 -337
- data/lib/new_relic/agent/beacon_configuration.rb +71 -11
- data/lib/new_relic/agent/browser_monitoring.rb +73 -14
- data/lib/new_relic/agent/busy_calculator.rb +11 -3
- data/lib/new_relic/agent/chained_call.rb +2 -2
- data/lib/new_relic/agent/database.rb +223 -0
- data/lib/new_relic/agent/error_collector.rb +231 -183
- data/lib/new_relic/agent/instrumentation.rb +2 -2
- data/lib/new_relic/agent/instrumentation/active_merchant.rb +10 -2
- data/lib/new_relic/agent/instrumentation/active_record.rb +138 -0
- data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +7 -1
- data/lib/new_relic/agent/instrumentation/authlogic.rb +6 -0
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +46 -14
- data/lib/new_relic/agent/instrumentation/data_mapper.rb +8 -2
- data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +11 -3
- data/lib/new_relic/agent/instrumentation/memcache.rb +49 -25
- data/lib/new_relic/agent/instrumentation/merb/controller.rb +7 -2
- data/lib/new_relic/agent/instrumentation/merb/errors.rb +7 -1
- data/lib/new_relic/agent/instrumentation/metric_frame.rb +31 -4
- data/lib/new_relic/agent/instrumentation/metric_frame/pop.rb +1 -5
- data/lib/new_relic/agent/instrumentation/net.rb +8 -2
- data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +5 -2
- data/lib/new_relic/agent/instrumentation/queue_time.rb +1 -1
- data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +66 -35
- data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +7 -1
- data/lib/new_relic/agent/instrumentation/rails/errors.rb +7 -1
- data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +121 -1
- data/lib/new_relic/agent/instrumentation/rails3/errors.rb +7 -1
- data/lib/new_relic/agent/instrumentation/rainbows_instrumentation.rb +21 -0
- data/lib/new_relic/agent/instrumentation/resque.rb +80 -0
- data/lib/new_relic/agent/instrumentation/sinatra.rb +46 -20
- data/lib/new_relic/agent/instrumentation/sunspot.rb +6 -0
- data/lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb +7 -2
- data/lib/new_relic/agent/method_tracer.rb +205 -99
- data/lib/new_relic/agent/new_relic_service.rb +221 -0
- data/lib/new_relic/agent/pipe_channel_manager.rb +161 -0
- data/lib/new_relic/agent/pipe_service.rb +54 -0
- data/lib/new_relic/agent/samplers/delayed_job_sampler.rb +89 -0
- data/lib/new_relic/agent/samplers/memory_sampler.rb +6 -7
- data/lib/new_relic/agent/shim_agent.rb +5 -5
- data/lib/new_relic/agent/sql_sampler.rb +282 -0
- data/lib/new_relic/agent/stats_engine.rb +2 -0
- data/lib/new_relic/agent/stats_engine/gc_profiler.rb +123 -0
- data/lib/new_relic/agent/stats_engine/metric_stats.rb +35 -30
- data/lib/new_relic/agent/stats_engine/samplers.rb +10 -4
- data/lib/new_relic/agent/stats_engine/transactions.rb +28 -87
- data/lib/new_relic/agent/transaction_info.rb +74 -0
- data/lib/new_relic/agent/transaction_sample_builder.rb +18 -3
- data/lib/new_relic/agent/transaction_sampler.rb +108 -20
- data/lib/new_relic/agent/worker_loop.rb +14 -6
- data/lib/new_relic/collection_helper.rb +19 -11
- data/lib/new_relic/command.rb +1 -1
- data/lib/new_relic/commands/deployments.rb +2 -2
- data/lib/new_relic/commands/install.rb +2 -13
- data/lib/new_relic/control.rb +2 -3
- data/lib/new_relic/control/class_methods.rb +12 -6
- data/lib/new_relic/control/configuration.rb +57 -8
- data/lib/new_relic/control/frameworks.rb +10 -0
- data/lib/new_relic/control/frameworks/external.rb +4 -4
- data/lib/new_relic/control/frameworks/merb.rb +2 -1
- data/lib/new_relic/control/frameworks/rails.rb +35 -22
- data/lib/new_relic/control/frameworks/rails3.rb +12 -7
- data/lib/new_relic/control/frameworks/ruby.rb +5 -5
- data/lib/new_relic/control/frameworks/sinatra.rb +1 -4
- data/lib/new_relic/control/instance_methods.rb +38 -12
- data/lib/new_relic/control/instrumentation.rb +23 -4
- data/lib/new_relic/control/logging_methods.rb +70 -15
- data/lib/new_relic/control/server_methods.rb +22 -9
- data/lib/new_relic/delayed_job_injection.rb +16 -3
- data/lib/new_relic/helper.rb +21 -0
- data/lib/new_relic/language_support.rb +95 -0
- data/lib/new_relic/local_environment.rb +92 -48
- data/lib/new_relic/metric_data.rb +7 -2
- data/lib/new_relic/metric_spec.rb +12 -9
- data/lib/new_relic/noticed_error.rb +6 -1
- data/lib/new_relic/rack/browser_monitoring.rb +18 -19
- data/lib/new_relic/rack/developer_mode.rb +3 -2
- data/lib/new_relic/recipes.rb +8 -4
- data/lib/new_relic/stats.rb +17 -60
- data/lib/new_relic/transaction_analysis.rb +2 -1
- data/lib/new_relic/transaction_analysis/segment_summary.rb +4 -2
- data/lib/new_relic/transaction_sample.rb +60 -75
- data/lib/new_relic/transaction_sample/segment.rb +31 -79
- data/lib/new_relic/version.rb +2 -2
- data/lib/newrelic_rpm.rb +1 -1
- data/newrelic.yml +2 -2
- data/newrelic_rpm.gemspec +46 -54
- data/test/active_record_fixtures.rb +3 -3
- data/test/config/newrelic.yml +1 -1
- data/test/fixtures/proc_cpuinfo.txt +575 -0
- data/test/new_relic/agent/agent/connect_test.rb +128 -25
- data/test/new_relic/agent/agent/start_test.rb +9 -94
- data/test/new_relic/agent/agent/start_worker_thread_test.rb +2 -4
- data/test/new_relic/agent/agent_test.rb +51 -78
- data/test/new_relic/agent/agent_test_controller.rb +1 -1
- data/test/new_relic/agent/agent_test_controller_test.rb +49 -33
- data/test/new_relic/agent/beacon_configuration_test.rb +12 -5
- data/test/new_relic/agent/browser_monitoring_test.rb +99 -50
- data/test/new_relic/agent/database_test.rb +161 -0
- data/test/new_relic/agent/error_collector_test.rb +47 -23
- data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +96 -42
- data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +0 -2
- data/test/new_relic/agent/instrumentation/instrumentation_test.rb +1 -1
- data/test/new_relic/agent/instrumentation/metric_frame/pop_test.rb +3 -11
- data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +9 -9
- data/test/new_relic/agent/instrumentation/queue_time_test.rb +6 -11
- data/test/new_relic/agent/memcache_instrumentation_test.rb +54 -18
- data/test/new_relic/agent/method_tracer/class_methods/add_method_tracer_test.rb +1 -1
- data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +1 -1
- data/test/new_relic/agent/method_tracer_test.rb +3 -2
- data/test/new_relic/agent/new_relic_service_test.rb +151 -0
- data/test/new_relic/agent/pipe_channel_manager_test.rb +114 -0
- data/test/new_relic/agent/pipe_service_test.rb +113 -0
- data/test/new_relic/agent/rpm_agent_test.rb +4 -31
- data/test/new_relic/agent/sql_sampler_test.rb +192 -0
- data/test/new_relic/agent/stats_engine/metric_stats_test.rb +19 -18
- data/test/new_relic/agent/stats_engine_test.rb +41 -6
- data/test/new_relic/agent/transaction_info_test.rb +13 -0
- data/test/new_relic/agent/transaction_sample_builder_test.rb +27 -4
- data/test/new_relic/agent/transaction_sampler_test.rb +68 -46
- data/test/new_relic/agent/worker_loop_test.rb +3 -3
- data/test/new_relic/agent_test.rb +242 -0
- data/test/new_relic/collection_helper_test.rb +50 -28
- data/test/new_relic/control/configuration_test.rb +77 -0
- data/test/new_relic/control/logging_methods_test.rb +49 -21
- data/test/new_relic/control_test.rb +115 -54
- data/test/new_relic/delayed_job_injection_test.rb +21 -0
- data/test/new_relic/fake_collector.rb +210 -0
- data/test/new_relic/fake_service.rb +44 -0
- data/test/new_relic/local_environment_test.rb +14 -1
- data/test/new_relic/metric_parser/metric_parser_test.rb +11 -0
- data/test/new_relic/rack/browser_monitoring_test.rb +84 -23
- data/test/new_relic/rack/developer_mode_helper_test.rb +141 -0
- data/test/new_relic/rack/developer_mode_test.rb +31 -0
- data/test/new_relic/stats_test.rb +3 -18
- data/test/new_relic/transaction_analysis/segment_summary_test.rb +14 -0
- data/test/new_relic/transaction_analysis_test.rb +3 -3
- data/test/new_relic/transaction_sample/segment_test.rb +15 -80
- data/test/new_relic/transaction_sample_test.rb +25 -18
- data/test/script/build_test_gem.sh +51 -0
- data/test/script/ci.sh +140 -0
- data/test/script/ci_agent-tests_runner.sh +82 -0
- data/test/script/ci_bench.sh +52 -0
- data/test/script/ci_multiverse_runner.sh +63 -0
- data/test/test_contexts.rb +1 -0
- data/test/test_helper.rb +18 -5
- data/ui/helpers/developer_mode_helper.rb +14 -8
- data/ui/helpers/google_pie_chart.rb +0 -1
- data/ui/views/newrelic/index.rhtml +2 -2
- data/vendor/gems/dependency_detection-0.0.1.build/LICENSE +4 -18
- data/vendor/gems/dependency_detection-0.0.1.build/lib/dependency_detection.rb +10 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/mem_cache.rb +11 -11
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/metric_parser.rb +17 -4
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/view.rb +4 -0
- metadata +50 -36
- data/lib/new_relic/agent/instrumentation/rails/active_record_instrumentation.rb +0 -108
- data/lib/new_relic/agent/instrumentation/rails3/active_record_instrumentation.rb +0 -112
- data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +0 -40
- data/lib/new_relic/data_serialization.rb +0 -84
- data/lib/new_relic/histogram.rb +0 -91
- data/lib/new_relic/rack/metric_app.rb +0 -65
- data/lib/new_relic/rack/mongrel_rpm.ru +0 -28
- data/lib/new_relic/rack/newrelic.yml +0 -27
- data/lib/new_relic/rack_app.rb +0 -6
- data/test/new_relic/data_serialization_test.rb +0 -70
- data/vendor/gems/dependency_detection-0.0.1.build/README +0 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/LICENSE +0 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/README +0 -0
@@ -1,54 +1,49 @@
|
|
1
|
+
require 'new_relic/language_support'
|
2
|
+
|
1
3
|
module NewRelic
|
2
4
|
module Agent
|
3
5
|
class StatsEngine
|
6
|
+
# Handles methods related to actual Metric collection
|
4
7
|
module MetricStats
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
# A simple mutex-synchronized hash to make sure our statistics
|
9
|
+
# are internally consistent even in truly-threaded rubies like JRuby
|
10
|
+
class SynchronizedHash < ::Hash
|
11
|
+
include NewRelic::LanguageSupport::SynchronizedHash
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@lock = Mutex.new
|
9
15
|
end
|
10
|
-
|
16
|
+
|
11
17
|
def []=(*args)
|
12
|
-
@
|
13
|
-
super
|
14
|
-
}
|
15
|
-
end
|
16
|
-
|
17
|
-
def [](*args)
|
18
|
-
@mutex.synchronize {
|
19
|
-
super
|
20
|
-
}
|
18
|
+
@lock.synchronize { super }
|
21
19
|
end
|
22
20
|
|
23
21
|
def clear(*args)
|
24
|
-
@
|
25
|
-
super
|
26
|
-
}
|
22
|
+
@lock.synchronize { super }
|
27
23
|
end
|
28
24
|
|
29
25
|
def delete(*args)
|
30
|
-
@
|
31
|
-
super
|
32
|
-
}
|
26
|
+
@lock.synchronize { super }
|
33
27
|
end
|
34
28
|
|
35
29
|
def delete_if(*args)
|
36
|
-
@
|
37
|
-
super
|
38
|
-
}
|
30
|
+
@lock.synchronize { super }
|
39
31
|
end
|
40
32
|
end
|
41
|
-
|
33
|
+
|
34
|
+
# Returns all of the metric names of all the stats in the engine
|
42
35
|
def metrics
|
43
36
|
stats_hash.keys.map(&:to_s)
|
44
37
|
end
|
45
|
-
|
38
|
+
|
39
|
+
# a simple accessor for looking up a stat with no scope -
|
40
|
+
# returns a new stats object if no stats object for that
|
41
|
+
# metric exists yet
|
46
42
|
def get_stats_no_scope(metric_name)
|
47
43
|
stats_hash[NewRelic::MetricSpec.new(metric_name, '')] ||= NewRelic::MethodTraceStats.new
|
48
44
|
end
|
49
45
|
|
50
46
|
# This version allows a caller to pass a stat class to use
|
51
|
-
#
|
52
47
|
def get_custom_stats(metric_name, stat_class)
|
53
48
|
stats_hash[NewRelic::MetricSpec.new(metric_name)] ||= stat_class.new
|
54
49
|
end
|
@@ -69,13 +64,21 @@ module NewRelic
|
|
69
64
|
end
|
70
65
|
stats
|
71
66
|
end
|
72
|
-
|
67
|
+
|
68
|
+
# Returns a stat if one exists, otherwise returns nil. If you
|
69
|
+
# want auto-initialization, use one of get_stats or get_stats_no_scope
|
73
70
|
def lookup_stats(metric_name, scope_name = '')
|
74
71
|
stats_hash[NewRelic::MetricSpec.new(metric_name, scope_name)]
|
75
72
|
end
|
76
|
-
|
73
|
+
|
74
|
+
# This module was extracted from the harvest method and should
|
75
|
+
# be refactored
|
77
76
|
module Harvest
|
78
|
-
|
77
|
+
|
78
|
+
# merge data from previous harvests into this stats engine -
|
79
|
+
# takes into account the case where there are new stats for
|
80
|
+
# that metric, and the case where there is no current data
|
81
|
+
# for that metric
|
79
82
|
def merge_data(metric_data_hash)
|
80
83
|
metric_data_hash.each do |metric_spec, metric_data|
|
81
84
|
new_data = lookup_stats(metric_spec.name, metric_spec.scope)
|
@@ -172,7 +175,9 @@ module NewRelic
|
|
172
175
|
def reset_stats
|
173
176
|
stats_hash.values.each { |s| s.reset }
|
174
177
|
end
|
175
|
-
|
178
|
+
|
179
|
+
# returns a memoized SynchronizedHash that holds the actual
|
180
|
+
# instances of Stats keyed off their MetricName
|
176
181
|
def stats_hash
|
177
182
|
@stats_hash ||= SynchronizedHash.new
|
178
183
|
end
|
@@ -6,14 +6,20 @@ module Agent
|
|
6
6
|
def add_harvest_sampler(*args); end
|
7
7
|
def start_sampler_thread(*args); end
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
|
+
# Contains statistics engine extensions to support the concept of samplers
|
10
11
|
module Samplers
|
11
12
|
|
12
13
|
# By default a sampler polls on harvest time, once a minute. However you can
|
13
14
|
# override #use_harvest_sampler? to return false and it will sample
|
14
15
|
# every POLL_PERIOD seconds on a background thread.
|
15
16
|
POLL_PERIOD = 20
|
16
|
-
|
17
|
+
|
18
|
+
# starts the sampler thread which runs periodically, rather than
|
19
|
+
# at harvest time. This is deprecated, and should not actually
|
20
|
+
# be used - mo threads mo problems
|
21
|
+
#
|
22
|
+
# returns unless there are actually periodic samplers to run
|
17
23
|
def start_sampler_thread
|
18
24
|
|
19
25
|
return if @sampler_thread && @sampler_thread.alive?
|
@@ -41,7 +47,7 @@ module Agent
|
|
41
47
|
end
|
42
48
|
|
43
49
|
def log_added_sampler(type, sampler)
|
44
|
-
log.debug "Adding #{type} sampler: #{sampler.
|
50
|
+
log.debug "Adding #{type} sampler: #{sampler.id}"
|
45
51
|
end
|
46
52
|
|
47
53
|
public
|
@@ -68,7 +74,7 @@ module Agent
|
|
68
74
|
begin
|
69
75
|
sampled_item.poll
|
70
76
|
false # it's okay. don't delete it.
|
71
|
-
rescue
|
77
|
+
rescue => e
|
72
78
|
log.error "Removing #{sampled_item} from list"
|
73
79
|
log.error e
|
74
80
|
log.debug e.backtrace.to_s
|
@@ -1,10 +1,9 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
module NewRelic
|
2
3
|
module Agent
|
3
4
|
class StatsEngine
|
4
|
-
|
5
|
-
#
|
6
|
-
# when the agent is disabled
|
7
|
-
|
5
|
+
# A simple stack element that tracks the current name and length
|
6
|
+
# of the executing stack
|
8
7
|
class ScopeStackElement
|
9
8
|
attr_reader :name, :deduct_call_time_from_parent
|
10
9
|
attr_accessor :children_time
|
@@ -14,8 +13,13 @@ module Agent
|
|
14
13
|
@children_time = 0
|
15
14
|
end
|
16
15
|
end
|
17
|
-
|
16
|
+
|
17
|
+
# Handles pushing and popping elements onto an internal stack that
|
18
|
+
# tracks where time should be allocated in Transaction Traces
|
18
19
|
module Transactions
|
20
|
+
|
21
|
+
# Defines methods that stub out the stats engine methods
|
22
|
+
# when the agent is disabled
|
19
23
|
module Shim # :nodoc:
|
20
24
|
def start_transaction(*args); end
|
21
25
|
def end_transaction; end
|
@@ -25,36 +29,32 @@ module Agent
|
|
25
29
|
def scope_name; end
|
26
30
|
def pop_scope(*args); end
|
27
31
|
end
|
28
|
-
|
32
|
+
|
33
|
+
# add a new transaction sampler, unless we're currently in a
|
34
|
+
# transaction (then we fail)
|
29
35
|
def transaction_sampler= sampler
|
30
36
|
fail "Can't add a scope listener midflight in a transaction" if scope_stack.any?
|
31
37
|
@transaction_sampler = sampler
|
32
38
|
end
|
33
|
-
|
39
|
+
|
40
|
+
# removes a transaction sampler
|
34
41
|
def remove_transaction_sampler(l)
|
35
42
|
@transaction_sampler = nil
|
36
43
|
end
|
37
|
-
|
44
|
+
|
45
|
+
# Pushes a scope onto the transaction stack - this generates a
|
46
|
+
# TransactionSample::Segment at the end of transaction execution
|
38
47
|
def push_scope(metric, time = Time.now.to_f, deduct_call_time_from_parent = true)
|
39
|
-
|
40
48
|
stack = scope_stack
|
41
|
-
if collecting_gc?
|
42
|
-
if stack.empty?
|
43
|
-
# reset the gc time so we only include gc time spent during this call
|
44
|
-
@last_gc_timestamp = gc_time
|
45
|
-
@last_gc_count = gc_collections
|
46
|
-
else
|
47
|
-
capture_gc_time
|
48
|
-
end
|
49
|
-
end
|
50
49
|
@transaction_sampler.notice_push_scope metric, time if @transaction_sampler
|
51
50
|
scope = ScopeStackElement.new(metric, deduct_call_time_from_parent)
|
52
51
|
stack.push scope
|
53
52
|
scope
|
54
53
|
end
|
55
|
-
|
54
|
+
|
55
|
+
# Pops a scope off the transaction stack - this updates the
|
56
|
+
# transaction sampler that we've finished execution of a traced method
|
56
57
|
def pop_scope(expected_scope, duration, time=Time.now.to_f)
|
57
|
-
capture_gc_time if collecting_gc?
|
58
58
|
stack = scope_stack
|
59
59
|
scope = stack.pop
|
60
60
|
fail "unbalanced pop from blame stack, got #{scope ? scope.name : 'nil'}, expected #{expected_scope ? expected_scope.name : 'nil'}" if scope != expected_scope
|
@@ -69,7 +69,8 @@ module Agent
|
|
69
69
|
@transaction_sampler.notice_pop_scope(scope.name, time) if @transaction_sampler
|
70
70
|
scope
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
|
+
# Returns the latest ScopeStackElement
|
73
74
|
def peek_scope
|
74
75
|
scope_stack.last
|
75
76
|
end
|
@@ -84,9 +85,9 @@ module Agent
|
|
84
85
|
# via controller actions
|
85
86
|
def scope_name=(transaction)
|
86
87
|
Thread::current[:newrelic_scope_name] = transaction
|
87
|
-
Thread::current[:newrelic_most_recent_transaction] = transaction
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
|
+
# Returns the current scope name from the thread local
|
90
91
|
def scope_name
|
91
92
|
Thread::current[:newrelic_scope_name]
|
92
93
|
end
|
@@ -95,6 +96,7 @@ module Agent
|
|
95
96
|
def start_transaction(name = nil)
|
96
97
|
Thread::current[:newrelic_scope_stack] ||= []
|
97
98
|
self.scope_name = name if name
|
99
|
+
GCProfiler.init
|
98
100
|
end
|
99
101
|
|
100
102
|
# Try to clean up gracefully, otherwise we leave things hanging around on thread locals.
|
@@ -102,6 +104,7 @@ module Agent
|
|
102
104
|
# and is ignored.
|
103
105
|
#
|
104
106
|
def end_transaction
|
107
|
+
GCProfiler.capture
|
105
108
|
stack = scope_stack
|
106
109
|
|
107
110
|
if stack && stack.empty?
|
@@ -111,73 +114,11 @@ module Agent
|
|
111
114
|
end
|
112
115
|
|
113
116
|
private
|
114
|
-
|
115
|
-
#
|
116
|
-
def collecting_gc?
|
117
|
-
if !defined?(@@collecting_gc)
|
118
|
-
@@collecting_gc = false
|
119
|
-
if !NewRelic::Control.instance.multi_threaded?
|
120
|
-
@@collecting_gc = true if GC.respond_to?(:time) && GC.respond_to?(:collections) # 1.8.x
|
121
|
-
@@collecting_gc = true if defined?(GC::Profiler) && GC::Profiler.enabled? # 1.9.2
|
122
|
-
end
|
123
|
-
end
|
124
|
-
@@collecting_gc
|
125
|
-
end
|
126
|
-
|
127
|
-
# The total number of times the garbage collector has run since
|
128
|
-
# profiling was enabled
|
129
|
-
def gc_collections
|
130
|
-
if GC.respond_to?(:count)
|
131
|
-
GC.count
|
132
|
-
elsif GC.respond_to?(:collections)
|
133
|
-
GC.collections
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
# The total amount of time taken by garbage collection since
|
138
|
-
# profiling was enabled
|
139
|
-
def gc_time
|
140
|
-
if GC.respond_to?(:time)
|
141
|
-
GC.time
|
142
|
-
elsif defined?(GC::Profiler) && GC::Profiler.respond_to?(:total_time)
|
143
|
-
# The 1.9 profiler returns a time in usec
|
144
|
-
GC::Profiler.total_time * 1000000.0
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
# Assumes collecting_gc?
|
149
|
-
def capture_gc_time
|
150
|
-
# Skip this if we are already in this segment
|
151
|
-
return if !scope_stack.empty? && scope_stack.last.name == "GC/cumulative"
|
152
|
-
num_calls = gc_collections - @last_gc_count
|
153
|
-
elapsed = (gc_time - @last_gc_timestamp).to_f
|
154
|
-
@last_gc_timestamp = gc_time
|
155
|
-
@last_gc_count = gc_collections
|
156
|
-
|
157
|
-
if defined?(GC::Profiler)
|
158
|
-
GC::Profiler.clear
|
159
|
-
@last_gc_timestamp = 0
|
160
|
-
end
|
161
|
-
|
162
|
-
if num_calls > 0
|
163
|
-
# µs to seconds
|
164
|
-
elapsed = elapsed / 1000000.0
|
165
|
-
# Allocate the GC time to a scope as if the GC just ended
|
166
|
-
# right now.
|
167
|
-
time = Time.now.to_f
|
168
|
-
gc_scope = push_scope("GC/cumulative", time - elapsed)
|
169
|
-
# GC stats are collected into a blamed metric which allows
|
170
|
-
# us to show the stats controller by controller
|
171
|
-
gc_stats = NewRelic::Agent.get_stats(gc_scope.name, true)
|
172
|
-
gc_stats.record_multiple_data_points(elapsed, num_calls)
|
173
|
-
pop_scope(gc_scope, elapsed, time)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
117
|
+
|
118
|
+
# Returns the current scope stack, memoized to a thread local variable
|
177
119
|
def scope_stack
|
178
120
|
Thread::current[:newrelic_scope_stack] ||= []
|
179
121
|
end
|
180
|
-
|
181
122
|
end
|
182
123
|
end
|
183
124
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module NewRelic
|
4
|
+
module Agent
|
5
|
+
class TransactionInfo
|
6
|
+
|
7
|
+
attr_accessor :token, :capture_deep_tt, :transaction_name
|
8
|
+
attr_reader :start_time
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@guid = ""
|
12
|
+
@transaction_name = "(unknown)"
|
13
|
+
@start_time = Time.now
|
14
|
+
end
|
15
|
+
|
16
|
+
def force_persist_sample?(sample)
|
17
|
+
token && sample.duration > NewRelic::Control.instance.apdex_t
|
18
|
+
end
|
19
|
+
|
20
|
+
def include_guid?
|
21
|
+
token && duration > NewRelic::Control.instance.apdex_t
|
22
|
+
end
|
23
|
+
|
24
|
+
def guid
|
25
|
+
@guid
|
26
|
+
end
|
27
|
+
|
28
|
+
def guid=(value)
|
29
|
+
@guid = value
|
30
|
+
end
|
31
|
+
|
32
|
+
def duration
|
33
|
+
Time.now - start_time
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.get()
|
37
|
+
Thread.current[:newrelic_transaction_info] ||= TransactionInfo.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.set(instance)
|
41
|
+
Thread.current[:newrelic_transaction_info] = instance
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.clear
|
45
|
+
Thread.current[:newrelic_transaction_info] = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
# clears any existing transaction info object and initializes a new one.
|
49
|
+
# This starts the timer for the transaction.
|
50
|
+
def self.reset(request=nil)
|
51
|
+
clear
|
52
|
+
instance = get
|
53
|
+
instance.token = get_token(request)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.get_token(request)
|
57
|
+
return nil unless request
|
58
|
+
|
59
|
+
agent_flag = request.cookies['NRAGENT']
|
60
|
+
if agent_flag
|
61
|
+
s = agent_flag.split("=")
|
62
|
+
if s.length == 2
|
63
|
+
if s[0] == "tk" && s[1]
|
64
|
+
ERB::Util.h(s[1])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
else
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
@@ -9,6 +9,7 @@ module NewRelic
|
|
9
9
|
# accessed by any other thread so no need for synchronization.
|
10
10
|
class TransactionSampleBuilder
|
11
11
|
attr_reader :current_segment, :sample
|
12
|
+
attr_accessor :segment_limit
|
12
13
|
|
13
14
|
include NewRelic::CollectionHelper
|
14
15
|
|
@@ -16,24 +17,36 @@ module NewRelic
|
|
16
17
|
@sample = NewRelic::TransactionSample.new(time.to_f)
|
17
18
|
@sample_start = time.to_f
|
18
19
|
@current_segment = @sample.root_segment
|
20
|
+
@segment_limit = NewRelic::Control.instance.fetch('transaction_tracer', {}) \
|
21
|
+
.fetch('limit_segments', 4000)
|
19
22
|
end
|
20
23
|
|
21
24
|
def sample_id
|
22
25
|
@sample.sample_id
|
23
26
|
end
|
27
|
+
|
24
28
|
def ignored?
|
25
29
|
@ignore || @sample.params[:path].nil?
|
26
30
|
end
|
31
|
+
|
27
32
|
def ignore_transaction
|
28
33
|
@ignore = true
|
29
34
|
end
|
35
|
+
|
30
36
|
def trace_entry(metric_name, time)
|
31
|
-
|
32
|
-
|
33
|
-
|
37
|
+
if @sample.count_segments < @segment_limit
|
38
|
+
segment = @sample.create_segment(time.to_f - @sample_start, metric_name)
|
39
|
+
@current_segment.add_called_segment(segment)
|
40
|
+
@current_segment = segment
|
41
|
+
if @sample.count_segments == @segment_limit
|
42
|
+
NewRelic::Control.instance.log.debug("Segment limit of #{@segment_limit} reached, ceasing collection.")
|
43
|
+
end
|
44
|
+
@current_segment
|
45
|
+
end
|
34
46
|
end
|
35
47
|
|
36
48
|
def trace_exit(metric_name, time)
|
49
|
+
return unless @sample.count_segments < @segment_limit
|
37
50
|
if metric_name != @current_segment.metric_name
|
38
51
|
fail "unbalanced entry/exit: #{metric_name} != #{@current_segment.metric_name}"
|
39
52
|
end
|
@@ -51,6 +64,8 @@ module NewRelic
|
|
51
64
|
end
|
52
65
|
@sample.root_segment.end_trace(time.to_f - @sample_start)
|
53
66
|
@sample.params[:custom_params] = normalize_params(NewRelic::Agent::Instrumentation::MetricFrame.custom_parameters)
|
67
|
+
|
68
|
+
@sample.force_persist = NewRelic::Agent::TransactionInfo.get.force_persist_sample?(sample)
|
54
69
|
@sample.freeze
|
55
70
|
@current_segment = nil
|
56
71
|
end
|