tingyun_rpm 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.gitignore +14 -0
  4. data/.travis.yml +4 -0
  5. data/CODE_OF_CONDUCT.md +13 -0
  6. data/Gemfile +3 -0
  7. data/Guardfile +25 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +41 -0
  10. data/cert/cacert.pem +0 -0
  11. data/lib/ting_yun/agent/agent.rb +128 -0
  12. data/lib/ting_yun/agent/class_methods.rb +21 -0
  13. data/lib/ting_yun/agent/collector/base_sampler.rb +2 -0
  14. data/lib/ting_yun/agent/collector/error_collector/error_trace_array.rb +88 -0
  15. data/lib/ting_yun/agent/collector/error_collector/noticed_error.rb +129 -0
  16. data/lib/ting_yun/agent/collector/error_collector.rb +165 -0
  17. data/lib/ting_yun/agent/collector/middle_ware_collector/cpu_sampler.rb +68 -0
  18. data/lib/ting_yun/agent/collector/middle_ware_collector/memory_sampler.rb +139 -0
  19. data/lib/ting_yun/agent/collector/middle_ware_collector/middle_ware.rb +13 -0
  20. data/lib/ting_yun/agent/collector/middle_ware_collector/sampler.rb +59 -0
  21. data/lib/ting_yun/agent/collector/middle_ware_collector.rb +80 -0
  22. data/lib/ting_yun/agent/collector/sql_sampler.rb +299 -0
  23. data/lib/ting_yun/agent/collector/stats_engine/metric_stats.rb +170 -0
  24. data/lib/ting_yun/agent/collector/stats_engine/stats_hash.rb +172 -0
  25. data/lib/ting_yun/agent/collector/stats_engine.rb +28 -0
  26. data/lib/ting_yun/agent/collector/transaction_sampler/slowest_sample_buffer.rb +25 -0
  27. data/lib/ting_yun/agent/collector/transaction_sampler/transaction_sample_buffer_base.rb +96 -0
  28. data/lib/ting_yun/agent/collector/transaction_sampler.rb +226 -0
  29. data/lib/ting_yun/agent/container_data_manager.rb +94 -0
  30. data/lib/ting_yun/agent/cross_app/cross_app_monitor.rb +131 -0
  31. data/lib/ting_yun/agent/cross_app/cross_app_tracing.rb +202 -0
  32. data/lib/ting_yun/agent/cross_app/inbound_request_monitor.rb +22 -0
  33. data/lib/ting_yun/agent/database.rb +410 -0
  34. data/lib/ting_yun/agent/datastore/metric_helper.rb +82 -0
  35. data/lib/ting_yun/agent/datastore/mongo.rb +44 -0
  36. data/lib/ting_yun/agent/datastore.rb +33 -0
  37. data/lib/ting_yun/agent/dispatcher.rb +39 -0
  38. data/lib/ting_yun/agent/event/event_listener.rb +47 -0
  39. data/lib/ting_yun/agent/event/event_loop.rb +194 -0
  40. data/lib/ting_yun/agent/instance_methods/connect.rb +164 -0
  41. data/lib/ting_yun/agent/instance_methods/container_data_manager.rb +137 -0
  42. data/lib/ting_yun/agent/instance_methods/handle_errors.rb +71 -0
  43. data/lib/ting_yun/agent/instance_methods/start.rb +219 -0
  44. data/lib/ting_yun/agent/instance_methods/start_worker_thread.rb +51 -0
  45. data/lib/ting_yun/agent/instance_methods.rb +39 -0
  46. data/lib/ting_yun/agent/method_tracer.rb +256 -0
  47. data/lib/ting_yun/agent/method_tracer_helpers.rb +85 -0
  48. data/lib/ting_yun/agent/threading/agent_thread.rb +49 -0
  49. data/lib/ting_yun/agent/transaction/attributes.rb +22 -0
  50. data/lib/ting_yun/agent/transaction/request_attributes.rb +126 -0
  51. data/lib/ting_yun/agent/transaction/trace.rb +125 -0
  52. data/lib/ting_yun/agent/transaction/trace_node.rb +110 -0
  53. data/lib/ting_yun/agent/transaction/traced_method_stack.rb +80 -0
  54. data/lib/ting_yun/agent/transaction/transaction_metrics.rb +51 -0
  55. data/lib/ting_yun/agent/transaction/transaction_sample_builder.rb +63 -0
  56. data/lib/ting_yun/agent/transaction/transaction_state.rb +112 -0
  57. data/lib/ting_yun/agent/transaction.rb +522 -0
  58. data/lib/ting_yun/agent.rb +207 -0
  59. data/lib/ting_yun/configuration/default_source.rb +638 -0
  60. data/lib/ting_yun/configuration/dotted_hash.rb +46 -0
  61. data/lib/ting_yun/configuration/environment_source.rb +116 -0
  62. data/lib/ting_yun/configuration/manager.rb +232 -0
  63. data/lib/ting_yun/configuration/manual_source.rb +14 -0
  64. data/lib/ting_yun/configuration/server_source.rb +88 -0
  65. data/lib/ting_yun/configuration/yaml_source.rb +136 -0
  66. data/lib/ting_yun/configuration.rb +9 -0
  67. data/lib/ting_yun/environment_report.rb +123 -0
  68. data/lib/ting_yun/frameworks/class_methods.rb +47 -0
  69. data/lib/ting_yun/frameworks/external.rb +15 -0
  70. data/lib/ting_yun/frameworks/instance_methods.rb +120 -0
  71. data/lib/ting_yun/frameworks/instrumentation.rb +67 -0
  72. data/lib/ting_yun/frameworks/rails.rb +63 -0
  73. data/lib/ting_yun/frameworks/rails3.rb +26 -0
  74. data/lib/ting_yun/frameworks/rails4.rb +14 -0
  75. data/lib/ting_yun/frameworks/ruby.rb +17 -0
  76. data/lib/ting_yun/frameworks/sinatra.rb +10 -0
  77. data/lib/ting_yun/frameworks.rb +34 -0
  78. data/lib/ting_yun/http/generic_request.rb +8 -0
  79. data/lib/ting_yun/http/net_http_request.rb +46 -0
  80. data/lib/ting_yun/instrumentation/active_record.rb +103 -0
  81. data/lib/ting_yun/instrumentation/middleware_proxy.rb +77 -0
  82. data/lib/ting_yun/instrumentation/middleware_tracing.rb +84 -0
  83. data/lib/ting_yun/instrumentation/mongo.rb +103 -0
  84. data/lib/ting_yun/instrumentation/mongo2.rb +37 -0
  85. data/lib/ting_yun/instrumentation/mongo_command_log_subscriber.rb +97 -0
  86. data/lib/ting_yun/instrumentation/moped.rb +95 -0
  87. data/lib/ting_yun/instrumentation/net.rb +59 -0
  88. data/lib/ting_yun/instrumentation/rack.rb +109 -0
  89. data/lib/ting_yun/instrumentation/rails3/action_controller.rb +63 -0
  90. data/lib/ting_yun/instrumentation/rails3/action_view.rb +115 -0
  91. data/lib/ting_yun/instrumentation/rails4/action_controller_subscriber.rb +124 -0
  92. data/lib/ting_yun/instrumentation/rails4/action_view_subscriber.rb +118 -0
  93. data/lib/ting_yun/instrumentation/rails4/active_record_subscriber.rb +124 -0
  94. data/lib/ting_yun/instrumentation/rails_middleware.rb +38 -0
  95. data/lib/ting_yun/instrumentation/redis.rb +70 -0
  96. data/lib/ting_yun/instrumentation/support/active_record_helper.rb +178 -0
  97. data/lib/ting_yun/instrumentation/support/controller_instrumentation.rb +54 -0
  98. data/lib/ting_yun/instrumentation/support/database.rb +38 -0
  99. data/lib/ting_yun/instrumentation/support/event_formatter.rb +19 -0
  100. data/lib/ting_yun/instrumentation/support/evented_subscriber.rb +97 -0
  101. data/lib/ting_yun/instrumentation/support/external_error.rb +52 -0
  102. data/lib/ting_yun/instrumentation/support/metric_translator.rb +84 -0
  103. data/lib/ting_yun/instrumentation/support/mongo_formatter.rb +49 -0
  104. data/lib/ting_yun/instrumentation/support/parameter_filtering.rb +21 -0
  105. data/lib/ting_yun/instrumentation/support/queue_time.rb +76 -0
  106. data/lib/ting_yun/instrumentation/support/transaction_namer.rb +68 -0
  107. data/lib/ting_yun/instrumentation/thrift.rb +329 -0
  108. data/lib/ting_yun/logger/agent_logger.rb +196 -0
  109. data/lib/ting_yun/logger/log_once.rb +38 -0
  110. data/lib/ting_yun/logger/memory_logger.rb +56 -0
  111. data/lib/ting_yun/logger/null_logger.rb +31 -0
  112. data/lib/ting_yun/logger/startup_logger.rb +13 -0
  113. data/lib/ting_yun/logger.rb +8 -0
  114. data/lib/ting_yun/metrics/metric_data.rb +86 -0
  115. data/lib/ting_yun/metrics/metric_spec.rb +89 -0
  116. data/lib/ting_yun/metrics/stats.rb +158 -0
  117. data/lib/ting_yun/metrics.rb +12 -0
  118. data/lib/ting_yun/support/coerce.rb +86 -0
  119. data/lib/ting_yun/support/collector.rb +29 -0
  120. data/lib/ting_yun/support/exception.rb +79 -0
  121. data/lib/ting_yun/support/hash_extensions.rb +25 -0
  122. data/lib/ting_yun/support/helper.rb +54 -0
  123. data/lib/ting_yun/support/hostname.rb +13 -0
  124. data/lib/ting_yun/support/http_clients/uri_util.rb +49 -0
  125. data/lib/ting_yun/support/language_support.rb +155 -0
  126. data/lib/ting_yun/support/library_detection.rb +129 -0
  127. data/lib/ting_yun/support/local_environment.rb +185 -0
  128. data/lib/ting_yun/support/path.rb +13 -0
  129. data/lib/ting_yun/support/serialize/encodes.rb +61 -0
  130. data/lib/ting_yun/support/serialize/encoding_normalizer.rb +84 -0
  131. data/lib/ting_yun/support/serialize/json_marshaller.rb +73 -0
  132. data/lib/ting_yun/support/serialize/json_wrapper.rb +78 -0
  133. data/lib/ting_yun/support/serialize/marshaller.rb +69 -0
  134. data/lib/ting_yun/support/serialize/ok_json.rb +651 -0
  135. data/lib/ting_yun/support/system_info.rb +206 -0
  136. data/lib/ting_yun/support/timer_lib.rb +29 -0
  137. data/lib/ting_yun/support/version_number.rb +70 -0
  138. data/lib/ting_yun/ting_yun_service/connection.rb +118 -0
  139. data/lib/ting_yun/ting_yun_service/http.rb +41 -0
  140. data/lib/ting_yun/ting_yun_service/request.rb +90 -0
  141. data/lib/ting_yun/ting_yun_service/ssl.rb +45 -0
  142. data/lib/ting_yun/ting_yun_service/upload_service.rb +149 -0
  143. data/lib/ting_yun/ting_yun_service.rb +124 -0
  144. data/lib/ting_yun/version.rb +17 -0
  145. data/lib/tingyun_rpm.rb +47 -0
  146. data/tingyun_rpm.gemspec +60 -0
  147. 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