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,170 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under Ting Yun's license terms.
3
+
4
+ module TingYun
5
+ module Agent
6
+ module Collector
7
+ class StatsEngine
8
+ module MetricStats
9
+ # Handles methods related to actual Metric collection
10
+
11
+ SCOPE_PLACEHOLDER = '__SCOPE__'.freeze
12
+
13
+ # Update the unscoped metrics given in metric_names.
14
+ # metric_names may be either a single name, or an array of names.
15
+ #
16
+ # This is an internal method, subject to change at any time. Client apps
17
+ # and gems should use the public API (TingYun::Agent.record_metric)
18
+ # instead.
19
+ #
20
+ # There are four ways to use this method:
21
+ #
22
+ # 1. With a numeric value, it will update the Stats objects associated
23
+ # with the given metrics by calling record_data_point(value, aux).
24
+ # aux will be treated in this case as the exclusive time associated
25
+ # with the call being recorded.
26
+ #
27
+ # 2. With a value of :apdex_s, :apdex_t, or :apdex_f, it will treat the
28
+ # associated stats as an Apdex metric, updating it to reflect the
29
+ # occurrence of a transaction falling into the given category.
30
+ # The aux value in this case should be the apdex threshold used in
31
+ # bucketing the request.
32
+ #
33
+ # 3. If a block is given, value and aux will be ignored, and instead the
34
+ # Stats object associated with each named unscoped metric will be
35
+ # yielded to the block for customized update logic.
36
+ #
37
+ # 4. If value is a Stats instance, it will be merged into the Stats
38
+ # associated with each named unscoped metric.
39
+ #
40
+ # If this method is called during a transaction, the metrics will be
41
+ # attached to the Transaction, and not merged into the global set until
42
+ # the end of the transaction.
43
+ #
44
+ # Otherwise, the metrics will be recorded directly into the global set
45
+ # of metrics, under a lock.
46
+ #
47
+ # @api private
48
+ #
49
+
50
+
51
+ def tl_record_unscoped_metrics(metric_names, value=nil, aux=nil, &blk)
52
+ state = TingYun::Agent::TransactionState.tl_get
53
+ record_unscoped_metrics(state, metric_names, value, aux, &blk)
54
+ end
55
+
56
+ def record_unscoped_metrics(state, metric_names, value=nil, aux=nil, &blk)
57
+ txn = state.current_transaction
58
+
59
+ if txn
60
+ txn.metrics.record_unscoped(metric_names, value, aux, &blk)
61
+ else
62
+ specs = coerce_to_metric_spec_array(metric_names, nil)
63
+ with_stats_lock do
64
+ @stats_hash.record(specs, value, aux, &blk)
65
+ end
66
+ end
67
+ end
68
+
69
+ # Like tl_record_unscoped_metrics, but records a scoped metric as well.
70
+ #
71
+ # This is an internal method, subject to change at any time. Client apps
72
+ # and gems should use the public API (TingYun::Agent.record_metric)
73
+ # instead.
74
+ #
75
+ # The given scoped_metric will be recoded as both a scoped *and* an
76
+ # unscoped metric. The summary_metrics will be recorded as unscoped
77
+ # metrics only.
78
+ #
79
+ # If called during a transaction, all metrics will be attached to the
80
+ # Transaction, and not merged into the global set of metrics until the
81
+ # end of the transaction.
82
+ #
83
+ # If called outside of a transaction, only the *unscoped* metrics will
84
+ # be recorded, directly into the global set of metrics (under a lock).
85
+ #
86
+ # @api private
87
+
88
+ def tl_record_scoped_and_unscoped_metrics(scoped_metric, summary_metrics=nil, value=nil, aux=nil, &blk)
89
+ state = TingYun::Agent::TransactionState.tl_get
90
+ record_scoped_and_unscoped_metrics(state, scoped_metric, summary_metrics, value, aux, &blk)
91
+ end
92
+
93
+ def record_scoped_and_unscoped_metrics(state, scoped_metric, summary_metrics=nil, value=nil, aux=nil ,&blk)
94
+ txn = state.current_transaction
95
+
96
+ if txn
97
+ txn.metrics.record_scoped(scoped_metric, value, aux, &blk)
98
+ txn.metrics.record_unscoped(scoped_metric, value, aux, &blk)
99
+ if summary_metrics
100
+ txn.metrics.record_unscoped(summary_metrics, value, aux, &blk)
101
+ end
102
+ else
103
+ specs = coerce_to_metric_spec_array(scoped_metric, nil)
104
+ if summary_metrics
105
+ specs.concat(coerce_to_metric_spec_array(summary_metrics, nil))
106
+ end
107
+ with_stats_lock do
108
+ @stats_hash.record(specs, value, aux, &blk)
109
+ end
110
+ end
111
+ end
112
+
113
+ def coerce_to_metric_spec_array(metric_names_or_specs, scope)
114
+ specs = []
115
+ Array(metric_names_or_specs).map do |name_or_spec|
116
+ case name_or_spec
117
+ when String
118
+ specs << TingYun::Metrics::MetricSpec.new(name_or_spec)
119
+ specs << TingYun::Metrics::MetricSpec.new(name_or_spec, scope) if scope
120
+ when TingYun::Metrics::MetricSpec
121
+ specs << name_or_spec
122
+ end
123
+ end
124
+ specs
125
+ end
126
+
127
+ def reset!
128
+ with_stats_lock do
129
+ old = @stats_hash
130
+ @stats_hash = StatsHash.new
131
+ old
132
+ end
133
+ end
134
+
135
+ def harvest!
136
+ now = Time.now
137
+ snapshot = reset!
138
+ snapshot.harvested_at = now
139
+ snapshot
140
+ end
141
+
142
+ # Renamed to reset!, here for backwards compatibility with 3rd-party
143
+ # gems (though this really isn't part of the public API).
144
+ # @deprecated
145
+ def reset_stats; reset!; end
146
+
147
+ # merge data from previous harvests into this stats engine
148
+ def merge!(other_stats_hash)
149
+ with_stats_lock do
150
+ @stats_hash.merge!(other_stats_hash)
151
+ @stats_hash
152
+ end
153
+ end
154
+
155
+ # For use by test code only.
156
+ def to_h
157
+ with_stats_lock { @stats_hash.to_h }
158
+ end
159
+
160
+ def merge_transaction_metrics!(txn_metrics, scope)
161
+ with_stats_lock do
162
+ @stats_hash.merge_transaction_metrics!(txn_metrics, scope)
163
+ end
164
+ end
165
+
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,172 @@
1
+ # encoding: utf-8
2
+
3
+
4
+ # A Hash-like class for storing perfMetrics data.
5
+ #
6
+ # Internally, metrics are split into unscoped and scoped collections.
7
+ #
8
+ # Unscoped metrics are stored in a Hash, keyed by Strings representing the name
9
+ # of the metrics.
10
+ #
11
+ # Scoped metrics are stored in a Hash where the keys are TingYun::Metrics::MetricSpec
12
+ # objects (effectively <name, scope> tuples).
13
+ #
14
+ # Values in both hashes are TingYun::Metrics::Stats objects.
15
+ #
16
+ # Missing keys will be automatically created as empty TingYun::Metrics::Stats
17
+ # instances, so use has_key? explicitly to check for key existence.
18
+ #
19
+ # Note that instances of this class are intended to be append-only with respect
20
+ # to new metrics. That is, you should not attempt to *remove* an entry after it
21
+ # has been added, only update it (create a new instance if you need to start
22
+ # over with a blank slate).
23
+ #
24
+ # This class makes no provisions for safe usage from multiple threads, such
25
+ # measures should be externally provided.
26
+
27
+ require 'ting_yun/metrics/stats'
28
+ require 'ting_yun/metrics/metric_spec'
29
+ require 'ting_yun/support/exception'
30
+
31
+ module TingYun
32
+ module Agent
33
+ module Collector
34
+ class StatsHash
35
+
36
+ attr_accessor :started_at, :harvested_at
37
+
38
+ def initialize(started_at=Time.now)
39
+ @started_at = started_at.to_f
40
+ @scoped = Hash.new { |h, k| h[k] = TingYun::Metrics::Stats.new }
41
+ @unscoped = Hash.new { |h, k| h[k] = TingYun::Metrics::Stats.new }
42
+ end
43
+
44
+ def marshal_dump
45
+ [@started_at, Hash[@scoped], Hash[@unscoped]]
46
+ end
47
+
48
+ def marshal_load(data)
49
+ @started_at = data.shift
50
+ @scoped = Hash.new { |h, k| h[k] = TingYun::Metrics::Stats.new }
51
+ @unscoped = Hash.new { |h, k| h[k] = TingYun::Metrics::Stats.new }
52
+ @scoped.merge!(data.shift)
53
+ @unscoped.merge!(data.shift)
54
+ end
55
+
56
+ def ==(other)
57
+ self.to_h == other.to_h
58
+ end
59
+
60
+ def to_h
61
+ hash = {}
62
+ @scoped.each { |k, v| hash[k] = v }
63
+ @unscoped.each { |k, v| hash[TingYun::Metrics::MetricSpec.new(k)] = v }
64
+ hash
65
+ end
66
+
67
+ def [](key)
68
+ case key
69
+ when String
70
+ @unscoped[key]
71
+ when TingYun::Metrics::MetricSpec
72
+ if key.scope.empty?
73
+ @unscoped[key.name]
74
+ else
75
+ @scoped[key]
76
+ end
77
+ end
78
+ end
79
+
80
+ def each
81
+ @scoped.each do |k, v|
82
+ yield k, v
83
+ end
84
+ @unscoped.each do |k, v|
85
+ spec = TingYun::Metrics::MetricSpec.new(k)
86
+ yield spec, v
87
+ end
88
+ end
89
+
90
+ def empty?
91
+ @unscoped.empty? && @scoped.empty?
92
+ end
93
+
94
+ def size
95
+ @unscoped.size + @scoped.size
96
+ end
97
+
98
+ def merge!(other)
99
+ @started_at = other.started_at if other.started_at < @started_at
100
+
101
+ other.each do |spec, val|
102
+ if spec.scope.empty?
103
+ merge_or_insert(@unscoped, spec.name, val)
104
+ else
105
+ merge_or_insert(@scoped, spec, val)
106
+ end
107
+ end
108
+ self
109
+ end
110
+
111
+ class StatsHashLookupError < TingYun::Support::Exception::InternalAgentError
112
+ def initialize(original_error, hash, metric_spec)
113
+ super("Lookup error in StatsHash: #{original_error.class}: #{original_error.message}. Falling back adding #{metric_spec.inspect}")
114
+ end
115
+ end
116
+
117
+ def record(metric_specs, value=nil, aux=nil, &blk)
118
+ Array(metric_specs).each do |metric_spec|
119
+ if metric_spec.scope.empty?
120
+ key = metric_spec.name
121
+ hash = @unscoped
122
+ else
123
+ key = metric_spec
124
+ hash = @scoped
125
+ end
126
+
127
+ begin
128
+ stats = hash[key]
129
+ rescue NoMethodError => e
130
+ stats = handle_stats_lookup_error(key, hash, e)
131
+ end
132
+
133
+ stats.record(value, aux, &blk)
134
+ end
135
+ end
136
+
137
+ def merge_transaction_metrics!(txn_metrics, scope)
138
+
139
+ txn_metrics.each_unscoped do |name, stats|
140
+ merge_or_insert(@unscoped, name, stats)
141
+ end
142
+ txn_metrics.each_scoped do |name, stats|
143
+ spec = TingYun::Metrics::MetricSpec.new(name, scope)
144
+ merge_or_insert(@scoped, spec, stats)
145
+ end
146
+ end
147
+
148
+ def merge_or_insert(target, name, stats)
149
+ if target.has_key?(name)
150
+ target[name].merge!(stats)
151
+ else
152
+ target[name] = stats
153
+ end
154
+ end
155
+
156
+ def handle_stats_lookup_error(key, hash, error)
157
+ # This only happen in the case of a corrupted default_proc
158
+ # Side-step it manually, notice the issue, and carry on....
159
+ ::TingYun::Agent.instance.error_collector. \
160
+ notice_agent_error(StatsHashLookupError.new(error, hash, key))
161
+ stats = TingYun::Metrics::Stats.new
162
+ hash[key] = stats
163
+ # Try to restore the default_proc so we won't continually trip the error
164
+ if hash.respond_to?(:default_proc=)
165
+ hash.default_proc = Proc.new { |h, k| h[k] = TingYun::Metrics::Stats.new }
166
+ end
167
+ stats
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ require 'ting_yun/agent/collector/stats_engine/stats_hash'
4
+ require 'ting_yun/agent/collector/stats_engine/metric_stats'
5
+
6
+ module TingYun
7
+ module Agent
8
+ module Collector
9
+ # This class handles all the statistics gathering for the agent
10
+ class StatsEngine
11
+
12
+ include MetricStats
13
+
14
+
15
+ def initialize
16
+ @stats_lock = Mutex.new
17
+ @stats_hash = StatsHash.new
18
+ end
19
+
20
+ # All access to the @stats_hash ivar should be funnelled through this
21
+ # method to ensure thread-safety.
22
+ def with_stats_lock
23
+ @stats_lock.synchronize { yield }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under Ting Yun's license terms.
3
+
4
+ require 'ting_yun/agent/collector/transaction_sampler/transaction_sample_buffer_base'
5
+ module TingYun
6
+ module Agent
7
+ module Collector
8
+ class TransactionSampler
9
+ class SlowestSampleBuffer < TransactionSampleBufferBase
10
+
11
+ CAPACITY = 1
12
+
13
+ def capacity
14
+ CAPACITY
15
+ end
16
+
17
+ def allow_sample?(sample)
18
+ sample.threshold && sample.duration >= sample.threshold
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under Ting Yun's license terms.
3
+
4
+ module TingYun
5
+ module Agent
6
+ module Collector
7
+ class TransactionSampler
8
+ class TransactionSampleBufferBase
9
+
10
+ SINGLE_BUFFER_MAX = 20
11
+ NO_SAMPLES = [].freeze
12
+
13
+ def initialize
14
+ @samples = []
15
+ end
16
+
17
+ #If a buffer needs to modify, override this method.
18
+ def allow_sample?(sample)
19
+ true
20
+ end
21
+
22
+ #If a buffer needs to modify, override this method.
23
+ def enabled?
24
+ true
25
+ end
26
+
27
+ def reset!
28
+ @samples = []
29
+ end
30
+
31
+ def harvest_samples
32
+ @samples
33
+ ensure
34
+ reset!
35
+ end
36
+
37
+ def store(sample)
38
+ return unless enabled?
39
+ if allow_sample?(sample)
40
+ add_sample(sample)
41
+ truncate_samples_if_needed
42
+ end
43
+ end
44
+
45
+ def store_previous(previous_samples)
46
+ return unless enabled?
47
+ previous_samples.each do |sample|
48
+ add_sample(sample) if allow_sample?(sample)
49
+ end
50
+ truncate_samples_if_needed
51
+ end
52
+
53
+ def truncate_samples_if_needed
54
+ truncate_samples if full?
55
+ end
56
+
57
+ def full?
58
+ @samples.length >= max_capacity
59
+ end
60
+
61
+
62
+ # Capacity is the desired number of samples a buffer will hold. This
63
+ # can be user dictated via config if a feature wants.
64
+ #
65
+ # This value will be forcibly capped by the max_capacity
66
+ def capacity
67
+ raise NotImplementedError.new("TransactionSampleBufferBase subclasses must provide a capacity override")
68
+ end
69
+
70
+ def max_capacity
71
+ capacity > SINGLE_BUFFER_MAX ? SINGLE_BUFFER_MAX : capacity
72
+ end
73
+
74
+ # Our default truncation strategy is to keep max_capacity
75
+ # worth of the longest samples. Override this method for alternate
76
+ # behavior.
77
+ def truncate_samples
78
+ @samples.sort!{|a,b| a.duration <=> b.duration}
79
+ @samples.slice!(0..-(max_capacity + 1))
80
+ end
81
+
82
+
83
+ private
84
+
85
+ # If a buffer needs to modify an added sample, override this method.
86
+ # Bounds checking, allowing samples and truncation belongs elsewhere.
87
+ def add_sample(sample)
88
+ @samples << sample
89
+ end
90
+
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+