tingyun_rpm 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/lib/ting_yun/agent/agent.rb +8 -0
  4. data/lib/ting_yun/agent/collector/stats_engine/base_quantile_hash.rb +20 -0
  5. data/lib/ting_yun/agent/collector/stats_engine/metric_stats.rb +10 -0
  6. data/lib/ting_yun/agent/collector/stats_engine.rb +9 -0
  7. data/lib/ting_yun/agent/collector/transaction_sampler/class_method.rb +2 -2
  8. data/lib/ting_yun/agent/cross_app/cross_app_tracing.rb +16 -10
  9. data/lib/ting_yun/agent/datastore/metric_helper.rb +31 -7
  10. data/lib/ting_yun/agent/datastore.rb +6 -11
  11. data/lib/ting_yun/agent/dispatcher.rb +5 -1
  12. data/lib/ting_yun/agent/instance_methods/container_data_manager.rb +5 -1
  13. data/lib/ting_yun/agent/instance_methods/start_worker_thread.rb +5 -0
  14. data/lib/ting_yun/agent/method_tracer_helpers.rb +8 -4
  15. data/lib/ting_yun/agent/transaction/attributes.rb +6 -2
  16. data/lib/ting_yun/agent/transaction/class_method.rb +14 -5
  17. data/lib/ting_yun/agent/transaction/instance_method.rb +20 -4
  18. data/lib/ting_yun/agent/transaction/trace.rb +2 -1
  19. data/lib/ting_yun/agent/transaction/trace_node.rb +10 -2
  20. data/lib/ting_yun/agent/transaction/traced_method_stack.rb +2 -2
  21. data/lib/ting_yun/agent/transaction/transaction_sample_builder.rb +2 -1
  22. data/lib/ting_yun/agent/transaction/transaction_state.rb +22 -1
  23. data/lib/ting_yun/agent/transaction/transaction_timings.rb +1 -2
  24. data/lib/ting_yun/agent/transaction.rb +13 -7
  25. data/lib/ting_yun/configuration/default_source.rb +44 -7
  26. data/lib/ting_yun/configuration/yaml_source.rb +1 -0
  27. data/lib/ting_yun/frameworks/instrumentation.rb +6 -1
  28. data/lib/ting_yun/frameworks/rails5.rb +10 -0
  29. data/lib/ting_yun/frameworks.rb +1 -1
  30. data/lib/ting_yun/http/http_client_request.rb +39 -0
  31. data/lib/ting_yun/http/net_http_request.rb +4 -0
  32. data/lib/ting_yun/instrumentation/active_record.rb +11 -5
  33. data/lib/ting_yun/instrumentation/bunny.rb +142 -0
  34. data/lib/ting_yun/instrumentation/data_mapper.rb +167 -0
  35. data/lib/ting_yun/instrumentation/grape.rb +39 -0
  36. data/lib/ting_yun/instrumentation/http_client.rb +70 -0
  37. data/lib/ting_yun/instrumentation/kafka.rb +218 -0
  38. data/lib/ting_yun/instrumentation/memcached.rb +135 -0
  39. data/lib/ting_yun/instrumentation/middleware_proxy.rb +1 -4
  40. data/lib/ting_yun/instrumentation/middleware_tracing.rb +5 -1
  41. data/lib/ting_yun/instrumentation/mongo.rb +18 -6
  42. data/lib/ting_yun/instrumentation/mongo2.rb +5 -1
  43. data/lib/ting_yun/instrumentation/mongo_command_log_subscriber.rb +5 -5
  44. data/lib/ting_yun/instrumentation/moped.rb +4 -3
  45. data/lib/ting_yun/instrumentation/net.rb +3 -3
  46. data/lib/ting_yun/instrumentation/rails3/action_controller.rb +8 -4
  47. data/lib/ting_yun/instrumentation/rails3/action_view.rb +8 -4
  48. data/lib/ting_yun/instrumentation/rails4/action_controller.rb +29 -0
  49. data/lib/ting_yun/instrumentation/rails4/action_view.rb +29 -0
  50. data/lib/ting_yun/instrumentation/rails4/active_record.rb +30 -0
  51. data/lib/ting_yun/instrumentation/rails5/action_cable.rb +31 -0
  52. data/lib/ting_yun/instrumentation/rails5/action_controller.rb +29 -0
  53. data/lib/ting_yun/instrumentation/rails5/action_view.rb +28 -0
  54. data/lib/ting_yun/instrumentation/rails5/active_record.rb +30 -0
  55. data/lib/ting_yun/instrumentation/rake.rb +3 -2
  56. data/lib/ting_yun/instrumentation/redis.rb +6 -5
  57. data/lib/ting_yun/instrumentation/sidekiq.rb +61 -0
  58. data/lib/ting_yun/instrumentation/sinatra/action.rb +95 -0
  59. data/lib/ting_yun/instrumentation/sinatra/view.rb +67 -0
  60. data/lib/ting_yun/instrumentation/support/action_cable_subscriber.rb +83 -0
  61. data/lib/ting_yun/instrumentation/{rails4 → support}/action_controller_subscriber.rb +5 -29
  62. data/lib/ting_yun/instrumentation/{rails4 → support}/action_view_subscriber.rb +2 -24
  63. data/lib/ting_yun/instrumentation/support/active_record_helper.rb +23 -6
  64. data/lib/ting_yun/instrumentation/{rails4 → support}/active_record_subscriber.rb +13 -37
  65. data/lib/ting_yun/instrumentation/support/controller_instrumentation.rb +204 -1
  66. data/lib/ting_yun/instrumentation/support/database.rb +2 -1
  67. data/lib/ting_yun/instrumentation/support/external_error.rb +2 -2
  68. data/lib/ting_yun/instrumentation/support/external_helper.rb +30 -0
  69. data/lib/ting_yun/instrumentation/support/method_instrumentation.rb +228 -0
  70. data/lib/ting_yun/instrumentation/support/metric_translator.rb +4 -1
  71. data/lib/ting_yun/instrumentation/support/sinatra_helper.rb +20 -0
  72. data/lib/ting_yun/instrumentation/support/transaction_namer.rb +3 -1
  73. data/lib/ting_yun/instrumentation/thrift.rb +5 -6
  74. data/lib/ting_yun/logger/agent_logger.rb +1 -0
  75. data/lib/ting_yun/logger/create_logger_helper.rb +16 -2
  76. data/lib/ting_yun/metrics/metric_data.rb +8 -2
  77. data/lib/ting_yun/metrics/metric_spec.rb +2 -1
  78. data/lib/ting_yun/support/helper.rb +4 -0
  79. data/lib/ting_yun/support/quantile_p2.rb +204 -0
  80. data/lib/ting_yun/ting_yun_service/upload_service.rb +38 -12
  81. data/lib/ting_yun/ting_yun_service.rb +4 -7
  82. data/lib/ting_yun/version.rb +3 -1
  83. data/lib/tingyun_rpm.rb +0 -4
  84. data/tingyun_rpm.gemspec +3 -3
  85. metadata +35 -13
  86. data/CODE_OF_CONDUCT.md +0 -13
  87. data/lib/ting_yun/agent/method_tracer.rb +0 -256
