tingyun_rpm 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +14 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +3 -0
- data/Guardfile +25 -0
- data/LICENSE.txt +22 -0
- data/README.md +41 -0
- data/cert/cacert.pem +0 -0
- data/lib/ting_yun/agent/agent.rb +128 -0
- data/lib/ting_yun/agent/class_methods.rb +21 -0
- data/lib/ting_yun/agent/collector/base_sampler.rb +2 -0
- data/lib/ting_yun/agent/collector/error_collector/error_trace_array.rb +88 -0
- data/lib/ting_yun/agent/collector/error_collector/noticed_error.rb +129 -0
- data/lib/ting_yun/agent/collector/error_collector.rb +165 -0
- data/lib/ting_yun/agent/collector/middle_ware_collector/cpu_sampler.rb +68 -0
- data/lib/ting_yun/agent/collector/middle_ware_collector/memory_sampler.rb +139 -0
- data/lib/ting_yun/agent/collector/middle_ware_collector/middle_ware.rb +13 -0
- data/lib/ting_yun/agent/collector/middle_ware_collector/sampler.rb +59 -0
- data/lib/ting_yun/agent/collector/middle_ware_collector.rb +80 -0
- data/lib/ting_yun/agent/collector/sql_sampler.rb +299 -0
- data/lib/ting_yun/agent/collector/stats_engine/metric_stats.rb +170 -0
- data/lib/ting_yun/agent/collector/stats_engine/stats_hash.rb +172 -0
- data/lib/ting_yun/agent/collector/stats_engine.rb +28 -0
- data/lib/ting_yun/agent/collector/transaction_sampler/slowest_sample_buffer.rb +25 -0
- data/lib/ting_yun/agent/collector/transaction_sampler/transaction_sample_buffer_base.rb +96 -0
- data/lib/ting_yun/agent/collector/transaction_sampler.rb +226 -0
- data/lib/ting_yun/agent/container_data_manager.rb +94 -0
- data/lib/ting_yun/agent/cross_app/cross_app_monitor.rb +131 -0
- data/lib/ting_yun/agent/cross_app/cross_app_tracing.rb +202 -0
- data/lib/ting_yun/agent/cross_app/inbound_request_monitor.rb +22 -0
- data/lib/ting_yun/agent/database.rb +410 -0
- data/lib/ting_yun/agent/datastore/metric_helper.rb +82 -0
- data/lib/ting_yun/agent/datastore/mongo.rb +44 -0
- data/lib/ting_yun/agent/datastore.rb +33 -0
- data/lib/ting_yun/agent/dispatcher.rb +39 -0
- data/lib/ting_yun/agent/event/event_listener.rb +47 -0
- data/lib/ting_yun/agent/event/event_loop.rb +194 -0
- data/lib/ting_yun/agent/instance_methods/connect.rb +164 -0
- data/lib/ting_yun/agent/instance_methods/container_data_manager.rb +137 -0
- data/lib/ting_yun/agent/instance_methods/handle_errors.rb +71 -0
- data/lib/ting_yun/agent/instance_methods/start.rb +219 -0
- data/lib/ting_yun/agent/instance_methods/start_worker_thread.rb +51 -0
- data/lib/ting_yun/agent/instance_methods.rb +39 -0
- data/lib/ting_yun/agent/method_tracer.rb +256 -0
- data/lib/ting_yun/agent/method_tracer_helpers.rb +85 -0
- data/lib/ting_yun/agent/threading/agent_thread.rb +49 -0
- data/lib/ting_yun/agent/transaction/attributes.rb +22 -0
- data/lib/ting_yun/agent/transaction/request_attributes.rb +126 -0
- data/lib/ting_yun/agent/transaction/trace.rb +125 -0
- data/lib/ting_yun/agent/transaction/trace_node.rb +110 -0
- data/lib/ting_yun/agent/transaction/traced_method_stack.rb +80 -0
- data/lib/ting_yun/agent/transaction/transaction_metrics.rb +51 -0
- data/lib/ting_yun/agent/transaction/transaction_sample_builder.rb +63 -0
- data/lib/ting_yun/agent/transaction/transaction_state.rb +112 -0
- data/lib/ting_yun/agent/transaction.rb +522 -0
- data/lib/ting_yun/agent.rb +207 -0
- data/lib/ting_yun/configuration/default_source.rb +638 -0
- data/lib/ting_yun/configuration/dotted_hash.rb +46 -0
- data/lib/ting_yun/configuration/environment_source.rb +116 -0
- data/lib/ting_yun/configuration/manager.rb +232 -0
- data/lib/ting_yun/configuration/manual_source.rb +14 -0
- data/lib/ting_yun/configuration/server_source.rb +88 -0
- data/lib/ting_yun/configuration/yaml_source.rb +136 -0
- data/lib/ting_yun/configuration.rb +9 -0
- data/lib/ting_yun/environment_report.rb +123 -0
- data/lib/ting_yun/frameworks/class_methods.rb +47 -0
- data/lib/ting_yun/frameworks/external.rb +15 -0
- data/lib/ting_yun/frameworks/instance_methods.rb +120 -0
- data/lib/ting_yun/frameworks/instrumentation.rb +67 -0
- data/lib/ting_yun/frameworks/rails.rb +63 -0
- data/lib/ting_yun/frameworks/rails3.rb +26 -0
- data/lib/ting_yun/frameworks/rails4.rb +14 -0
- data/lib/ting_yun/frameworks/ruby.rb +17 -0
- data/lib/ting_yun/frameworks/sinatra.rb +10 -0
- data/lib/ting_yun/frameworks.rb +34 -0
- data/lib/ting_yun/http/generic_request.rb +8 -0
- data/lib/ting_yun/http/net_http_request.rb +46 -0
- data/lib/ting_yun/instrumentation/active_record.rb +103 -0
- data/lib/ting_yun/instrumentation/middleware_proxy.rb +77 -0
- data/lib/ting_yun/instrumentation/middleware_tracing.rb +84 -0
- data/lib/ting_yun/instrumentation/mongo.rb +103 -0
- data/lib/ting_yun/instrumentation/mongo2.rb +37 -0
- data/lib/ting_yun/instrumentation/mongo_command_log_subscriber.rb +97 -0
- data/lib/ting_yun/instrumentation/moped.rb +95 -0
- data/lib/ting_yun/instrumentation/net.rb +59 -0
- data/lib/ting_yun/instrumentation/rack.rb +109 -0
- data/lib/ting_yun/instrumentation/rails3/action_controller.rb +63 -0
- data/lib/ting_yun/instrumentation/rails3/action_view.rb +115 -0
- data/lib/ting_yun/instrumentation/rails4/action_controller_subscriber.rb +124 -0
- data/lib/ting_yun/instrumentation/rails4/action_view_subscriber.rb +118 -0
- data/lib/ting_yun/instrumentation/rails4/active_record_subscriber.rb +124 -0
- data/lib/ting_yun/instrumentation/rails_middleware.rb +38 -0
- data/lib/ting_yun/instrumentation/redis.rb +70 -0
- data/lib/ting_yun/instrumentation/support/active_record_helper.rb +178 -0
- data/lib/ting_yun/instrumentation/support/controller_instrumentation.rb +54 -0
- data/lib/ting_yun/instrumentation/support/database.rb +38 -0
- data/lib/ting_yun/instrumentation/support/event_formatter.rb +19 -0
- data/lib/ting_yun/instrumentation/support/evented_subscriber.rb +97 -0
- data/lib/ting_yun/instrumentation/support/external_error.rb +52 -0
- data/lib/ting_yun/instrumentation/support/metric_translator.rb +84 -0
- data/lib/ting_yun/instrumentation/support/mongo_formatter.rb +49 -0
- data/lib/ting_yun/instrumentation/support/parameter_filtering.rb +21 -0
- data/lib/ting_yun/instrumentation/support/queue_time.rb +76 -0
- data/lib/ting_yun/instrumentation/support/transaction_namer.rb +68 -0
- data/lib/ting_yun/instrumentation/thrift.rb +329 -0
- data/lib/ting_yun/logger/agent_logger.rb +196 -0
- data/lib/ting_yun/logger/log_once.rb +38 -0
- data/lib/ting_yun/logger/memory_logger.rb +56 -0
- data/lib/ting_yun/logger/null_logger.rb +31 -0
- data/lib/ting_yun/logger/startup_logger.rb +13 -0
- data/lib/ting_yun/logger.rb +8 -0
- data/lib/ting_yun/metrics/metric_data.rb +86 -0
- data/lib/ting_yun/metrics/metric_spec.rb +89 -0
- data/lib/ting_yun/metrics/stats.rb +158 -0
- data/lib/ting_yun/metrics.rb +12 -0
- data/lib/ting_yun/support/coerce.rb +86 -0
- data/lib/ting_yun/support/collector.rb +29 -0
- data/lib/ting_yun/support/exception.rb +79 -0
- data/lib/ting_yun/support/hash_extensions.rb +25 -0
- data/lib/ting_yun/support/helper.rb +54 -0
- data/lib/ting_yun/support/hostname.rb +13 -0
- data/lib/ting_yun/support/http_clients/uri_util.rb +49 -0
- data/lib/ting_yun/support/language_support.rb +155 -0
- data/lib/ting_yun/support/library_detection.rb +129 -0
- data/lib/ting_yun/support/local_environment.rb +185 -0
- data/lib/ting_yun/support/path.rb +13 -0
- data/lib/ting_yun/support/serialize/encodes.rb +61 -0
- data/lib/ting_yun/support/serialize/encoding_normalizer.rb +84 -0
- data/lib/ting_yun/support/serialize/json_marshaller.rb +73 -0
- data/lib/ting_yun/support/serialize/json_wrapper.rb +78 -0
- data/lib/ting_yun/support/serialize/marshaller.rb +69 -0
- data/lib/ting_yun/support/serialize/ok_json.rb +651 -0
- data/lib/ting_yun/support/system_info.rb +206 -0
- data/lib/ting_yun/support/timer_lib.rb +29 -0
- data/lib/ting_yun/support/version_number.rb +70 -0
- data/lib/ting_yun/ting_yun_service/connection.rb +118 -0
- data/lib/ting_yun/ting_yun_service/http.rb +41 -0
- data/lib/ting_yun/ting_yun_service/request.rb +90 -0
- data/lib/ting_yun/ting_yun_service/ssl.rb +45 -0
- data/lib/ting_yun/ting_yun_service/upload_service.rb +149 -0
- data/lib/ting_yun/ting_yun_service.rb +124 -0
- data/lib/ting_yun/version.rb +17 -0
- data/lib/tingyun_rpm.rb +47 -0
- data/tingyun_rpm.gemspec +60 -0
- metadata +415 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module TingYun
|
4
|
+
module Instrumentation
|
5
|
+
module Support
|
6
|
+
|
7
|
+
module QueueTime
|
8
|
+
unless defined?(REQUEST_START_HEADER)
|
9
|
+
REQUEST_START_HEADER = 'HTTP_X_REQUEST_START'.freeze
|
10
|
+
QUEUE_START_HEADER = 'HTTP_X_QUEUE_START'.freeze
|
11
|
+
MIDDLEWARE_START_HEADER = 'HTTP_X_MIDDLEWARE_START'.freeze
|
12
|
+
ALL_QUEUE_METRIC = 'WebFrontend/QueueTime'.freeze
|
13
|
+
# any timestamps before this are thrown out and the parser
|
14
|
+
# will try again with a larger unit (2000/1/1 UTC)
|
15
|
+
EARLIEST_ACCEPTABLE_TIME = Time.at(946684800)
|
16
|
+
|
17
|
+
CANDIDATE_HEADERS = [
|
18
|
+
REQUEST_START_HEADER,
|
19
|
+
QUEUE_START_HEADER,
|
20
|
+
MIDDLEWARE_START_HEADER
|
21
|
+
].freeze
|
22
|
+
|
23
|
+
DIVISORS = [1_000_000, 1_000, 1]
|
24
|
+
end
|
25
|
+
|
26
|
+
module_function
|
27
|
+
|
28
|
+
def parse_frontend_timestamp(headers, now=Time.now)
|
29
|
+
earliest = nil
|
30
|
+
|
31
|
+
CANDIDATE_HEADERS.each do |header|
|
32
|
+
if headers[header]
|
33
|
+
parsed = parse_timestamp(timestamp_string_from_header_value(headers[header]))
|
34
|
+
if parsed && (!earliest || parsed < earliest)
|
35
|
+
earliest = parsed
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
if earliest && earliest > now
|
41
|
+
TingYun::Agent.logger.debug("Negative queue time detected, treating as zero: start=#{earliest.to_f} > now=#{now.to_f}")
|
42
|
+
earliest = now
|
43
|
+
end
|
44
|
+
|
45
|
+
earliest
|
46
|
+
end
|
47
|
+
|
48
|
+
def timestamp_string_from_header_value(value)
|
49
|
+
case value
|
50
|
+
when /^\s*([\d+\.]+)\s*$/ then
|
51
|
+
$1
|
52
|
+
# following regexp intentionally unanchored to handle
|
53
|
+
# (ie ignore) leading server names
|
54
|
+
when /t=([\d+\.]+)/ then
|
55
|
+
$1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_timestamp(string)
|
60
|
+
DIVISORS.each do |divisor|
|
61
|
+
begin
|
62
|
+
t = Time.at(string.to_f / divisor)
|
63
|
+
return t if t > EARLIEST_ACCEPTABLE_TIME
|
64
|
+
rescue RangeError
|
65
|
+
# On Ruby versions built with a 32-bit time_t, attempting to
|
66
|
+
# instantiate a Time object in the far future raises a RangeError,
|
67
|
+
# in which case we know we've chosen the wrong divisor.
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module TingYun
|
4
|
+
module Instrumentation
|
5
|
+
module Support
|
6
|
+
class TransactionNamer
|
7
|
+
|
8
|
+
|
9
|
+
def self.prefix_for_category(txn, category = nil)
|
10
|
+
category ||= (txn && txn.category)
|
11
|
+
|
12
|
+
case category
|
13
|
+
when :controller then
|
14
|
+
::TingYun::Agent::Transaction::CONTROLLER_PREFIX
|
15
|
+
when :task then
|
16
|
+
::TingYun::Agent::Transaction::TASK_PREFIX
|
17
|
+
when :rack then
|
18
|
+
::TingYun::Agent::Transaction::RACK_PREFIX
|
19
|
+
when :uri then
|
20
|
+
::TingYun::Agent::Transaction::CONTROLLER_PREFIX
|
21
|
+
when :sinatra then
|
22
|
+
::TingYun::Agent::Transaction::SINATRA_PREFIX
|
23
|
+
when :middleware then
|
24
|
+
::TingYun::Agent::Transaction::MIDDLEWARE_PREFIX
|
25
|
+
when :grape then
|
26
|
+
::TingYun::Agent::Transaction::GRAPE_PREFIX
|
27
|
+
when :rake then
|
28
|
+
::TingYun::Agent::Transaction::RAKE_PREFIX
|
29
|
+
else
|
30
|
+
"#{category.to_s}/" # for internal use only
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def self.name_for(txn, traced_obj, category, options={})
|
36
|
+
"#{prefix_for_category(txn, category)}#{path_name(traced_obj, options)}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.path_name(traced_obj, options={})
|
40
|
+
return options[:path] if options[:path]
|
41
|
+
|
42
|
+
class_name = klass_name(traced_obj, options)
|
43
|
+
if options[:name]
|
44
|
+
if class_name
|
45
|
+
"#{class_name}/#{options[:name]}"
|
46
|
+
else
|
47
|
+
options[:name]
|
48
|
+
end
|
49
|
+
elsif traced_obj.respond_to?(:tingyun_metric_path)
|
50
|
+
traced_obj.tingyun_metric_path
|
51
|
+
else
|
52
|
+
class_name
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.klass_name(traced_obj, options={})
|
57
|
+
return options[:class_name] if options[:class_name]
|
58
|
+
|
59
|
+
if (traced_obj.is_a?(Class) || traced_obj.is_a?(Module))
|
60
|
+
traced_obj.name
|
61
|
+
else
|
62
|
+
traced_obj.class.name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,329 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'ting_yun/support/helper'
|
3
|
+
require 'ting_yun/agent'
|
4
|
+
|
5
|
+
module TingYun
|
6
|
+
module Instrumentation
|
7
|
+
module ThriftHelper
|
8
|
+
def operator result_klass
|
9
|
+
namespaces = result_klass.to_s.split('::')
|
10
|
+
operator_name = namespaces[0].downcase
|
11
|
+
if namespaces.last =~ /_result/
|
12
|
+
operator_name = "#{operator_name}.#{namespaces.last.sub('_result', '').downcase}"
|
13
|
+
elsif namespaces.last =~ /_args/
|
14
|
+
operator_name = "#{operator_name}.#{namespaces.last.sub('_args', '').downcase}"
|
15
|
+
end
|
16
|
+
|
17
|
+
operator_name
|
18
|
+
end
|
19
|
+
|
20
|
+
def operations
|
21
|
+
@operations ||= {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def started_time_and_node(operate)
|
25
|
+
_op_ = operations.delete(operate)
|
26
|
+
time = (_op_ && _op_[:started_time]) or Time.now.to_f
|
27
|
+
node = _op_ && _op_[:node]
|
28
|
+
[time, node]
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def tingyun_socket
|
33
|
+
@iprot.instance_variable_get("@trans").instance_variable_get("@transport")
|
34
|
+
end
|
35
|
+
|
36
|
+
def tingyun_host
|
37
|
+
@tingyun_host ||= tingyun_socket.instance_variable_get("@host") rescue nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def tingyun_port
|
41
|
+
@tingyun_port ||= tingyun_socket.instance_variable_get("@port") rescue nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def metrics operate
|
45
|
+
state = TingYun::Agent::TransactionState.tl_get
|
46
|
+
metrics = if tingyun_host.nil?
|
47
|
+
["External/thrift:%2F%2F#{operate}/#{operate}"]
|
48
|
+
else
|
49
|
+
["External/thrift:%2F%2F#{tingyun_host}:#{tingyun_port}%2F#{operate}/#{operate}"]
|
50
|
+
end
|
51
|
+
metrics << "External/NULL/ALL"
|
52
|
+
|
53
|
+
if TingYun::Agent::Transaction.recording_web_transaction?
|
54
|
+
metrics << "External/NULL/AllWeb"
|
55
|
+
else
|
56
|
+
metrics << "External/NULL/AllBackground"
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
my_data = state.thrift_return_data
|
61
|
+
|
62
|
+
|
63
|
+
if my_data
|
64
|
+
uri = "thrift:%2F%2F#{tingyun_host}:#{tingyun_port}%2F#{operate}/#{operate}"
|
65
|
+
metrics << "cross_app;#{my_data["id"]};#{my_data["action"]};#{uri}"
|
66
|
+
end
|
67
|
+
return metrics
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
TingYun::Support::LibraryDetection.defer do
|
78
|
+
named :thrift
|
79
|
+
|
80
|
+
depends_on do
|
81
|
+
defined?(::Thrift) && defined?(::Thrift::Client) && defined?(::Thrift::BaseProtocol)
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
executes do
|
86
|
+
TingYun::Agent.logger.info 'Installing Thrift Instrumentation'
|
87
|
+
require 'ting_yun/support/serialize/json_wrapper'
|
88
|
+
end
|
89
|
+
|
90
|
+
executes do
|
91
|
+
# ::Thrift::Processor.module_eval do
|
92
|
+
#
|
93
|
+
#
|
94
|
+
#
|
95
|
+
# def same_account?(state)
|
96
|
+
# server_info = TingYun::Agent.config[:tingyunIdSecret].split('|')
|
97
|
+
# client_info = (state.client_tingyun_id_secret || '').split('|')
|
98
|
+
# if !server_info[0].nil? && server_info[0] == client_info[0] && !server_info[0].empty?
|
99
|
+
# return true
|
100
|
+
# else
|
101
|
+
# return false
|
102
|
+
# end
|
103
|
+
# end
|
104
|
+
# def write_result_with_tingyun(result, oprot, name, seqid)
|
105
|
+
#
|
106
|
+
# state = TingYun::Agent::TransactionState.tl_get
|
107
|
+
# oprot.write_message_begin(name, ::Thrift::MessageTypes::REPLY, seqid)
|
108
|
+
#
|
109
|
+
# if state.execution_traced? && same_account?(state)
|
110
|
+
# class_name = "WebAction/thrift/#{self.class.to_s.split('::').first.downcase}.#{name}"
|
111
|
+
# state.current_transaction.default_name = class_name
|
112
|
+
# data = TingYun::Support::Serialize::JSONWrapper.dump("TingyunTxData" => build_payload(state))
|
113
|
+
# oprot.write_field_begin("TingyunField", 11, 6)
|
114
|
+
# oprot.write_string(data)
|
115
|
+
# oprot.write_field_end
|
116
|
+
# write_result_without_tingyun(result, oprot, name, seqid)
|
117
|
+
# state.current_transaction.add_agent_attribute(:httpStatus, 200)
|
118
|
+
# TingYun::Agent::Transaction.stop(state)
|
119
|
+
# else
|
120
|
+
# write_result_without_tingyun(result, oprot, name, seqid)
|
121
|
+
# end
|
122
|
+
# end
|
123
|
+
#
|
124
|
+
# def write_error_with_tingyun(err, oprot, name, seqid)
|
125
|
+
# p 'write_error'
|
126
|
+
# state = TingYun::Agent::TransactionState.tl_get
|
127
|
+
# oprot.write_message_begin(name, ::Thrift::MessageTypes::EXCEPTION, seqid)
|
128
|
+
#
|
129
|
+
# if state.execution_traced? && same_account?(state)
|
130
|
+
#
|
131
|
+
# class_name = "WebAction/thrift/#{self.class.to_s.split('::').first.downcase}.#{name}"
|
132
|
+
# state.current_transaction.default_name = class_name
|
133
|
+
# data = TingYun::Support::Serialize::JSONWrapper.dump("TingyunTxData" => build_payload(state))
|
134
|
+
# oprot.write_field_begin("TingyunField", 11, 6)
|
135
|
+
# oprot.write_string(data)
|
136
|
+
# oprot.write_field_end
|
137
|
+
# write_result_without_tingyun(err, oprot, name, seqid)
|
138
|
+
# p 'write_error end'
|
139
|
+
# state.current_transaction.add_agent_attribute(:httpStatus, 500)
|
140
|
+
#
|
141
|
+
# TingYun::Agent::Transaction.stop(state)
|
142
|
+
# else
|
143
|
+
# write_result_without_tingyun(err, oprot, name, seqid)
|
144
|
+
# end
|
145
|
+
# end
|
146
|
+
#
|
147
|
+
#
|
148
|
+
# def build_payload(state)
|
149
|
+
# state.web_duration = TingYun::Helper.time_to_millis(Time.now - state.current_transaction.start_time)
|
150
|
+
# payload = {
|
151
|
+
# :id => TingYun::Agent.config[:tingyunIdSecret].split('|')[1],
|
152
|
+
# :action => state.current_transaction.best_name,
|
153
|
+
# :trId => state.transaction_sample_builder.trace.guid,
|
154
|
+
# :time => {
|
155
|
+
# :duration => state.web_duration,
|
156
|
+
# :qu => state.queue_duration,
|
157
|
+
# :db => state.sql_duration,
|
158
|
+
# :ex => state.external_duration,
|
159
|
+
# :rds => state.rds_duration,
|
160
|
+
# :mc => state.mc_duration,
|
161
|
+
# :mon => state.mon_duration,
|
162
|
+
# :code => execute_duration(state)
|
163
|
+
# }
|
164
|
+
# }
|
165
|
+
# payload[:tr] = 1 if slow_action_tracer?(state)
|
166
|
+
# payload[:r] = state.client_req_id unless state.client_req_id.nil?
|
167
|
+
# payload
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# def slow_action_tracer?(state)
|
171
|
+
# if state.web_duration > TingYun::Agent.config[:'nbs.action_tracer.action_threshold']
|
172
|
+
# return true
|
173
|
+
# else
|
174
|
+
# return false
|
175
|
+
# end
|
176
|
+
# end
|
177
|
+
#
|
178
|
+
# def write_result_without_tingyun(result, oprot, name, seqid)
|
179
|
+
# result.write(oprot)
|
180
|
+
# oprot.write_message_end
|
181
|
+
# oprot.trans.flush
|
182
|
+
# end
|
183
|
+
#
|
184
|
+
# def execute_duration(state)
|
185
|
+
# state.web_duration - state.queue_duration - state.sql_duration - state.external_duration - state.rds_duration - state.mc_duration - state.mon_duration
|
186
|
+
# end
|
187
|
+
#
|
188
|
+
# alias :write_result :write_result_with_tingyun
|
189
|
+
# alias :write_error :write_error_with_tingyun
|
190
|
+
# # alias :write_result_without_tingyun :write_result
|
191
|
+
# end
|
192
|
+
|
193
|
+
::Thrift::BaseProtocol.class_eval do
|
194
|
+
|
195
|
+
def skip_with_tingyun(type)
|
196
|
+
|
197
|
+
data = skip_without_tingyun(type)
|
198
|
+
state = TingYun::Agent::TransactionState.tl_get
|
199
|
+
if data.is_a? ::String
|
200
|
+
if data.include?("TingyunTxData")
|
201
|
+
|
202
|
+
my_data = TingYun::Support::Serialize::JSONWrapper.load data.gsub("'",'"')
|
203
|
+
|
204
|
+
state.thrift_return_data = my_data["TingyunTxData"]
|
205
|
+
|
206
|
+
transaction_sampler = ::TingYun::Agent.instance.transaction_sampler
|
207
|
+
transaction_sampler.tl_builder.current_node[:txId] = state.request_guid
|
208
|
+
transaction_sampler.tl_builder.current_node[:txData] = my_data["TingyunTxData"]
|
209
|
+
# elsif data.include?("TingyunID")
|
210
|
+
# TingYun::Agent::Transaction.start(state, :thrift, :apdex_start_time => Time.now)
|
211
|
+
# my_data = TingYun::Support::Serialize::JSONWrapper.load data.gsub("'",'"')
|
212
|
+
# save_referring_transaction_info(state, my_data)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def save_referring_transaction_info(state,data)
|
218
|
+
|
219
|
+
info = data["TingyunID"].split(';')
|
220
|
+
tingyun_id_secret = info[0]
|
221
|
+
client_transaction_id = info.find do |e|
|
222
|
+
e.match(/x=/)
|
223
|
+
end.split('=')[1] rescue nil
|
224
|
+
client_req_id = info.find do |e|
|
225
|
+
e.match(/r=/)
|
226
|
+
end.split('=')[1] rescue nil
|
227
|
+
|
228
|
+
state.client_tingyun_id_secret = tingyun_id_secret
|
229
|
+
state.client_transaction_id = client_transaction_id
|
230
|
+
state.client_req_id = client_req_id
|
231
|
+
end
|
232
|
+
|
233
|
+
alias :skip_without_tingyun :skip
|
234
|
+
alias :skip :skip_with_tingyun
|
235
|
+
end
|
236
|
+
|
237
|
+
::Thrift::Client.module_eval do
|
238
|
+
|
239
|
+
include TingYun::Instrumentation::ThriftHelper
|
240
|
+
|
241
|
+
def send_message_args_with_tingyun(args_class, args = {})
|
242
|
+
state = TingYun::Agent::TransactionState.tl_get
|
243
|
+
return unless state.execution_traced?
|
244
|
+
cross_app_id = TingYun::Agent.config[:tingyunIdSecret] or
|
245
|
+
raise TingYun::Agent::CrossAppTracing::Error, "no tingyunIdSecret configured"
|
246
|
+
txn_guid = state.request_guid
|
247
|
+
tingyun_id = "#{cross_app_id};c=1;x=#{txn_guid}"
|
248
|
+
|
249
|
+
data = TingYun::Support::Serialize::JSONWrapper.dump("TingyunID" => tingyun_id)
|
250
|
+
@oprot.write_field_begin("TingyunField", 11, 6)
|
251
|
+
@oprot.write_string(data)
|
252
|
+
@oprot.write_field_end
|
253
|
+
send_message_args_without_tingyun(args_class, args)
|
254
|
+
end
|
255
|
+
|
256
|
+
alias :send_message_args_without_tingyun :send_message_args
|
257
|
+
alias :send_message_args :send_message_args_with_tingyun
|
258
|
+
|
259
|
+
def send_message_with_tingyun(name, args_class, args = {})
|
260
|
+
|
261
|
+
tag = "#{args_class.to_s.split('::').first.downcase}.#{name}"
|
262
|
+
t0 = Time.now.to_f
|
263
|
+
operations[tag] = {:started_time => t0}
|
264
|
+
state = TingYun::Agent::TransactionState.tl_get
|
265
|
+
return unless state.execution_traced?
|
266
|
+
stack = state.traced_method_stack
|
267
|
+
node = stack.push_frame(state,:thrift,t0)
|
268
|
+
operations[tag][:node] = node
|
269
|
+
|
270
|
+
send_message_without_tingyun(name, args_class, args)
|
271
|
+
end
|
272
|
+
|
273
|
+
alias :send_message_without_tingyun :send_message
|
274
|
+
alias :send_message :send_message_with_tingyun
|
275
|
+
|
276
|
+
def send_oneway_message_with_tingyun(name, args_class, args = {})
|
277
|
+
tag = "#{args_class.to_s.split('::').first.downcase}.#{name}"
|
278
|
+
op_started = Time.now.to_f
|
279
|
+
base, *other_metrics = metrics(tag)
|
280
|
+
result = send_oneway_message_without_tingyun(name, args_class, args)
|
281
|
+
duration = (Time.now.to_f - op_started)*1000
|
282
|
+
TingYun::Agent.instance.stats_engine.tl_record_scoped_and_unscoped_metrics(base, other_metrics, duration)
|
283
|
+
result
|
284
|
+
end
|
285
|
+
alias :send_oneway_message_without_tingyun :send_oneway_message
|
286
|
+
alias :send_oneway_message :send_oneway_message_with_tingyun
|
287
|
+
|
288
|
+
def receive_message_with_tingyun(result_klass)
|
289
|
+
state = TingYun::Agent::TransactionState.tl_get
|
290
|
+
|
291
|
+
operate = operator(result_klass)
|
292
|
+
|
293
|
+
t0, node = started_time_and_node(operate)
|
294
|
+
|
295
|
+
|
296
|
+
result = receive_message_without_tingyun(result_klass)
|
297
|
+
if result.nil? || result.success.nil?
|
298
|
+
e = ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, "#{operate} failed: unknown result")
|
299
|
+
e.instance_variable_set(:@tingyun_klass, metrics(operate)[0])
|
300
|
+
e.instance_variable_set(:@tingyun_external, true)
|
301
|
+
e.instance_variable_set(:@tingyun_code, 1000)
|
302
|
+
e.instance_variable_set(:@tingyun_trace, caller.reject! { |t| t.include?('tingyun_rpm') })
|
303
|
+
TingYun::Agent.notice_error(e)
|
304
|
+
end
|
305
|
+
|
306
|
+
t1 = Time.now.to_f
|
307
|
+
node_name, *other_metrics = metrics(operate)
|
308
|
+
duration = TingYun::Helper.time_to_millis(t1 - t0)
|
309
|
+
|
310
|
+
TingYun::Agent.instance.stats_engine.tl_record_scoped_and_unscoped_metrics(
|
311
|
+
other_metrics.pop, other_metrics, duration
|
312
|
+
)
|
313
|
+
if node
|
314
|
+
node.name = node_name
|
315
|
+
transaction_sampler = ::TingYun::Agent.instance.transaction_sampler
|
316
|
+
transaction_sampler.add_node_info(:uri => "thrift:#{tingyun_host}:#{tingyun_port}/#{operate}")
|
317
|
+
stack = state.traced_method_stack
|
318
|
+
stack.pop_frame(state, node, node_name, t1)
|
319
|
+
end
|
320
|
+
|
321
|
+
result
|
322
|
+
end
|
323
|
+
|
324
|
+
alias :receive_message_without_tingyun :receive_message
|
325
|
+
alias :receive_message :receive_message_with_tingyun
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under Ting Yun's license terms.
|
3
|
+
|
4
|
+
require 'thread'
|
5
|
+
require 'logger'
|
6
|
+
require 'ting_yun/logger/log_once'
|
7
|
+
require 'ting_yun/logger/memory_logger'
|
8
|
+
require 'ting_yun/support/hostname'
|
9
|
+
require 'ting_yun/logger/null_logger'
|
10
|
+
|
11
|
+
|
12
|
+
module TingYun
|
13
|
+
module Logger
|
14
|
+
class AgentLogger
|
15
|
+
include LogOnce
|
16
|
+
|
17
|
+
def initialize(root = "", override_logger=nil)
|
18
|
+
@already_logged_lock = Mutex.new
|
19
|
+
clear_already_logged
|
20
|
+
create_log(root, override_logger)
|
21
|
+
set_log_level!
|
22
|
+
set_log_format!
|
23
|
+
|
24
|
+
gather_startup_logs
|
25
|
+
end
|
26
|
+
|
27
|
+
def fatal(*msgs, &blk)
|
28
|
+
format_and_send(:fatal, msgs, &blk)
|
29
|
+
end
|
30
|
+
|
31
|
+
def error(*msgs, &blk)
|
32
|
+
format_and_send(:error, msgs, &blk)
|
33
|
+
end
|
34
|
+
|
35
|
+
def warn(*msgs, &blk)
|
36
|
+
format_and_send(:warn, msgs, &blk)
|
37
|
+
end
|
38
|
+
|
39
|
+
def info(*msgs, &blk)
|
40
|
+
format_and_send(:info, msgs, &blk)
|
41
|
+
end
|
42
|
+
|
43
|
+
def debug(*msgs, &blk)
|
44
|
+
format_and_send(:debug, msgs, &blk)
|
45
|
+
end
|
46
|
+
|
47
|
+
def is_startup_logger?
|
48
|
+
@log.is_a?(NullLogger)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Use this when you want to log an exception with explicit control over
|
52
|
+
# the log level that the backtrace is logged at. If you just want the
|
53
|
+
# default behavior of backtraces logged at debug, use one of the methods
|
54
|
+
# above and pass an Exception as one of the args.
|
55
|
+
def log_exception(level, e, backtrace_level=level)
|
56
|
+
@log.send(level, "%p: %s" % [e.class, e.message])
|
57
|
+
@log.send(backtrace_level) do
|
58
|
+
backtrace = backtrace_from_exception(e)
|
59
|
+
if backtrace
|
60
|
+
"Debugging backtrace:\n" + backtrace.join("\n ")
|
61
|
+
else
|
62
|
+
"No backtrace available."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def log_formatter=(formatter)
|
68
|
+
@log.formatter = formatter
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def backtrace_from_exception(e)
|
74
|
+
# We've seen that often the backtrace on a SystemStackError is bunk
|
75
|
+
# so massage the caller instead at a known depth.
|
76
|
+
#
|
77
|
+
# Tests keep us honest about minmum method depth our log calls add.
|
78
|
+
return caller.drop(5) if e.is_a?(SystemStackError)
|
79
|
+
|
80
|
+
e.backtrace
|
81
|
+
end
|
82
|
+
|
83
|
+
# Allows for passing exception.rb in explicitly, which format with backtrace
|
84
|
+
def format_and_send(level, *msgs, &block)
|
85
|
+
check_log_file
|
86
|
+
if block
|
87
|
+
if @log.send("#{level}?")
|
88
|
+
msgs = Array(block.call)
|
89
|
+
else
|
90
|
+
msgs = []
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
msgs.flatten.each do |item|
|
95
|
+
case item
|
96
|
+
when Exception then
|
97
|
+
log_exception(level, item, :debug)
|
98
|
+
else
|
99
|
+
@log.send(level, item)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def check_log_file
|
106
|
+
unless File.exist? @file_path
|
107
|
+
begin
|
108
|
+
@log = ::Logger.new(@file_path)
|
109
|
+
set_log_format!
|
110
|
+
rescue => e
|
111
|
+
@log = ::Logger.new(STDOUT)
|
112
|
+
warn("check_log_file: Failed creating logger for file #{file_path}, using standard out for logging.", e)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def create_log(root, override_logger)
|
118
|
+
if !override_logger.nil?
|
119
|
+
@log = override_logger
|
120
|
+
elsif ::TingYun::Agent.config[:'nbs.agent_enabled'] == false
|
121
|
+
create_null_logger
|
122
|
+
else
|
123
|
+
if wants_stdout?
|
124
|
+
@log = ::Logger.new(STDOUT)
|
125
|
+
else
|
126
|
+
create_log_to_file(root)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def create_log_to_file(root)
|
132
|
+
path = find_or_create_file_path(::TingYun::Agent.config[:agent_log_file_path], root)
|
133
|
+
if path.nil?
|
134
|
+
@log = ::Logger.new(STDOUT)
|
135
|
+
warn("Error creating log directory #{::TingYun::Agent.config[:agent_log_file_path]}, using standard out for logging.")
|
136
|
+
else
|
137
|
+
@file_path = "#{path}/#{::TingYun::Agent.config[:agent_log_file_name]}"
|
138
|
+
begin
|
139
|
+
@log = ::Logger.new(@file_path)
|
140
|
+
rescue => e
|
141
|
+
@log = ::Logger.new(STDOUT)
|
142
|
+
warn("Failed creating logger for file #{file_path}, using standard out for logging.", e)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def create_null_logger
|
148
|
+
@log = ::TingYun::Logger::NullLogger.new
|
149
|
+
end
|
150
|
+
|
151
|
+
def wants_stdout?
|
152
|
+
::TingYun::Agent.config[:agent_log_file_name].upcase == "STDOUT"
|
153
|
+
end
|
154
|
+
|
155
|
+
def find_or_create_file_path(path_setting, root)
|
156
|
+
for abs_path in [File.expand_path(path_setting),
|
157
|
+
File.expand_path(File.join(root, path_setting))] do
|
158
|
+
if File.directory?(abs_path) || (Dir.mkdir(abs_path) rescue nil)
|
159
|
+
return abs_path[%r{^(.*?)/?$}]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
nil
|
163
|
+
end
|
164
|
+
|
165
|
+
def set_log_level!
|
166
|
+
@log.level = AgentLogger.log_level_for(::TingYun::Agent.config[:agent_log_level])
|
167
|
+
end
|
168
|
+
|
169
|
+
LOG_LEVELS = {
|
170
|
+
"debug" => ::Logger::DEBUG,
|
171
|
+
"info" => ::Logger::INFO,
|
172
|
+
"warn" => ::Logger::WARN,
|
173
|
+
"error" => ::Logger::ERROR,
|
174
|
+
"fatal" => ::Logger::FATAL,
|
175
|
+
}
|
176
|
+
|
177
|
+
def self.log_level_for(level)
|
178
|
+
LOG_LEVELS.fetch(level.to_s.downcase, ::Logger::INFO)
|
179
|
+
end
|
180
|
+
|
181
|
+
def set_log_format!
|
182
|
+
@hostname = TingYun::Support::Hostname.get
|
183
|
+
@prefix = wants_stdout? ? '** [TingYun]' : ''
|
184
|
+
@log.formatter = Proc.new do |severity, timestamp, progname, msg|
|
185
|
+
"#{@prefix}[#{timestamp.strftime("%m/%d/%y %H:%M:%S %z")} #{@hostname} (#{$$})] #{severity} : #{msg}\n"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
#send the statup log info from memory to the agent log
|
190
|
+
def gather_startup_logs
|
191
|
+
StartupLogger.instance.dump(self)
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under Ting Yun's license terms.
|
3
|
+
|
4
|
+
module TingYun
|
5
|
+
module Logger
|
6
|
+
module LogOnce
|
7
|
+
NUM_LOG_ONCE_KEYS = 1000
|
8
|
+
|
9
|
+
def log_once(level, key, *msgs)
|
10
|
+
@already_logged_lock.synchronize do
|
11
|
+
return if @already_logged.include?(key)
|
12
|
+
|
13
|
+
if @already_logged.size >= NUM_LOG_ONCE_KEYS && key.kind_of?(String)
|
14
|
+
# The reason for preventing too many keys in `logged` is for
|
15
|
+
# memory concerns.
|
16
|
+
# The reason for checking the type of the key is that we always want
|
17
|
+
# to allow symbols to log, since there are very few of them.
|
18
|
+
# The assumption here is that you would NEVER pass dynamically-created
|
19
|
+
# symbols, because you would never create symbols dynamically in the
|
20
|
+
# first place, as that would already be a memory leak in most Rubies,
|
21
|
+
# even if we didn't hang on to them all here.
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
@already_logged[key] = true
|
26
|
+
end
|
27
|
+
|
28
|
+
self.send(level, *msgs)
|
29
|
+
end
|
30
|
+
|
31
|
+
def clear_already_logged
|
32
|
+
@already_logged_lock.synchronize do
|
33
|
+
@already_logged = {}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|