tingyun_rpm 1.1.4.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/Guardfile +10 -0
- data/lib/ting_yun/agent.rb +1 -0
- data/lib/ting_yun/agent/agent.rb +16 -27
- data/lib/ting_yun/agent/collector/error_collector.rb +7 -18
- data/lib/ting_yun/agent/collector/error_collector/noticed_error.rb +26 -21
- data/lib/ting_yun/agent/collector/middle_ware_collector/cpu_sampler.rb +4 -9
- data/lib/ting_yun/agent/collector/sql_sampler.rb +32 -188
- data/lib/ting_yun/agent/collector/sql_sampler/slow_sql.rb +47 -0
- data/lib/ting_yun/agent/collector/sql_sampler/sql_trace.rb +73 -0
- data/lib/ting_yun/agent/collector/sql_sampler/transaction_sql_data.rb +26 -0
- data/lib/ting_yun/agent/collector/stats_engine/metric_stats.rb +6 -5
- data/lib/ting_yun/agent/collector/stats_engine/stats_hash.rb +2 -2
- data/lib/ting_yun/agent/collector/transaction_sampler.rb +23 -159
- data/lib/ting_yun/agent/collector/transaction_sampler/class_method.rb +130 -0
- data/lib/ting_yun/agent/collector/transaction_sampler/slowest_sample_buffer.rb +1 -1
- data/lib/ting_yun/agent/collector/transaction_sampler/transaction_sample_buffer_base.rb +1 -1
- data/lib/ting_yun/agent/cross_app/cross_app_monitor.rb +29 -79
- data/lib/ting_yun/agent/cross_app/cross_app_tracing.rb +36 -66
- data/lib/ting_yun/agent/database.rb +41 -349
- data/lib/ting_yun/agent/database/connection_manager.rb +44 -0
- data/lib/ting_yun/agent/database/explain_plan_helpers.rb +173 -0
- data/lib/ting_yun/agent/database/obfuscator.rb +151 -0
- data/lib/ting_yun/agent/database/statement.rb +70 -0
- data/lib/ting_yun/agent/event/event_loop.rb +1 -2
- data/lib/ting_yun/agent/instance_methods/connect.rb +8 -20
- data/lib/ting_yun/agent/instance_methods/container_data_manager.rb +2 -3
- data/lib/ting_yun/agent/instance_methods/handle_errors.rb +6 -1
- data/lib/ting_yun/agent/instance_methods/start.rb +13 -81
- data/lib/ting_yun/agent/transaction.rb +48 -391
- data/lib/ting_yun/agent/transaction/apdex.rb +53 -0
- data/lib/ting_yun/agent/transaction/attributes.rb +2 -1
- data/lib/ting_yun/agent/transaction/class_method.rb +127 -0
- data/lib/ting_yun/agent/transaction/exceptions.rb +42 -0
- data/lib/ting_yun/agent/transaction/instance_method.rb +139 -0
- data/lib/ting_yun/agent/transaction/request_attributes.rb +9 -39
- data/lib/ting_yun/agent/transaction/trace.rb +7 -5
- data/lib/ting_yun/agent/transaction/trace_node.rb +1 -3
- data/lib/ting_yun/agent/transaction/traced_method_stack.rb +2 -3
- data/lib/ting_yun/agent/transaction/transaction_sample_builder.rb +6 -1
- data/lib/ting_yun/agent/transaction/transaction_state.rb +59 -17
- data/lib/ting_yun/agent/transaction/transaction_timings.rb +72 -0
- data/lib/ting_yun/configuration.rb +11 -0
- data/lib/ting_yun/configuration/default_source.rb +20 -17
- data/lib/ting_yun/configuration/manager.rb +50 -21
- data/lib/ting_yun/frameworks.rb +1 -0
- data/lib/ting_yun/frameworks/rails.rb +15 -0
- data/lib/ting_yun/instrumentation/active_record.rb +12 -18
- data/lib/ting_yun/instrumentation/middleware_tracing.rb +8 -14
- data/lib/ting_yun/instrumentation/mongo.rb +21 -27
- data/lib/ting_yun/instrumentation/mongo_command_log_subscriber.rb +7 -3
- data/lib/ting_yun/instrumentation/moped.rb +2 -2
- data/lib/ting_yun/instrumentation/net.rb +4 -5
- data/lib/ting_yun/instrumentation/rack.rb +1 -2
- data/lib/ting_yun/instrumentation/rails4/active_record_subscriber.rb +22 -20
- data/lib/ting_yun/instrumentation/redis.rb +2 -2
- data/lib/ting_yun/instrumentation/support/controller_instrumentation.rb +1 -1
- data/lib/ting_yun/instrumentation/support/external_error.rb +19 -16
- data/lib/ting_yun/instrumentation/support/javascript_instrumentor.rb +92 -0
- data/lib/ting_yun/instrumentation/support/thrift_helper.rb +73 -0
- data/lib/ting_yun/instrumentation/thrift.rb +19 -222
- data/lib/ting_yun/logger.rb +1 -0
- data/lib/ting_yun/logger/agent_logger.rb +11 -67
- data/lib/ting_yun/logger/create_logger_helper.rb +72 -0
- data/lib/ting_yun/metrics/metric_data.rb +9 -31
- data/lib/ting_yun/metrics/metric_spec.rb +11 -0
- data/lib/ting_yun/metrics/stats.rb +24 -1
- data/lib/ting_yun/middleware/agent_middleware.rb +28 -0
- data/lib/ting_yun/middleware/browser_monitoring.rb +111 -0
- data/lib/ting_yun/support/coerce.rb +1 -0
- data/lib/ting_yun/support/exception.rb +2 -33
- data/lib/ting_yun/support/local_environment.rb +7 -7
- data/lib/ting_yun/support/serialize/marshaller.rb +7 -25
- data/lib/ting_yun/ting_yun_service.rb +12 -9
- data/lib/ting_yun/ting_yun_service/connection.rb +3 -0
- data/lib/ting_yun/ting_yun_service/http.rb +4 -1
- data/lib/ting_yun/ting_yun_service/request.rb +5 -13
- data/lib/ting_yun/ting_yun_service/upload_service.rb +5 -7
- data/lib/ting_yun/version.rb +3 -5
- data/lib/tingyun_rpm.rb +12 -10
- data/tingyun_rpm.gemspec +3 -0
- metadata +49 -5
- data/.DS_Store +0 -0
- data/lib/ting_yun/agent/collector/base_sampler.rb +0 -2
@@ -14,11 +14,12 @@ module TingYun
|
|
14
14
|
|
15
15
|
include HandleErrors
|
16
16
|
|
17
|
-
|
18
|
-
attr_accessor :connect_attempts
|
17
|
+
|
19
18
|
|
20
19
|
# Disconnect just sets connected to false, which prevents
|
21
20
|
# the agent from trying to connect again
|
21
|
+
# @connect_state has three state {:disconnected,:pending,:connected}
|
22
|
+
|
22
23
|
def disconnect
|
23
24
|
@connect_state = :disconnected
|
24
25
|
true
|
@@ -39,17 +40,6 @@ module TingYun
|
|
39
40
|
force || (!connected? && !disconnected?)
|
40
41
|
end
|
41
42
|
|
42
|
-
# Retry period is a minute for each failed attempt that
|
43
|
-
# we've made. This should probably do some sort of sane TCP
|
44
|
-
# backoff to prevent hammering the server, but a minute for
|
45
|
-
# each attempt seems to work reasonably well.
|
46
|
-
def connect_retry_period
|
47
|
-
[600, connect_attempts * 60].min
|
48
|
-
end
|
49
|
-
|
50
|
-
def note_connect_failure
|
51
|
-
self.connect_attempts += 1
|
52
|
-
end
|
53
43
|
|
54
44
|
def generate_environment_report
|
55
45
|
@environment_report = environment_for_connect
|
@@ -114,17 +104,15 @@ module TingYun
|
|
114
104
|
# agent run and Ting Yun sees it as a separate instance (default is false).
|
115
105
|
def catch_errors
|
116
106
|
yield
|
117
|
-
|
118
|
-
rescue TingYun::Support::Exception::ExpiredConfigurationException => e
|
107
|
+
rescue TingYun::Support::Exception::UnKnownServerException => e
|
119
108
|
handle_force_restart(e)
|
120
109
|
retry
|
121
|
-
rescue TingYun::Support::Exception::
|
122
|
-
|
110
|
+
rescue TingYun::Support::Exception::ServerConnectionException => e
|
111
|
+
handle_delay_restart(e, 60)
|
123
112
|
retry
|
124
|
-
rescue TingYun::Support::Exception::InvalidDataException => e
|
125
|
-
handle_server_error(e)
|
126
113
|
rescue => e
|
127
|
-
|
114
|
+
handle_delay_restart(e, 60)
|
115
|
+
retry
|
128
116
|
end
|
129
117
|
|
130
118
|
# Takes a hash of configuration data returned from the
|
@@ -14,7 +14,7 @@ module TingYun
|
|
14
14
|
module ContainerDataManager
|
15
15
|
|
16
16
|
|
17
|
-
attr_reader :stats_engine, :error_collector, :transaction_sampler, :sql_sampler
|
17
|
+
attr_reader :stats_engine, :error_collector, :transaction_sampler, :sql_sampler
|
18
18
|
|
19
19
|
|
20
20
|
def drop_buffered_data
|
@@ -34,7 +34,6 @@ module TingYun
|
|
34
34
|
@error_collector = TingYun::Agent::Collector::ErrorCollector.new
|
35
35
|
@transaction_sampler = TingYun::Agent::Collector::TransactionSampler.new
|
36
36
|
@sql_sampler = TingYun::Agent::Collector::SqlSampler.new
|
37
|
-
@middleware = TingYun::Agent::Collector::MiddleWareCollector.new(@events)
|
38
37
|
end
|
39
38
|
|
40
39
|
def container_for_endpoint(endpoint)
|
@@ -106,7 +105,7 @@ module TingYun
|
|
106
105
|
def harvest_from_container(container, endpoint)
|
107
106
|
items =[]
|
108
107
|
begin
|
109
|
-
if TingYun::Agent.config[:'
|
108
|
+
if TingYun::Agent.config[:'enabled']
|
110
109
|
items = container.harvest!
|
111
110
|
else
|
112
111
|
container.reset!
|
@@ -53,8 +53,13 @@ module TingYun
|
|
53
53
|
drop_buffered_data
|
54
54
|
@service.force_restart if @service
|
55
55
|
@connect_state = :pending
|
56
|
-
sleep 30
|
57
56
|
end
|
57
|
+
|
58
|
+
def handle_delay_restart(error, sec)
|
59
|
+
handle_force_restart(error)
|
60
|
+
sleep sec
|
61
|
+
end
|
62
|
+
|
58
63
|
def handle_force_disconnect(error)
|
59
64
|
TingYun::Agent.logger.warn "Ting Yun forced this agent to disconnect (#{error.message})"
|
60
65
|
disconnect
|
@@ -11,8 +11,11 @@ module TingYun
|
|
11
11
|
|
12
12
|
# Check to see if the agent should start, returning +true+ if it should.
|
13
13
|
# should hava the vaild app_name, unstart-state and able to start
|
14
|
+
# The agent is disabled when it is not force enabled by the
|
15
|
+
# 'nbs.agent_enabled' option (e.g. in a manual start), or
|
16
|
+
# enabled normally through the configuration file
|
14
17
|
def agent_should_start?
|
15
|
-
return false if already_started? ||
|
18
|
+
return false if already_started? || !TingYun::Agent.config[:'nbs.agent_enabled']
|
16
19
|
unless app_name_configured?
|
17
20
|
TingYun::Agent.logger.error "No application name configured.",
|
18
21
|
"The Agent cannot start without at least one. Please check your ",
|
@@ -36,96 +39,30 @@ module TingYun
|
|
36
39
|
end
|
37
40
|
end
|
38
41
|
|
39
|
-
# The agent is disabled when it is not force enabled by the
|
40
|
-
# 'nbs.agent_enabled' option (e.g. in a manual start), or
|
41
|
-
# enabled normally through the configuration file
|
42
|
-
def disabled?
|
43
|
-
!TingYun::Agent.config[:'nbs.agent_enabled']
|
44
|
-
end
|
45
42
|
|
46
43
|
def log_startup
|
47
|
-
log_environment
|
48
|
-
log_dispatcher
|
49
|
-
log_app_name
|
50
|
-
end
|
51
|
-
|
52
|
-
def log_environment
|
53
|
-
Agent.logger.info "Environment: #{::TingYun::Frameworks.framework.env}"
|
54
|
-
end
|
55
|
-
|
56
|
-
# Logs the dispatcher to the log file to assist with
|
57
|
-
# debugging. When no debugger is present, logs this fact to
|
58
|
-
# assist with proper dispatcher detection
|
59
|
-
def log_dispatcher
|
44
|
+
Agent.logger.info "Environment: #{::TingYun::Frameworks.framework.env}" # log_environment
|
60
45
|
dispatcher_name = TingYun::Agent.config[:dispatcher].to_s
|
61
|
-
|
62
46
|
if dispatcher_name.empty?
|
63
47
|
TingYun::Agent.logger.info 'No known dispatcher detected.'
|
64
48
|
else
|
65
49
|
TingYun::Agent.logger.info "Dispatcher: #{dispatcher_name}"
|
66
|
-
end
|
67
|
-
|
68
|
-
|
69
|
-
def log_app_name
|
70
|
-
TingYun::Agent.logger.info "Application: #{TingYun::Agent.config.app_names.join(", ")}"
|
71
|
-
end
|
72
|
-
|
73
|
-
def sinatra_app?
|
74
|
-
(
|
75
|
-
defined?(Sinatra::Application) &&
|
76
|
-
Sinatra::Application.respond_to?(:run) &&
|
77
|
-
Sinatra::Application.run?
|
78
|
-
)
|
79
|
-
end
|
80
|
-
|
81
|
-
# Classy logging of the agent version and the current pid,
|
82
|
-
# so we can disambiguate processes in the log file and make
|
83
|
-
# sure they're running a reasonable version
|
84
|
-
def log_version_and_pid
|
85
|
-
TingYun::Agent.logger.debug "Ting Yun Ruby Agent #{TingYun::VERSION::STRING} Initialized: pid = #{$$}"
|
50
|
+
end # log_dispatcher
|
51
|
+
TingYun::Agent.logger.info "Application: #{TingYun::Agent.config.app_names.join(", ")}" # log_app_name
|
86
52
|
end
|
87
53
|
|
88
|
-
# Warn the user if they have configured their agent not to
|
89
|
-
# send data, that way we can see this clearly in the log file
|
90
|
-
def monitoring?
|
91
|
-
if TingYun::Agent.config[:monitor_mode]
|
92
|
-
true
|
93
|
-
else
|
94
|
-
TingYun::Agent.logger.warn('Agent configured not to send data in this environment.')
|
95
|
-
false
|
96
|
-
end
|
97
|
-
end
|
98
54
|
|
99
|
-
#
|
100
|
-
|
101
|
-
def has_license_key?
|
55
|
+
# A correct license key exists and is of the proper length
|
56
|
+
def has_correct_license_key?
|
102
57
|
if TingYun::Agent.config[:license_key] && TingYun::Agent.config[:license_key].length > 0
|
103
58
|
true
|
104
59
|
else
|
105
60
|
TingYun::Agent.logger.warn("No license key found. " +
|
106
|
-
|
61
|
+
"This often means your tingyun.yml file was not found, or it lacks a section for the running environment,'#{::TingYun::Frameworks.framework.env}'. You may also want to try linting your tingyun.yml to ensure it is valid YML.")
|
107
62
|
false
|
108
63
|
end
|
109
64
|
end
|
110
65
|
|
111
|
-
# A license key is an arbitrary 40 character string,
|
112
|
-
# usually looks something like a SHA1 hash
|
113
|
-
def correct_license_length
|
114
|
-
key = TingYun::Agent.config[:license_key]
|
115
|
-
|
116
|
-
if key.length > 0
|
117
|
-
true
|
118
|
-
else
|
119
|
-
TingYun::Agent.logger.error("Invalid license key: #{key}")
|
120
|
-
false
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
# A correct license key exists and is of the proper length
|
125
|
-
def has_correct_license_key?
|
126
|
-
has_license_key? && correct_license_length
|
127
|
-
end
|
128
|
-
|
129
66
|
# Logs the configured application names
|
130
67
|
def app_name_configured?
|
131
68
|
names = TingYun::Agent.config.app_names
|
@@ -149,7 +86,7 @@ module TingYun
|
|
149
86
|
# setting up the worker thread and the exit handler to shut
|
150
87
|
# down the agent
|
151
88
|
def check_config_and_start_agent
|
152
|
-
return unless
|
89
|
+
return unless has_correct_license_key?
|
153
90
|
return if is_using_forking_dispatcher?
|
154
91
|
setup_and_start_agent
|
155
92
|
end
|
@@ -163,7 +100,7 @@ module TingYun
|
|
163
100
|
@dispatcher.mark_started
|
164
101
|
generate_environment_report
|
165
102
|
install_exit_handler
|
166
|
-
|
103
|
+
@middleware.load_samplers # cpu and memory load
|
167
104
|
|
168
105
|
if TingYun::Agent.config[:sync_startup]
|
169
106
|
connect_in_sync
|
@@ -199,9 +136,7 @@ module TingYun
|
|
199
136
|
end
|
200
137
|
|
201
138
|
return if !needs_restart ||
|
202
|
-
!Agent.config[:'nbs.agent_enabled'] ||
|
203
|
-
!Agent.config[:monitor_mode] ||
|
204
|
-
disconnected?
|
139
|
+
!Agent.config[:'nbs.agent_enabled'] || disconnected?
|
205
140
|
|
206
141
|
::TingYun::Agent.logger.debug "Starting the worker thread in #{Process.pid} (parent #{Process.ppid}) after forking."
|
207
142
|
|
@@ -212,9 +147,6 @@ module TingYun
|
|
212
147
|
setup_and_start_agent(options)
|
213
148
|
end
|
214
149
|
|
215
|
-
def cpu_and_memory
|
216
|
-
@middleware.load_samplers
|
217
|
-
end
|
218
150
|
|
219
151
|
end
|
220
152
|
end
|
@@ -6,14 +6,24 @@ require 'ting_yun/agent/method_tracer_helpers'
|
|
6
6
|
require 'ting_yun/agent/transaction/transaction_metrics'
|
7
7
|
require 'ting_yun/agent/transaction/request_attributes'
|
8
8
|
require 'ting_yun/agent/transaction/attributes'
|
9
|
+
require 'ting_yun/agent/transaction/exceptions'
|
10
|
+
require 'ting_yun/agent/transaction/apdex'
|
11
|
+
require 'ting_yun/agent/transaction/class_method'
|
12
|
+
require 'ting_yun/agent/transaction/instance_method'
|
9
13
|
|
10
14
|
|
11
15
|
module TingYun
|
12
16
|
module Agent
|
17
|
+
# web transaction
|
13
18
|
class Transaction
|
14
19
|
|
20
|
+
include TingYun::Agent::Transaction::InstanceMethod
|
21
|
+
|
22
|
+
extend TingYun::Agent::Transaction::ClassMethod
|
23
|
+
|
24
|
+
|
25
|
+
|
15
26
|
|
16
|
-
APDEX_TXN_METRIC_PREFIX = 'Apdex/'.freeze
|
17
27
|
SUBTRANSACTION_PREFIX = 'Nested/'.freeze
|
18
28
|
CONTROLLER_PREFIX = 'WebAction/'.freeze
|
19
29
|
RAKE_TRANSACTION_PREFIX = 'BackgroundAction/Rake'.freeze
|
@@ -23,7 +33,7 @@ module TingYun
|
|
23
33
|
MIDDLEWARE_PREFIX = 'Middleware/Rack/'.freeze
|
24
34
|
GRAPE_PREFIX = 'Grape/'.freeze
|
25
35
|
RAKE_PREFIX = 'Rake'.freeze
|
26
|
-
|
36
|
+
|
27
37
|
EMPTY_SUMMARY_METRICS = [].freeze
|
28
38
|
MIDDLEWARE_SUMMARY_METRICS = ['Middleware/all'.freeze].freeze
|
29
39
|
|
@@ -32,43 +42,40 @@ module TingYun
|
|
32
42
|
NESTED_TRACE_STOP_OPTIONS = {:metric => true}.freeze
|
33
43
|
|
34
44
|
|
35
|
-
# A Time instance for the start time, never nil
|
36
|
-
attr_accessor :start_time
|
37
|
-
|
38
45
|
|
39
46
|
# A Time instance used for calculating the apdex score, which
|
40
47
|
# might end up being @start, or it might be further upstream if
|
41
48
|
# we can find a request header for the queue entry time
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
49
|
+
|
50
|
+
|
51
|
+
attr_reader :apdex,
|
52
|
+
:exceptions,
|
53
|
+
:metrics,
|
54
|
+
:attributes,
|
55
|
+
:request_attributes,
|
56
|
+
:frame_stack,
|
57
|
+
:guid,
|
58
|
+
:category,
|
59
|
+
:default_name,
|
60
|
+
:start_time
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
def initialize(category, client_transaction_id, options)
|
65
|
+
@start_time = Time.now
|
66
|
+
|
67
|
+
@exceptions = TingYun::Agent::Transaction::Exceptions.new
|
68
|
+
@metrics = TingYun::Agent::TransactionMetrics.new
|
69
|
+
@attributes = TingYun::Agent::Transaction::Attributes.new
|
70
|
+
@apdex = TingYun::Agent::Transaction::Apdex.new(options[:apdex_start_time], @start_time)
|
71
|
+
|
58
72
|
@has_children = false
|
59
73
|
@category = category
|
60
|
-
|
61
|
-
@
|
62
|
-
@apdex_start = options[:apdex_start_time] || @start_time
|
74
|
+
|
75
|
+
@guid = client_transaction_id || generate_guid
|
63
76
|
@frame_stack = []
|
64
77
|
@frozen_name = nil
|
65
78
|
@default_name = TingYun::Helper.correctly_encoded(options[:transaction_name])
|
66
|
-
@metrics = TingYun::Agent::TransactionMetrics.new
|
67
|
-
|
68
|
-
@error_recorded = false
|
69
|
-
|
70
|
-
@attributes = TingYun::Agent::Transaction::Attributes.new
|
71
|
-
|
72
79
|
|
73
80
|
if request = options[:request]
|
74
81
|
@request_attributes = TingYun::Agent::Transaction::RequestAttributes.new request
|
@@ -77,7 +84,6 @@ module TingYun
|
|
77
84
|
end
|
78
85
|
end
|
79
86
|
|
80
|
-
|
81
87
|
def request_path
|
82
88
|
@request_attributes && @request_attributes.request_path
|
83
89
|
end
|
@@ -86,116 +92,20 @@ module TingYun
|
|
86
92
|
@request_attributes && @request_attributes.port
|
87
93
|
end
|
88
94
|
|
89
|
-
def self.wrap(state, name, category, options = {})
|
90
|
-
Transaction.start(state, category, options.merge(:transaction_name => name))
|
91
|
-
|
92
|
-
begin
|
93
|
-
# We shouldn't raise from Transaction.start, but only wrap the yield
|
94
|
-
# to be absolutely sure we don't report agent problems as app errors
|
95
|
-
yield
|
96
|
-
rescue => e
|
97
|
-
Transaction.notice_error(e)
|
98
|
-
raise e
|
99
|
-
ensure
|
100
|
-
Transaction.stop(state)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
|
105
|
-
def self.start(state, category, options)
|
106
|
-
category ||= :controller
|
107
|
-
txn = state.current_transaction
|
108
|
-
options[:client_transaction_id] = state.client_transaction_id
|
109
|
-
if txn
|
110
|
-
txn.create_nested_frame(state, category, options)
|
111
|
-
else
|
112
|
-
txn = start_new_transaction(state, category, options)
|
113
|
-
end
|
114
|
-
|
115
|
-
# merge params every step into here
|
116
|
-
txn.attributes.merge_request_parameters(options[:filtered_params])
|
117
|
-
|
118
|
-
txn
|
119
|
-
rescue => e
|
120
|
-
TingYun::Agent.logger.error("Exception during Transaction.start", e)
|
121
|
-
end
|
122
|
-
|
123
|
-
def self.start_new_transaction(state, category, options)
|
124
|
-
txn = Transaction.new(category, options)
|
125
|
-
state.reset(txn)
|
126
|
-
txn.start(state)
|
127
|
-
txn
|
128
|
-
end
|
129
95
|
|
130
96
|
def start(state)
|
131
97
|
return if !state.execution_traced?
|
98
|
+
::TingYun::Agent.instance.events.notify(:start_transaction) # Dispatcher调用
|
99
|
+
|
100
|
+
::TingYun::Agent::Collector::TransactionSampler.on_start_transaction(state, start_time)
|
101
|
+
::TingYun::Agent::Collector::SqlSampler.on_start_transaction(state, request_path)
|
132
102
|
|
133
|
-
transaction_sampler.on_start_transaction(state, start_time)
|
134
|
-
sql_sampler.on_start_transaction(state, request_path)
|
135
|
-
TingYun::Agent.instance.events.notify(:start_transaction)
|
136
103
|
frame_stack.push TingYun::Agent::MethodTracerHelpers.trace_execution_scoped_header(state, Time.now.to_f)
|
137
104
|
name_last_frame @default_name
|
138
105
|
freeze_name_and_execute if @default_name.start_with?(RAKE_TRANSACTION_PREFIX)
|
139
106
|
end
|
140
107
|
|
141
|
-
def create_nested_frame(state, category, options)
|
142
|
-
@has_children = true
|
143
|
-
frame_stack.push TingYun::Agent::MethodTracerHelpers.trace_execution_scoped_header(state, Time.now.to_f)
|
144
|
-
name_last_frame(options[:transaction_name])
|
145
108
|
|
146
|
-
set_default_transaction_name(options[:transaction_name], category)
|
147
|
-
end
|
148
|
-
|
149
|
-
|
150
|
-
def set_default_transaction_name(name, category)
|
151
|
-
return log_frozen_name(name) if name_frozen?
|
152
|
-
if influences_transaction_name?(category)
|
153
|
-
self.default_name = name
|
154
|
-
@category = category if category
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
|
159
|
-
def self.stop(state, end_time = Time.now)
|
160
|
-
|
161
|
-
txn = state.current_transaction
|
162
|
-
|
163
|
-
if txn.nil?
|
164
|
-
TingYun::Agent.logger.error("Failed during Transaction.stop because there is no current transaction")
|
165
|
-
return
|
166
|
-
end
|
167
|
-
|
168
|
-
nested_frame = txn.frame_stack.pop
|
169
|
-
|
170
|
-
if txn.frame_stack.empty?
|
171
|
-
txn.stop(state, end_time, nested_frame)
|
172
|
-
state.reset
|
173
|
-
else
|
174
|
-
nested_name = nested_transaction_name(nested_frame.name)
|
175
|
-
|
176
|
-
if nested_name.start_with?(MIDDLEWARE_PREFIX)
|
177
|
-
summary_metrics = MIDDLEWARE_SUMMARY_METRICS
|
178
|
-
else
|
179
|
-
summary_metrics = EMPTY_SUMMARY_METRICS
|
180
|
-
end
|
181
|
-
|
182
|
-
TingYun::Agent::MethodTracerHelpers.trace_execution_scoped_footer(
|
183
|
-
state,
|
184
|
-
nested_frame.start_time.to_f,
|
185
|
-
nested_name,
|
186
|
-
summary_metrics,
|
187
|
-
nested_frame,
|
188
|
-
NESTED_TRACE_STOP_OPTIONS,
|
189
|
-
end_time.to_f)
|
190
|
-
|
191
|
-
end
|
192
|
-
|
193
|
-
:transaction_stopped
|
194
|
-
rescue => e
|
195
|
-
state.reset
|
196
|
-
TingYun::Agent.logger.error("Exception during Transaction.stop", e)
|
197
|
-
nil
|
198
|
-
end
|
199
109
|
|
200
110
|
|
201
111
|
def stop(state, end_time, outermost_frame)
|
@@ -210,7 +120,7 @@ module TingYun
|
|
210
120
|
trace_options = TRACE_OPTIONS_UNSCOPED
|
211
121
|
end
|
212
122
|
|
213
|
-
if
|
123
|
+
if name.start_with?(MIDDLEWARE_PREFIX)
|
214
124
|
summary_metrics_with_exclusive_time = MIDDLEWARE_SUMMARY_METRICS
|
215
125
|
else
|
216
126
|
summary_metrics_with_exclusive_time = EMPTY_SUMMARY_METRICS
|
@@ -226,280 +136,27 @@ module TingYun
|
|
226
136
|
trace_options,
|
227
137
|
end_time.to_f)
|
228
138
|
|
229
|
-
commit
|
139
|
+
commit(state, end_time, name) unless ignore(best_name)
|
230
140
|
end
|
231
141
|
|
232
|
-
def self.nested_transaction_name(name)
|
233
|
-
if name.start_with?(CONTROLLER_PREFIX) || name.start_with?(RAKE_TRANSACTION_PREFIX)
|
234
|
-
"#{SUBTRANSACTION_PREFIX}#{name}"
|
235
|
-
else
|
236
|
-
name
|
237
|
-
end
|
238
|
-
end
|
239
142
|
|
240
|
-
def commit
|
143
|
+
def commit(state, end_time, outermost_node_name)
|
241
144
|
|
242
145
|
assign_agent_attributes
|
243
146
|
|
244
147
|
|
245
|
-
transaction_sampler.on_finishing_transaction(state, self, end_time)
|
148
|
+
TingYun::Agent.instance.transaction_sampler.on_finishing_transaction(state, self, end_time)
|
246
149
|
|
247
|
-
sql_sampler.on_finishing_transaction(state, @frozen_name)
|
150
|
+
TingYun::Agent.instance.sql_sampler.on_finishing_transaction(state, @frozen_name)
|
248
151
|
|
249
152
|
record_summary_metrics(outermost_node_name, end_time)
|
250
|
-
record_apdex(
|
251
|
-
record_exceptions
|
252
|
-
merge_metrics
|
253
|
-
end
|
254
|
-
|
255
|
-
|
256
|
-
def record_summary_metrics(outermost_node_name,end_time)
|
257
|
-
unless @frozen_name == outermost_node_name
|
258
|
-
@metrics.record_unscoped(@frozen_name, TingYun::Helper.time_to_millis(end_time.to_f - start_time.to_f))
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
def assign_agent_attributes
|
263
|
-
|
264
|
-
add_agent_attribute(:threadName, "pid-#{$$}");
|
265
|
-
|
266
|
-
if http_response_code
|
267
|
-
add_agent_attribute(:httpStatus, http_response_code.to_s)
|
268
|
-
end
|
269
|
-
|
270
|
-
if response_content_type
|
271
|
-
add_agent_attribute(:contentType, response_content_type)
|
272
|
-
end
|
273
|
-
|
274
|
-
|
275
|
-
if @request_attributes
|
276
|
-
@request_attributes.assign_agent_attributes self
|
277
|
-
end
|
278
|
-
|
279
|
-
end
|
280
|
-
|
281
|
-
def add_agent_attribute(key, value)
|
282
|
-
@attributes.add_agent_attribute(key, value)
|
283
|
-
end
|
284
|
-
|
285
|
-
#collector error
|
286
|
-
def had_error?
|
287
|
-
if @exceptions.empty?
|
288
|
-
return false
|
289
|
-
else
|
290
|
-
return true
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
def record_exceptions
|
295
|
-
unless @exceptions.empty?
|
296
|
-
@exceptions.each do |exception, options|
|
297
|
-
|
298
|
-
options[:uri] ||= request_path if request_path
|
299
|
-
options[:port] = request_port if request_port
|
300
|
-
options[:metric_name] = best_name
|
301
|
-
options[:attributes] = @attributes
|
302
|
-
|
303
|
-
@error_recorded = !!::TingYun::Agent.instance.error_collector.notice_error(exception, options) || @error_recorded
|
304
|
-
end
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
|
-
def record_apdex(state, end_time=Time.now)
|
309
|
-
total_duration = (end_time - apdex_start)*1000
|
310
|
-
if recording_web_transaction?
|
311
|
-
record_apdex_metrics(APDEX_TXN_METRIC_PREFIX, total_duration, apdex_t)
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
|
316
|
-
def record_apdex_metrics(transaction_prefix, total_duration, current_apdex_t)
|
317
|
-
return unless current_apdex_t
|
318
|
-
return unless @frozen_name.start_with?(CONTROLLER_PREFIX)
|
319
|
-
|
320
|
-
apdex_bucket_global = apdex_bucket(total_duration, current_apdex_t)
|
321
|
-
txn_apdex_metric = @frozen_name.sub(/^[^\/]+\//, transaction_prefix)
|
322
|
-
@metrics.record_unscoped(txn_apdex_metric, apdex_bucket_global, current_apdex_t)
|
323
|
-
end
|
324
|
-
|
325
|
-
|
326
|
-
def apdex_bucket(duration, current_apdex_t)
|
327
|
-
self.class.apdex_bucket(duration, had_error?, current_apdex_t)
|
328
|
-
end
|
329
|
-
|
330
|
-
def self.apdex_bucket(duration, failed, apdex_t)
|
331
|
-
case
|
332
|
-
when failed
|
333
|
-
:apdex_f
|
334
|
-
when duration <= apdex_t
|
335
|
-
:apdex_s
|
336
|
-
when duration <= 4 * apdex_t
|
337
|
-
:apdex_t
|
338
|
-
else
|
339
|
-
:apdex_f
|
340
|
-
end
|
341
|
-
end
|
342
|
-
|
343
|
-
def apdex_t
|
344
|
-
TingYun::Agent.config[:apdex_t]
|
345
|
-
end
|
346
|
-
|
347
|
-
|
348
|
-
# See TingYun::Agent.notice_error for options and commentary
|
349
|
-
def self.notice_error(e, options={})
|
350
|
-
state = TingYun::Agent::TransactionState.tl_get
|
351
|
-
txn = state.current_transaction
|
352
|
-
if txn
|
353
|
-
txn.notice_error(e, options)
|
354
|
-
elsif TingYun::Agent.instance
|
355
|
-
TingYun::Agent.instance.error_collector.notice_error(e, options)
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
# Do not call this. Invoke the class method instead.
|
360
|
-
def notice_error(error, options={}) # :nodoc:
|
361
|
-
if @exceptions[error]
|
362
|
-
@exceptions[error].merge! options
|
363
|
-
else
|
364
|
-
@exceptions[error] = options
|
365
|
-
end
|
366
|
-
end
|
367
|
-
|
153
|
+
@apdex.record_apdex(@frozen_name, end_time, @exceptions.had_error?)
|
154
|
+
@exceptions.record_exceptions(@attributes)
|
368
155
|
|
369
|
-
# This transaction-local hash may be used as temprory storage by
|
370
|
-
# instrumentation that needs to pass data from one instrumentation point
|
371
|
-
# to another.
|
372
|
-
#
|
373
|
-
# For example, if both A and B are instrumented, and A calls B
|
374
|
-
# but some piece of state needed by the instrumentation at B is only
|
375
|
-
# available at A, the instrumentation at A may write into the hash, call
|
376
|
-
# through, and then remove the key afterwards, allowing the
|
377
|
-
# instrumentation at B to read the value in between.
|
378
|
-
#
|
379
|
-
# Keys should be symbols, and care should be taken to not generate key
|
380
|
-
# names dynamically, and to ensure that keys are removed upon return from
|
381
|
-
# the method that creates them.
|
382
|
-
#
|
383
|
-
def instrumentation_state
|
384
|
-
@instrumentation_state ||= {}
|
385
|
-
end
|
386
|
-
|
387
|
-
def with_database_metric_name(model, method, product=nil)
|
388
|
-
previous = self.instrumentation_state[:datastore_override]
|
389
|
-
model_name = case model
|
390
|
-
when Class
|
391
|
-
model.name
|
392
|
-
when String
|
393
|
-
model
|
394
|
-
else
|
395
|
-
model.to_s
|
396
|
-
end
|
397
|
-
self.instrumentation_state[:datastore_override] = [method, model_name, product]
|
398
|
-
yield
|
399
|
-
ensure
|
400
|
-
self.instrumentation_state[:datastore_override] = previous
|
401
|
-
end
|
402
|
-
|
403
|
-
def freeze_name_and_execute
|
404
|
-
if !name_frozen?
|
405
|
-
@name_frozen = true
|
406
|
-
@frozen_name = best_name
|
407
|
-
end
|
408
156
|
|
409
|
-
yield if block_given?
|
410
|
-
end
|
411
|
-
|
412
|
-
def promoted_transaction_name(name)
|
413
|
-
if name.start_with?(MIDDLEWARE_PREFIX)
|
414
|
-
"#{CONTROLLER_PREFIX}#{name}"
|
415
|
-
else
|
416
|
-
name
|
417
|
-
end
|
418
|
-
end
|
419
|
-
|
420
|
-
def merge_metrics
|
421
157
|
TingYun::Agent.instance.stats_engine.merge_transaction_metrics!(@metrics, best_name)
|
422
158
|
end
|
423
159
|
|
424
|
-
def name_last_frame(name)
|
425
|
-
frame_stack.last.name = name
|
426
|
-
end
|
427
|
-
|
428
|
-
def name_frozen?
|
429
|
-
@frozen_name ? true : false
|
430
|
-
end
|
431
|
-
|
432
|
-
def log_frozen_name(name)
|
433
|
-
TingYun::Agent.logger.warn("Attempted to rename transaction to '#{name}' after transaction name was already frozen as '#{@frozen_name}'.")
|
434
|
-
nil
|
435
|
-
end
|
436
|
-
|
437
|
-
def influences_transaction_name?(category)
|
438
|
-
!category || frame_stack.size == 1 || similar_category?(category)
|
439
|
-
end
|
440
|
-
|
441
|
-
def web_category?(category)
|
442
|
-
WEB_TRANSACTION_CATEGORIES.include?(category)
|
443
|
-
end
|
444
|
-
|
445
|
-
def similar_category?(category)
|
446
|
-
web_category?(@category) == web_category?(category)
|
447
|
-
end
|
448
|
-
|
449
|
-
def recording_web_transaction?
|
450
|
-
web_category?(@category)
|
451
|
-
end
|
452
|
-
|
453
|
-
def self.recording_web_transaction? #THREAD_LOCAL_ACCESS
|
454
|
-
txn = tl_current
|
455
|
-
txn && txn.recording_web_transaction?
|
456
|
-
end
|
457
|
-
|
458
|
-
def self.tl_current
|
459
|
-
TingYun::Agent::TransactionState.tl_get.current_transaction
|
460
|
-
end
|
461
|
-
|
462
|
-
def needs_middleware_summary_metrics?(name)
|
463
|
-
name.start_with?(MIDDLEWARE_PREFIX)
|
464
|
-
end
|
465
|
-
|
466
|
-
alias_method :ignore, :needs_middleware_summary_metrics?
|
467
|
-
|
468
|
-
def best_name
|
469
|
-
@frozen_name || @default_name || ::TingYun::Agent::UNKNOWN_METRIC
|
470
|
-
end
|
471
|
-
|
472
|
-
def queue_time
|
473
|
-
@apdex_start ? @start_time - @apdex_start : 0
|
474
|
-
end
|
475
|
-
|
476
|
-
|
477
|
-
def agent
|
478
|
-
TingYun::Agent.instance
|
479
|
-
end
|
480
|
-
|
481
|
-
def sql_sampler
|
482
|
-
agent.sql_sampler
|
483
|
-
end
|
484
|
-
|
485
|
-
|
486
|
-
def transaction_sampler
|
487
|
-
TingYun::Agent.instance.transaction_sampler
|
488
|
-
end
|
489
|
-
|
490
|
-
HEX_DIGITS = (0..15).map{|i| i.to_s(16)}
|
491
|
-
GUID_LENGTH = 16
|
492
|
-
|
493
|
-
# generate a random 64 bit uuid
|
494
|
-
private
|
495
|
-
def generate_guid
|
496
|
-
guid = ''
|
497
|
-
GUID_LENGTH.times do
|
498
|
-
guid << HEX_DIGITS[rand(16)]
|
499
|
-
end
|
500
|
-
guid
|
501
|
-
end
|
502
|
-
|
503
160
|
end
|
504
161
|
end
|
505
162
|
end
|