@@ -0,0 +1,228 @@
1
+ # encoding: utf-8
2
+ require 'ting_yun/frameworks' unless defined?(TingYun::Frameworks::Framework)
3
+ require 'ting_yun/support/helper'
4
+ require 'ting_yun/agent/method_tracer_helpers'
5
+ require 'ting_yun/agent/transaction/transaction_state'
6
+
7
+ module TingYun
8
+ module Instrumentation
9
+ module Support
10
+ module MethodInstrumentation
11
+
12
+ # This module contains class methods added to support installing custom
13
+ # metric tracers and executing for individual metrics.
14
+ #
15
+ # == Examples
16
+ #
17
+ # When the agent initializes, it extends Module with these methods.
18
+ # However if you want to use the API in code that might get loaded
19
+ # before the agent is initialized you will need to require
20
+ # this file:
21
+ #
22
+ # require 'ting_yun/instrumentation/support/method_instrumentation'
23
+ # class A
24
+ # include TingYun::Instrumentation::Support::MethodInstrumentation
25
+ # def process
26
+ # ...
27
+ # end
28
+ # add_method_tracer :process
29
+ # end
30
+ #
31
+ # To instrument a class method:
32
+ #
33
+ # require 'ting_yun/instrumentation/support/method_instrumentation'
34
+ # class An
35
+ # def self.process
36
+ # ...
37
+ # end
38
+ # class << self
39
+ # include TingYun::Instrumentation::Support::MethodInstrumentation
40
+ # add_method_tracer :process
41
+ # end
42
+ # end
43
+ #
44
+ # @api public
45
+
46
+ def self.included(klass)
47
+ klass.extend ClassMethods
48
+ end
49
+
50
+ def self.extended(klass)
51
+ klass.extend ClassMethods
52
+ end
53
+
54
+ module ClassMethods
55
+ def method_exists?(method_name)
56
+ exists = method_defined?(method_name) || private_method_defined?(method_name)
57
+ ::TingYun::Agent.logger.error("Did not trace #{self.name}##{method_name} because that method does not exist") unless exists
58
+ exists
59
+ end
60
+
61
+ # Example:
62
+ # Foo.default_metric_name('bar') #=> "tingyun/#{Foo.name}/bar"
63
+ def default_metric_name(method_name)
64
+ "tingyun/#{self.name}/#{method_name.to_s}"
65
+ end
66
+
67
+
68
+ # Checks to see if we have already traced a method with a
69
+ # given metric by checking to see if the traced method
70
+ # exists. Warns the user if methods are being double-traced
71
+ # to help with debugging custom instrumentation.
72
+ def traced_method_exists?(method_name, metric_name)
73
+ exists = method_defined?(define_trace_method_name(method_name, metric_name))
74
+ ::TingYun::Agent.logger.error("Attempt to trace a method twice with the same metric: Method = #{method_name}, Metric Name = #{metric_name}") if exists
75
+ exists
76
+ end
77
+
78
+ def tingyun_eval(method_name, metric_name, options)
79
+ options = validate_options(method_name, options)
80
+ if options[:scope]
81
+ define_method_with_scope(method_name, metric_name, options)
82
+ else
83
+ define_method_without_scope(method_name,metric_name, options)
84
+ end
85
+ end
86
+
87
+ DEFAULT_SETTINGS = {:scope => true, :metric => true, :before_code => "", :after_code => "" }.freeze
88
+
89
+ def validate_options(method_name, options)
90
+ unless options.is_a?(Hash)
91
+ raise TypeError.new("Error adding method tracer to #{method_name}: provided options must be a Hash")
92
+ end
93
+ options = DEFAULT_SETTINGS.merge(options)
94
+ unless options[:scope] || options[:metric]
95
+ raise "Can't add a tracer where push_scope is false and metric is false"
96
+ end
97
+ options
98
+ end
99
+
100
+ def define_method_with_scope(method_name,metric_name,options)
101
+ "def #{define_trace_method_name(method_name,metric_name)}(*args, &block)
102
+ #{options[:before_code]}
103
+
104
+ result = ::TingYun::Agent::MethodTracerHelpers.trace_execution_scoped(\"#{metric_name}\",
105
+ :metric => #{options[:metric]}) do
106
+ #{define_untrace_method_name(method_name, metric_name)}(*args, &block)
107
+ end
108
+ #{options[:after_code]}
109
+ result
110
+ end"
111
+ end
112
+
113
+ def define_method_without_scope(method_name,metric_name,options)
114
+ "def #{define_trace_method_name(method_name,metric_name)}(*args, &block)
115
+ return #{define_untrace_method_name(method_name, metric_name)}(*args, &block) unless TingYun::Agent::TransactionState.tl_get.execution_traced?\n
116
+ #{options[:before_code]}
117
+ t0 = Time.now
118
+ begin
119
+ #{define_untrace_method_name(method_name, metric_name)}(*args, &block)\n
120
+ ensure
121
+ duration = (Time.now - t0).to_f
122
+ ::TingYun::Agent.record_metric(\"#{metric_name}\", duration)
123
+ #{options[:after_code]}
124
+ end
125
+ end"
126
+ end
127
+
128
+ # Add a method tracer to the specified method.
129
+ #
130
+ # By default, this will cause invocations of the traced method to be
131
+ # recorded in transaction traces, and in a metric named after the class
132
+ # and method. It will also make the method show up in transaction-level
133
+ # breakdown charts and tables.
134
+ #
135
+ # === Overriding the metric name
136
+ #
137
+ # +metric_name+ is a string that is eval'd to get the name of the
138
+ # metric associated with the call, so if you want to use interpolation
139
+ # evaluated at call time, then single quote the value like this:
140
+ #
141
+ # add_method_tracer :foo, 'tingyun/#{self.class.name}/foo'
142
+ #
143
+ # This would name the metric according to the class of the runtime
144
+ # intance, as opposed to the class where +foo+ is defined.
145
+ #
146
+ # If not provided, the metric name will be <tt>tingyun/ClassName/method_name</tt>.
147
+ #
148
+ # @param [Symbol] method_name the name of the method to trace
149
+ # @param [String] metric_name the metric name to record calls to
150
+ # the traced method under. This may be either a static string, or Ruby
151
+ # code to be evaluated at call-time in order to determine the metric
152
+ # name dynamically.
153
+ # @param [Hash] options additional options controlling how the method is
154
+ # traced.
155
+ # @option options [Boolean] :scope (true) If false, the traced method will
156
+ # not appear in transaction traces(the components) or breakdown charts, and it will
157
+ # only be visible in custom dashboards(the generals).
158
+ # @option options [Boolean] :metric (true) If false, the traced method will
159
+ # only appear in transaction traces, but no metrics will be recorded
160
+ # for it.
161
+ # @option options [String] :before_code ('') Ruby code to be inserted and run
162
+ # before the tracer begins timing.
163
+ # @option options [String] :after_code ('') Ruby code to be inserted and run
164
+ # after the tracer stops timing.
165
+ #
166
+ # @example
167
+ # add_method_tracer :foo
168
+ #
169
+ # # With a custom metric name
170
+ # add_method_tracer :foo, 'tingyun/#{self.class.name}/foo'
171
+ #
172
+ # # Instrument foo only for custom dashboards (not in transaction
173
+ # # traces or breakdown charts)
174
+ # add_method_tracer :foo, 'tingyun/foo', :scope => false
175
+ #
176
+ # # Instrument foo in transaction traces only
177
+ # add_method_tracer :foo, 'tingyun/foo', :metric => false
178
+ #
179
+ # @api public
180
+ #
181
+
182
+
183
+ def add_method_tracer(method_name, metric_name = nil, opt={})
184
+ return unless method_exists?(method_name)
185
+ metric_name ||= default_metric_name(method_name)
186
+ return if traced_method_exists?(method_name, metric_name)
187
+
188
+ traced_method = tingyun_eval(method_name, metric_name,opt)
189
+
190
+ visibility = TingYun::Helper.instance_method_visibility self, method_name
191
+ class_eval traced_method, __FILE__, __LINE__
192
+
193
+ alias_method define_untrace_method_name(method_name, metric_name), method_name
194
+ alias_method method_name, define_trace_method_name(method_name, metric_name)
195
+ send visibility, method_name
196
+ send visibility, define_trace_method_name(method_name, metric_name)
197
+ ::TingYun::Agent.logger.debug("Traced method: class = #{self.name},"+
198
+ "method = #{method_name}, "+
199
+ "metric = '#{metric_name}'")
200
+ end
201
+
202
+ private
203
+
204
+
205
+ # given a method and a metric, this method returns the
206
+ # traced alias of the method name
207
+ def define_trace_method_name(method_name, metric_name)
208
+ "#{_sanitize_name(method_name)}_with_trace_#{_sanitize_name(metric_name)}"
209
+ end
210
+ # given a method and a metric, this method returns the
211
+ # untraced alias of the method name
212
+ def define_untrace_method_name(method_name, metric_name)
213
+ "#{_sanitize_name(method_name)}_without_trace_#{_sanitize_name(metric_name)}"
214
+ end
215
+
216
+ # makes sure that method names do not contain characters that
217
+ # might break the interpreter, for example ! or ? characters
218
+ # that are not allowed in the middle of method names
219
+ def _sanitize_name(name)
220
+ name.to_s.tr_s('^a-zA-Z0-9', '_')
221
+ end
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end
227
+
228
+
@@ -10,7 +10,7 @@ module TingYun
10
10
 
11
11
  MONGODB = 'MongoDB'.freeze
12
12
 
13
- def self.metrics_for(name, payload)
13
+ def self.metrics_for(name, payload, host_port)
14
14
  payload ||= {}
15
15
 
16
16
  return nil if collection_in_selector?(payload)
@@ -27,6 +27,9 @@ module TingYun
27
27
 
28
28
  TingYun::Agent::Datastore::MetricHelper.metrics_for(MONGODB,
29
29
  TingYun::Agent::Datastore::Mongo.transform_operation(name),
30
+ host_port[0],
31
+ host_port[1],
32
+ payload[:database],
30
33
  collection)
31
34
  rescue => e
32
35
  TingYun::Agent.logger.debug("Failure during Mongo metric generation", e)
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ module TingYun
4
+ module Instrumentation
5
+ module Support
6
+ module SinatraHelper
7
+
8
+ module_function
9
+
10
+ SINATRA_MIN_VERSION = '1.2.3'.freeze
11
+ SINATRA_MAX_VERSION = '1.4.8'.freeze
12
+
13
+ def version_supported?
14
+ TingYun::Support::VersionNumber.new(::Sinatra::VERSION) >= TingYun::Support::VersionNumber.new(SINATRA_MIN_VERSION)
15
+ TingYun::Support::VersionNumber.new(::Sinatra::VERSION) <= TingYun::Support::VersionNumber.new(SINATRA_MAX_VERSION)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -19,13 +19,15 @@ module TingYun
19
19
  when :uri then
20
20
  ::TingYun::Agent::Transaction::CONTROLLER_PREFIX
21
21
  when :sinatra then
22
- ::TingYun::Agent::Transaction::SINATRA_PREFIX
22
+ ::TingYun::Agent::Transaction::CONTROLLER_PREFIX
23
23
  when :middleware then
24
24
  ::TingYun::Agent::Transaction::MIDDLEWARE_PREFIX
25
25
  when :grape then
26
26
  ::TingYun::Agent::Transaction::GRAPE_PREFIX
27
27
  when :rake then
28
28
  ::TingYun::Agent::Transaction::RAKE_PREFIX
29
+ when :action_cable then
30
+ ::TingYun::Agent::Transaction::CABLE_PREFIX
29
31
  else
30
32
  "#{category.to_s}/" # for internal use only
31
33
  end
@@ -13,6 +13,7 @@ TingYun::Support::LibraryDetection.defer do
13
13
  executes do
14
14
  TingYun::Agent.logger.info 'Installing Thrift Instrumentation'
15
15
  require 'ting_yun/support/serialize/json_wrapper'
16
+ require 'ting_yun/instrumentation/support/external_helper'
16
17
  end
17
18
 
18
19
  executes do
@@ -40,19 +41,17 @@ TingYun::Support::LibraryDetection.defer do
40
41
  require 'ting_yun/instrumentation/support/thrift_helper'
41
42
 
42
43
  include TingYun::Instrumentation::ThriftHelper
43
-
44
+ include TingYun::Instrumentation::Support::ExternalHelper
44
45
 
45
46
  def send_message_args_with_tingyun(args_class, args = {})
46
47
  return send_message_args_without_tingyun(args_class, args) unless TingYun::Agent.config[:'nbs.transaction_tracer.thrift'] && TingYun::Agent.config[:'nbs.transaction_tracer.enabled']
47
48
  begin
48
49
  state = TingYun::Agent::TransactionState.tl_get
49
50
  return unless state.execution_traced?
50
- cross_app_id = TingYun::Agent.config[:tingyunIdSecret] or
51
- raise TingYun::Agent::CrossAppTracing::Error, "no tingyunIdSecret configured"
52
- tingyun_id = "#{cross_app_id};c=1;x=#{state.request_guid}"
53
51
 
54
- data = TingYun::Support::Serialize::JSONWrapper.dump("TingyunID" => tingyun_id)
55
- @oprot.write_field_begin("TingyunField", 11, 6)
52
+ data = TingYun::Support::Serialize::JSONWrapper.dump("TingyunID" => create_tingyun_id("thrift"))
53
+ TingYun::Agent.logger.info("thift will send TingyunID : ", data)
54
+ @oprot.write_field_begin("TingyunField", 11, 40000)
56
55
  @oprot.write_string(data)
57
56
  @oprot.write_field_end
58
57
  rescue => e
@@ -14,6 +14,7 @@ module TingYun
14
14
  include ::TingYun::Logger::LogOnce
15
15
  include ::TingYun::Logger::CreateLoggerHelper
16
16
 
17
+ attr_reader :file_path
17
18
  def initialize(root = "", override_logger=nil)
18
19
  @already_logged_lock = Mutex.new
19
20
  clear_already_logged
@@ -4,7 +4,7 @@ module TingYun
4
4
  module Logger
5
5
  module CreateLoggerHelper
6
6
 
7
-
7
+ module_function
8
8
 
9
9
  def create_log(root, override_logger)
10
10
  if !override_logger.nil?
@@ -26,6 +26,7 @@ module TingYun
26
26
  begin
27
27
  @log = ::Logger.new(@file_path)
28
28
  set_log_format
29
+ set_log_level
29
30
  rescue => e
30
31
  @log = ::Logger.new(STDOUT)
31
32
  warn("check_log_file: Failed creating logger for file #{@file_path}, using standard out for logging.", e)
@@ -33,7 +34,20 @@ module TingYun
33
34
  end
34
35
  end
35
36
 
36
-
37
+ def create_new_logfile
38
+ file_path = TingYun::Agent.logger.file_path
39
+ shift_age = TingYun::Agent.config[:agent_log_file_number]
40
+ if File.size(file_path) >= (TingYun::Agent.config[:agent_log_file_size])*1024*1024
41
+ (shift_age-3).downto(0) do |i|
42
+ index_file = file_path.gsub('.log', "_#{i}.log")
43
+ if FileTest.exist?(index_file)
44
+ File.rename(index_file, file_path.gsub('.log', "_#{i+1}.log"))
45
+ end
46
+ end
47
+ TingYun::Agent.agent.untraced_graceful_disconnect
48
+ File.rename(file_path, file_path.gsub('.log', "_0.log"))
49
+ end
50
+ end
37
51
 
38
52
  def create_log_to_file(root)
39
53
  path = find_or_create_file_path(::TingYun::Agent.config[:agent_log_file_path], root)
@@ -13,11 +13,13 @@ module TingYun
13
13
  attr_accessor :metric_id
14
14
  # the actual statistics object
15
15
  attr_accessor :stats
16
+ attr_reader :quantile
16
17
 
17
- def initialize(metric_spec, stats, metric_id)
18
+ def initialize(metric_spec, stats, metric_id, quantile = [])
18
19
  @metric_spec = metric_spec
19
20
  @stats = stats
20
21
  @metric_id = metric_id
22
+ @quantile = quantile
21
23
  end
22
24
 
23
25
  def eql?(o)
@@ -48,7 +50,11 @@ module TingYun
48
50
 
49
51
  def to_collector_array(encoder=nil)
50
52
  stat_key = metric_id || to_hash
51
- [stat_key, metrics(stat_key)]
53
+ if quantile.empty?
54
+ [stat_key, metrics(stat_key)]
55
+ else
56
+ [stat_key, metrics(stat_key), quantile]
57
+ end
52
58
  end
53
59
 
54
60
  def to_hash
@@ -8,7 +8,7 @@
8
8
  module TingYun
9
9
  module Metrics
10
10
  class MetricSpec
11
- attr_accessor :name, :scope, :calleeId, :calleeName
11
+ attr_accessor :name, :scope, :calleeId, :calleeName, :full_name
12
12
 
13
13
  # the maximum length of a metric name or metric scope
14
14
  MAX_LENGTH = 255
@@ -16,6 +16,7 @@ module TingYun
16
16
  EMPTY_SCOPE = ''.freeze
17
17
 
18
18
  def initialize(metric_name='', metric_scope=nil)
19
+ @full_name = metric_name.to_s
19
20
  if metric_name.to_s.length > MAX_LENGTH
20
21
  @name = metric_name.to_s[LENGTH_RANGE]
21
22
  else
@@ -47,6 +47,10 @@ module TingYun
47
47
  (time.to_f * 1000).round
48
48
  end
49
49
 
50
+ def time_to_f_millis(time)
51
+ (time.to_f * 1000)
52
+ end
53
+
50
54
  def milliseconds_to_seconds(milliseconds)
51
55
  milliseconds / 1000.0
52
56
  end
@@ -0,0 +1,204 @@
1
+ # encoding: utf-8
2
+ require 'json'
3
+
4
+ module TingYun
5
+ module Support
6
+ class QuantileP2
7
+
8
+ def self.support?
9
+ return false if !TingYun::Agent.config[:'nbs.quantile']
10
+ quantile = TingYun::Agent.config[:'nbs.quantile']
11
+ quantile = JSON.parse(quantile) rescue false unless quantile.is_a?(Array)
12
+ return false if !quantile || quantile.empty? || (quantile.size > quantile.uniq.size) || quantile.any? { |i| i.to_i == 0 || !i.is_a?(Fixnum)}
13
+ return true
14
+ end
15
+
16
+
17
+
18
+ attr_accessor :quartileList, :markers_y, :markers_x, :p2_n, :count
19
+ def initialize(quartileList)
20
+ @quartileList = quartileList.sort!
21
+ @markers_y = Array.new(@quartileList.length * 2 + 3){0.0}
22
+ @count = 0
23
+ initMarkers
24
+ end
25
+
26
+ def initMarkers
27
+ quartile_count = quartileList.length
28
+ marker_count = quartile_count * 2 + 3
29
+ @markers_x = Array.new(marker_count){0.0}
30
+ @markers_x[0] = 0.0
31
+ @p2_n = Array.new(markers_y.length){0}
32
+ (0..quartile_count-1).each do |i|
33
+ marker = quartileList[i]
34
+ markers_x[i * 2 + 1] = (marker + markers_x[i * 2]) / 2
35
+ markers_x[i * 2 + 2] = marker
36
+ end
37
+ markers_x[marker_count - 2] = (1 + quartileList[quartile_count - 1]) / 2
38
+ markers_x[marker_count - 1] = 1.0
39
+ (0..marker_count-1).each do |i|
40
+ p2_n[i] = i
41
+ end
42
+ end
43
+
44
+ def markers
45
+
46
+ if (count < markers_y.length)
47
+ result = Array.new(count){0.0}
48
+ markers = Array.new(markers_y.length){0.0}
49
+ pw_q_copy = markers_y.clone()
50
+ pw_q_copy.sort!
51
+ j = 0
52
+ (pw_q_copy.length - count .. pw_q_copy.length - 1).each do |i|
53
+ result[j] = pw_q_copy[i]
54
+ j+=1
55
+ end
56
+
57
+ (0..pw_q_copy.length-1).each do |i|
58
+ markers[i] = result[((count - 1) * i * 1.0 / (pw_q_copy.length - 1)).round]
59
+ end
60
+ return markers;
61
+ end
62
+
63
+ return markers_y;
64
+ end
65
+
66
+ def binarySearch(arr, key)
67
+ low = 0
68
+ high = arr.length-1
69
+
70
+ while(low <=high) do
71
+ mid = (low + high) >> 1
72
+ midVal = arr[mid]
73
+ if (midVal < key)
74
+ low = mid + 1
75
+ elsif(midVal > key)
76
+ high = mid - 1
77
+ else
78
+ midBits = midVal.round 16
79
+ keyBits = key.round 16
80
+ if (midBits == keyBits)
81
+ return mid
82
+ elsif(midBits < keyBits)
83
+ low = mid + 1
84
+ else
85
+ high = mid - 1
86
+ end
87
+ end
88
+ end
89
+ return -(low + 1)
90
+ end
91
+
92
+ def quadPred(d, i)
93
+ qi = markers_y[i]
94
+ qip1 = markers_y[i + 1]
95
+ qim1 = markers_y[i - 1]
96
+ ni = p2_n[i]
97
+ nip1 = p2_n[i + 1]
98
+ nim1 = p2_n[i - 1]
99
+
100
+ a = (ni - nim1 + d) * (qip1 - qi) / (nip1 - ni)
101
+ b = (nip1 - ni - d) * (qi - qim1) / (ni - nim1)
102
+ return qi + (d * (a + b)) / (nip1 - nim1)
103
+ end
104
+
105
+
106
+ def linPred(d, i)
107
+ qi = markers_y[i]
108
+ qipd = markers_y[i + d]
109
+ ni = p2_n[i]
110
+ nipd = p2_n[i + d]
111
+
112
+ return qi + d * (qipd - qi) / (nipd - ni)
113
+ end
114
+
115
+ def add(v)
116
+
117
+ return unless v.is_a?(Numeric)
118
+ obsIdx = count
119
+ @count += 1
120
+
121
+ if (obsIdx < markers_y.length)
122
+ markers_y[obsIdx] = v
123
+ if (obsIdx == markers_y.length - 1)
124
+ markers_y.sort!
125
+ end
126
+ else
127
+
128
+
129
+ # k = markers_y.find_index {|i| i==v or i>v}
130
+ #
131
+ # if k ##in
132
+ # if v==markers_y[k] ##exist
133
+ # if k == 0##first
134
+ # markers_y[0] = v
135
+ # k = 1
136
+ # elsif k == markers_y.length-1 ##last
137
+ # k = markers_y.length - 1;
138
+ # markers_y[k] = v
139
+ # end
140
+ # end
141
+ # else
142
+ # k = markers_y.length -1
143
+ # end
144
+ k = binarySearch markers_y, v
145
+
146
+ if k< 0
147
+ k = -(k + 1)
148
+ end
149
+ if k==0
150
+ markers_y[0] = v
151
+ k = 1
152
+ elsif k == markers_y.length
153
+ k = markers_y.length - 1
154
+ markers_y[k] = v
155
+ end
156
+
157
+ (k..p2_n.length-1).each do |i|
158
+ p2_n[i] += 1
159
+ end
160
+
161
+ (1..markers_y.length - 2).each do |i|
162
+
163
+ n_ = markers_x[i] * obsIdx
164
+ di = n_ - p2_n[i]
165
+ if ((di-1.0 >=0.000001 && p2_n[i + 1] - p2_n[i] > 1) || ((di+1.0 <=0.000001 && p2_n[i - 1] - p2_n[i] < -1)))
166
+ d = di < 0 ? -1 : 1
167
+ qi_ = quadPred(d, i)
168
+ if (qi_ < markers_y[i - 1] || qi_ > markers_y[i + 1])
169
+
170
+ qi_ = linPred(d, i)
171
+ end
172
+
173
+ markers_y[i] = qi_
174
+
175
+ p2_n[i] += d
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+ #
184
+ # testdata4 =[0.0, 3009.0, 3046.0, 3070.0, 3102.0, 3119.0, 3139.0, 3150.0, 3163.0, 3179.0, 3228.0]
185
+ # testdata3 =[2,1,6,6,4,9,5,6,2,7,2,4,9,7,8,4,1,8,8,8,3,5,4,1,9,5,5,6,2,0,8,5,3,6,1,4,8,0,0,1,1,3,9,9,6,7,1,5,8,7,6,9,3,1,2,4,8,2,3,4,7,2,9,2,3,9,8,7,6,1,8,5,0,8,3,2,8,0,1,7,4,9,9,3,6,2,3,0,1,4,9,3,0,9,6,1,9,7,1,9,3,4,4,0,9,6,2,6,1,4,9,9,2,2,3,0,2,0,4,4,1,9,2,7,8,9,6,5,6,5,1,4,3,6,4,7,6,6,5,6,2,2,5,4,8,6,3,4,7,2,4,8,7,0,0,0,9,6,5,2,8,3,2,1,9,2,4,0,3,2,3,6,6,6,4,8,1,0,7,7,2,8,5,1,3,0,5,3,3,3,3,8,8,7,9,1,3,3,1,1,0,5,2,2,4,9,3,3,5,7,4,0,7,4,2,6,3,2,5,4,9,0,8,8,0,6,7,0,2,3,3,4,7,9,9,7,8,5,1,4,5,0,8,5,8,7,0,7,3,9,5,0,7,1,2,6,8,3,3,6,0,6,0,0,4,5,6,3,6,8,6,3,2,8,9,1,9,3,8,6,3,5,9,0,3,6,2,9,1,1,0,6,4,1,0,9,3,2,9,5,6,3,7,8,3,4,1,0,8,1,3,0,3,3,9,9,7,2,1,3,5,6,6,9,5,1,9,8,8,7,0,7,3,9,3,1,6,1,7,3,3,3,9,9,8,4,3,8,1,2,0,1,9,6,3,2,2,5,5,7,3,4,2,2,7,5,4,7,0,6,4,3,6,4,2,9,3,4,8,7,8,2,1,6,6,7,0,7,8,4,8,0,1,6,9,9,5,5,7,5,6,7,4,8,7,6,7,1,1,1,1,9,2,2,0,3,4,0,6,9,9,1,8,5,0,5,5,4,7,6,5,6,2,1,2,5,0,6,3,7,3,6,1,3,1,0,5,3,9,2,9,9,8,0,9,5,3,9,6,8,0,0,2,5,3,1,3,4,2,9,4,3,0,8,1,7,0,5,3,9,5,3,4,4,1,7,5,5,8,9,8,0,1,0,1,9,7,8,2,3,4,7,5,3,8,7,8,4,1,3,6,6,0,8,8,1,3,5,2,6,0,1,2,1,5,3,5,0,7,0,2,3,9,8,2,5,8,4,8,9,8,7,2,7,7,1,2,3,7,9,7,4,5,2,6,2,3,8,8,8,0,8,4,7,9,2,6,7,5,1,3,0,4,1,3,8,2,8,1,0,5,6,3,5,6,7,9,2,4,5,9,2,9,5,0,6,1,1,0,3,9,2,8,6,6,8,6,3,9,0,0,7,1,9,9,6,4,7,3,0,1,8,1,6,5,7,3,9,7,0,3,7,3,3,6,0,6,3,3,4,7,4,1,3,9,3,2,2,5,0,5,2,5,1,2,3,9,0,9,8,7,9,2,0,9,8,9,0,5,4,4,4,4,3,2,9,0,2,5,8,0,9,4,6,5,0,2,1,8,1,4,8,4,2,0,2,9,7,7,7,1,2,1,3,3,5,1,9,2,3,2,7,6,5,6,9,5,0,7,9,8,3,4,5,1,6,4,6,9,4,5,0,0,0,6,8,3,4,0,7,8,6,9,8,8,9,8,7,8,0,6,5,8,5,4,6,3,5,4,1,0,9,7,2,4,1,7,9,3,4,1,5,7,9,5,8,9,4,6,1,3,5,8,4,0,4,1,4,2,4,3,0,0,8,9,5,2,7,8,2,6,1,9,8,9,9,0,7,9,6,8,8,8,7,4,7,4,3,3,2,5,9,5,3,3,2,3,1,0,5,7,7,2,5,9,3,7,4,1,3,1,5,4,0,5,6,9,1,5,2,4,5,8,5,3,0,1,3,3,4,0,1,0,8,8,0,7,9,1,1,0,5,2,1,2,8,2,6,6,8,2,7,9,5,5,1,2,0,0,5,9,8,8,1,5,7,2,1,2,3,5,5,3,9,4,0,5,2,2,5,0,0,2,5,3,3,5,2,8,9,8,8,6,7,7,9,6,7,0,6,0,6,4,8,7,8,7,4,4,1,0,4,1,9,3,2,1,7,3,1,1,2,3,2,9,5,9,1,8,4,6,6,1,0,9,9,3,4,9,9,0,5,7,0,5,8,2,1,3,4,7,6,0,3,0,7,3,0,1,3,0,1,0,5,2,3,3,4,3,2]
186
+ # testdata2 =[3028.0, 2211.0]
187
+ # testdata1 =[3110,3770,3990,3990,3000,3880,3330,3440,3440,3000,3550,3440,3220,3330,3220,3110,3770,3110,3880,3330,3440,3440,3000,3110,3220,3440,3000,3550,3880,3990,3990,3550,3110,3330,3330,3000,3880,3660,3110,3990,3110,3990,3440,3330,3660,3660,3000,3220,3220,3330,3660,3990,3440,3220,3220,3440,3440,3880,3990,3550,3440,3110,3330,3440,3110,3770,3330,3220,3440,3440,3440,3220,3660,3000,3440,3550,3220,3220,3110,3660,3110,3880,3550,3770,3220,3440,3220,3110,3220,3220,3110,3880,3550,3770,3770,3550,3990,3220,3880,3660,3110,3550,3990,3110,3550,3880,3110,3770,3770,3110,3440,3770,3000,3110,3990,3110,3550,3770,3990,3000,3990,3110,3550,3880,3110,3880,3550,3220,3550,3550,3770,3990,3550,3220,3330,3990,3770,3770,3550,3770,3880,3660,3330,3990,3990,3000,3110,3440,3220,3000,3550,3770,3110,3550,3330,3990,3110,3330,3550,3440,3220,3550,3220,3330,3000,3660,3110,3770,3110,3660,3550,3440,3990,3330,3990,3550,3990,3550,3330,3770,3550,3550,3000,3440,3000,3330,3440,3110,3880,3110,3550,3660,3990,3220,3330,3330,3000,3660,3660,3220]
188
+ # testdatas =[testdata1.map(&:to_f),testdata2,testdata3.map(&:to_f),testdata4]
189
+ # quartileList =[1.0/7*2,1.0/7*3,1.0/7*4,1.0/7*5 ]
190
+ #
191
+ # qm=::TingYun::Support::QuantileP2.new(quartileList)
192
+ # # testdatas.each do |testdata|
193
+ # # qp=::TingYun::Support::QuantileP2.new(quartileList)
194
+ # # testdata.each do |da|
195
+ # # qp.add(da)
196
+ # # p qp.markers
197
+ # # p "---------"
198
+ # # end
199
+ # # end
200
+ # testdata4.each do |da|
201
+ # qm.add(da.to_f)
202
+ # end
203
+ #
204
+ # p qm.markers