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,70 @@
1
+ # encoding: utf-8
2
+
3
+
4
+
5
+ TingYun::Support::LibraryDetection.defer do
6
+ named :redis
7
+
8
+ depends_on do
9
+ defined?(::Redis)
10
+ end
11
+
12
+
13
+ executes do
14
+ TingYun::Agent.logger.info 'Installing Redis Instrumentation'
15
+ require 'ting_yun/agent/transaction/transaction_state'
16
+ end
17
+
18
+ executes do
19
+ require 'ting_yun/agent/datastore'
20
+
21
+ ::Redis::Client.class_eval do
22
+
23
+ def record_redis_duration(_1, _2, duration)
24
+ state = TingYun::Agent::TransactionState.tl_get
25
+ unless state.nil?
26
+ state.rds_duration += duration * 1000
27
+ end
28
+ end
29
+
30
+ call_method = ::Redis::Client.new.respond_to?(:call) ? :call : :raw_call_command
31
+
32
+ def call_with_tingyun_trace(*args, &blk)
33
+ operation = args[0].is_a?(Array) ? args[0][0] : args[0]
34
+
35
+ TingYun::Agent::Datastore.wrap("Redis", operation, nil, method(:record_redis_duration)) do
36
+ call_without_tingyun_trace(*args, &blk)
37
+ end
38
+ end
39
+
40
+ alias_method :call_without_tingyun_trace, call_method
41
+ alias_method call_method, :call_with_tingyun_trace
42
+
43
+
44
+ if public_method_defined? :call_pipelined
45
+ def call_pipelined_with_tingyun_trace(*args, &block)
46
+ pipeline = args[0]
47
+ operation = pipeline.is_a?(::Redis::Pipeline::Multi) ? 'multi' : 'pipeline'
48
+
49
+ TingYun::Agent::Datastore.wrap("Redis", operation, nil, method(:record_redis_duration)) do
50
+ call_pipelined_without_tingyun_trace(*args, &block)
51
+ end
52
+ end
53
+
54
+ alias_method :call_pipelined_without_tingyun_trace, :call_pipelined
55
+ alias_method :call_pipelined, :call_pipelined_with_tingyun_trace
56
+ end
57
+
58
+ if public_method_defined? :connect
59
+
60
+ alias_method :connect_without_tingyun, :connect
61
+
62
+ def connect(*args, &block)
63
+ TingYun::Agent::Datastore.wrap("Redis", "connect", nil, method(:record_redis_duration)) do
64
+ connect_without_tingyun(*args, &block)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,178 @@
1
+ # encoding: utf-8
2
+
3
+
4
+ require 'ting_yun/instrumentation/support/database'
5
+ require 'ting_yun/agent/datastore/metric_helper'
6
+ require 'ting_yun/agent'
7
+ module TingYun
8
+ module Instrumentation
9
+ module Support
10
+ module ActiveRecordHelper
11
+ module_function
12
+
13
+
14
+ ACTIVE_RECORD = "ActiveRecord".freeze unless defined?(ACTIVE_RECORD)
15
+
16
+ # Used by both the AR 3.x and 4.x instrumentation
17
+ def instrument_additional_methods
18
+ instrument_save_methods
19
+ instrument_relation_methods
20
+ end
21
+
22
+ def instrument_save_methods
23
+ ::ActiveRecord::Base.class_eval do
24
+ alias_method :save_without_tingyun, :save
25
+
26
+ def save(*args, &blk)
27
+ ::TingYun::Agent.with_database_metric_name(self.class.name, nil, ACTIVE_RECORD) do
28
+ save_without_tingyun(*args, &blk)
29
+ end
30
+ end
31
+
32
+ alias_method :save_without_tingyun!, :save!
33
+
34
+ def save!(*args, &blk)
35
+ ::TingYun::Agent.with_database_metric_name(self.class.name, nil, ACTIVE_RECORD) do
36
+ save_without_tingyun!(*args, &blk)
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def instrument_relation_methods
43
+
44
+ ::ActiveRecord::Relation.class_eval do
45
+ alias_method :update_all_without_tingyun, :update_all
46
+
47
+ def update_all(*args, &blk)
48
+ ::TingYun::Agent.with_database_metric_name(self.name, nil, ACTIVE_RECORD) do
49
+ update_all_without_tingyun(*args, &blk)
50
+ end
51
+ end
52
+
53
+ alias_method :delete_all_without_tingyun, :delete_all
54
+
55
+ def delete_all(*args, &blk)
56
+ ::TingYun::Agent.with_database_metric_name(self.name, nil, ACTIVE_RECORD) do
57
+ delete_all_without_tingyun(*args, &blk)
58
+ end
59
+ end
60
+
61
+ alias_method :destroy_all_without_tingyun, :destroy_all
62
+
63
+ def destroy_all(*args, &blk)
64
+ ::TingYun::Agent.with_database_metric_name(self.name, nil, ACTIVE_RECORD) do
65
+ destroy_all_without_tingyun(*args, &blk)
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ def metrics_for(name, sql, adapter_name)
72
+ product = map_product(adapter_name)
73
+ splits = split_name(name)
74
+ model = model_from_splits(splits) || product
75
+ operation = operation_from_splits(splits, sql)
76
+
77
+ TingYun::Agent::Datastore::MetricHelper.metrics_for(product, operation, model, ACTIVE_RECORD)
78
+ end
79
+
80
+
81
+ SPACE = ' '.freeze unless defined?(SPACE)
82
+ EMPTY = [].freeze unless defined?(EMPTY)
83
+
84
+ def split_name(name)
85
+ if name && name.respond_to?(:split)
86
+ name.split(SPACE)
87
+ else
88
+ EMPTY
89
+ end
90
+ end
91
+
92
+ def model_from_splits(splits)
93
+ if splits.length == 2
94
+ splits.first
95
+ else
96
+ nil
97
+ end
98
+ end
99
+
100
+ def operation_from_splits(splits, sql)
101
+ if splits.length == 2
102
+ map_operation(splits[1])
103
+ else
104
+ TingYun::Instrumentation::Support::Database.parse_operation_from_query(sql)
105
+ end
106
+ end
107
+
108
+ # These are used primarily to optimize and avoid allocation on well
109
+ # known operations coming in. Anything not matching the list is fine,
110
+ # it just needs to get downcased directly for use.
111
+ OPERATION_NAMES = {
112
+ 'Find' => 'SELECT',
113
+ 'Load' => 'SELECT',
114
+ 'Count' => 'SELECT',
115
+ 'Exists' => 'SELECT',
116
+ 'Create' => 'INSERT',
117
+ 'Columns' => 'SELECT',
118
+ 'Indexes' => 'SELECT',
119
+ 'Destroy' => 'DELETE',
120
+ 'Update' => 'UPDATE',
121
+ 'Save' => 'INSERT'
122
+ }.freeze unless defined?(OPERATION_NAMES)
123
+
124
+ def map_operation(raw_operation)
125
+ direct_op = OPERATION_NAMES[raw_operation]
126
+ return direct_op if direct_op
127
+
128
+ # raw_operation.upcase
129
+ end
130
+
131
+ PRODUCT_NAMES = {
132
+ "mysql" => "MySQL",
133
+ "mysql2" => "MySQL",
134
+
135
+ "postgresql" => "Postgres",
136
+
137
+ "sqlite3" => "SQLite",
138
+
139
+ # https://rubygems.org/gems/activerecord-jdbcpostgresql-adapter
140
+ "jdbcmysql" => "MySQL",
141
+
142
+ # https://rubygems.org/gems/activerecord-jdbcpostgresql-adapter
143
+ "jdbcpostgresql" => "Postgres",
144
+
145
+ # https://rubygems.org/gems/activerecord-jdbcsqlite3-adapter
146
+ "jdbcsqlite3" => "SQLite",
147
+
148
+ # https://rubygems.org/gems/activerecord-jdbcderby-adapter
149
+ "derby" => "Derby",
150
+ "jdbcderby" => "Derby",
151
+
152
+ # https://rubygems.org/gems/activerecord-jdbc-adapter
153
+ "jdbc" => "JDBC",
154
+
155
+ # https://rubygems.org/gems/activerecord-jdbcmssql-adapter
156
+ "jdbcmssql" => "MSSQL",
157
+ "mssql" => "MSSQL",
158
+
159
+ # https://rubygems.org/gems/activerecord-sqlserver-adapter
160
+ "sqlserver" => "MSSQL",
161
+
162
+ # https://rubygems.org/gems/activerecord-odbc-adapter
163
+ "odbc" => "ODBC",
164
+
165
+ # https://rubygems.org/gems/activerecord-oracle_enhanced-adapter
166
+ "oracle_enhanced" => "Oracle"
167
+ }.freeze unless defined?(PRODUCT_NAMES)
168
+
169
+ DEFAULT_PRODUCT_NAME = "Database".freeze unless defined?(DEFAULT_PRODUCT_NAME)
170
+
171
+ def map_product(adapter_name)
172
+ PRODUCT_NAMES.fetch(adapter_name, DEFAULT_PRODUCT_NAME)
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+
3
+ require 'ting_yun/agent/transaction/transaction_state'
4
+ require 'ting_yun/instrumentation/support/transaction_namer'
5
+ require 'ting_yun/agent/transaction'
6
+ require 'ting_yun/agent'
7
+
8
+
9
+ module TingYun
10
+ module Instrumentation
11
+ module Support
12
+ module ControllerInstrumentation
13
+
14
+ NR_DEFAULT_OPTIONS = {}.freeze unless defined?(NR_DEFAULT_OPTIONS )
15
+
16
+ def perform_action_with_tingyun_trace (*args, &block)
17
+
18
+ state = TingYun::Agent::TransactionState.tl_get
19
+
20
+ state.request = self.request
21
+ trace_options = args.last.is_a?(Hash) ? args.last : NR_DEFAULT_OPTIONS
22
+ category = trace_options[:category] || :controller
23
+ txn_options = create_transaction_options(trace_options, category, state)
24
+
25
+ begin
26
+ txn = TingYun::Agent::Transaction.start(state, category, txn_options)
27
+ begin
28
+ yield
29
+ rescue => e
30
+ ::TingYun::Agent.notice_error(e)
31
+ raise
32
+ end
33
+ ensure
34
+ TingYun::Agent::Transaction.stop(state)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def create_transaction_options(trace_options, category, state)
41
+ txn_options = {}
42
+
43
+ txn_options[:request] ||= request if respond_to?(:request)
44
+ txn_options[:filtered_params] = trace_options[:params]
45
+ txn_options[:transaction_name] = TingYun::Instrumentation::Support::TransactionNamer.name_for(nil, self, category, trace_options)
46
+ txn_options[:apdex_start_time] = Time.now
47
+
48
+ txn_options
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ require 'ting_yun/support/helper'
4
+
5
+ module TingYun
6
+ module Instrumentation
7
+ module Support
8
+ module Database
9
+ extend self
10
+
11
+ KNOWN_OPERATIONS = [
12
+ 'SELECT',
13
+ 'UPDATE',
14
+ 'DELETE',
15
+ 'INSERT',
16
+ 'SHOW',
17
+ 'CALL'
18
+ ]
19
+
20
+ SQL_COMMENT_REGEX = Regexp.new('/\*.*?\*/', Regexp::MULTILINE).freeze
21
+ EMPTY_STRING = ''.freeze
22
+
23
+ def parse_operation_from_query(sql)
24
+ sql =TingYun::Helper.correctly_encoded(sql).gsub(SQL_COMMENT_REGEX, EMPTY_STRING)
25
+ if sql =~ /(\w+)/
26
+ op = $1.upcase
27
+ if KNOWN_OPERATIONS.include?(op)
28
+ return op
29
+ else
30
+ return "CALL"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module TingYun
4
+ module Instrumentation
5
+ module Support
6
+ module EventFormatter
7
+ def self.format(command_name, database_name, command)
8
+ result = {
9
+ :operation => command_name,
10
+ :database => database_name,
11
+ :collection => command.values.first,
12
+ :term => command.values.last
13
+ }
14
+ result
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,97 @@
1
+
2
+ module TingYun
3
+ module Instrumentation
4
+ module Support
5
+ class EventedSubscriber
6
+ def initialize
7
+ @queue_key = ['TingYun', self.class.name, object_id].join('-')
8
+ end
9
+
10
+ def self.subscribed?
11
+ # rather than digging through Listener ivars
12
+ ActiveSupport::Notifications.notifier.instance_variable_get(:@subscribers) \
13
+ .find{|s| s.instance_variable_get(:@delegate).class == self }
14
+ end
15
+
16
+ def self.subscribe(pattern)
17
+ unless subscribed?
18
+ ActiveSupport::Notifications.subscribe(pattern, new)
19
+ end
20
+ end
21
+
22
+ def start(name, id, payload)
23
+ event = ActiveSupport::Notifications::Event.new(name, Time.now, nil, id, payload)
24
+ push_event(event)
25
+ event
26
+ end
27
+
28
+ def finish(name, id, payload)
29
+ pop_event(id)
30
+ end
31
+
32
+ def log_notification_error(error, name, event_type)
33
+ # These are important enough failures that we want the backtraces
34
+ # logged at error level, hence the explicit log_exception call.
35
+ TingYun::Agent.logger.error("Error during #{event_type} callback for event '#{name}':")
36
+ TingYun::Agent.logger.log_exception(:error, error)
37
+ end
38
+
39
+ def push_event(event)
40
+ parent = event_stack[event.transaction_id].last
41
+ if parent && event.respond_to?(:parent=)
42
+ event.parent = parent
43
+ parent << event
44
+ end
45
+ event_stack[event.transaction_id].push event
46
+ end
47
+
48
+ def pop_event(transaction_id)
49
+ event = event_stack[transaction_id].pop
50
+ event.end = Time.now
51
+ event
52
+ end
53
+
54
+ def event_stack
55
+ Thread.current[@queue_key] ||= Hash.new {|h,id| h[id] = [] }
56
+ end
57
+ end
58
+
59
+ # Taken from ActiveSupport::Notifications::Event, pasted here
60
+ # with a couple minor additions so we don't have a hard
61
+ # dependency on ActiveSupport::Notifications.
62
+ #
63
+ # Represents an intrument event, provides timing and metric
64
+ # name information useful when recording metrics.
65
+ class Event
66
+ attr_reader :name, :time, :transaction_id, :payload, :children
67
+ attr_accessor :end, :parent, :frame
68
+
69
+ def initialize(name, start, ending, transaction_id, payload, _=nil)
70
+ @name = name
71
+ @payload = payload.dup
72
+ @time = start
73
+ @transaction_id = transaction_id
74
+ @end = ending
75
+ @children = []
76
+ end
77
+
78
+ def metric_name
79
+ raise NotImplementedError
80
+ end
81
+
82
+ def duration
83
+ (self.end - time)*1000
84
+ end
85
+
86
+ def <<(event)
87
+ @children << event
88
+ end
89
+
90
+ def parent_of?(event)
91
+ @children.include? event
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+ require 'ting_yun/agent'
3
+ require 'ting_yun/support/exception'
4
+
5
+ module TingYun
6
+ module Instrumentation
7
+ module Support
8
+ module ExternalError
9
+
10
+
11
+ module_function
12
+
13
+ def capture_exception(response,request,type)
14
+ if !response.nil? && response.code =~ /^[4,5][0-9][0-9]$/ && response.code!='401'
15
+ e = TingYun::Support::Exception::InternalServerError.new("#{response.code}: #{response.message}")
16
+ klass = "External/#{request.uri.to_s.gsub('/','%2F')}/#{type}"
17
+ e.instance_variable_set(:@tingyun_klass, klass)
18
+ e.instance_variable_set(:@tingyun_external, true)
19
+ e.instance_variable_set(:@tingyun_code, response.code)
20
+ e.instance_variable_set(:@tingyun_trace, caller.reject! { |t| t.include?('tingyun_rpm') })
21
+ TingYun::Agent.notice_error(e)
22
+ end
23
+ end
24
+
25
+ def handle_error(e,klass)
26
+
27
+ e.instance_variable_set(:@tingyun_klass, klass)
28
+ e.instance_variable_set(:@tingyun_external, true)
29
+ e.instance_variable_set(:@tingyun_trace, caller.reject! { |t| t.include?('tingyun_rpm') })
30
+
31
+ case e
32
+ when Errno::ECONNREFUSED
33
+ e.instance_variable_set(:@tingyun_code, 902)
34
+ when SocketError
35
+ e.instance_variable_set(:@tingyun_code, 901)
36
+ when OpenSSL::SSL::SSLError
37
+ e.instance_variable_set(:@tingyun_code, 908)
38
+ when Timeout::Error
39
+ e.instance_variable_set(:@tingyun_code, 903)
40
+ else
41
+ e.instance_variable_set(:@tingyun_code, 1000)
42
+ end
43
+
44
+ TingYun::Agent.notice_error(e)
45
+
46
+ raise e
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,84 @@
1
+ # encoding: utf-8
2
+ require 'ting_yun/agent'
3
+ require 'ting_yun/agent/datastore/metric_helper'
4
+ require 'ting_yun/agent/datastore/mongo'
5
+
6
+ module TingYun
7
+ module Instrumentation
8
+ module Support
9
+ module MetricTranslator
10
+
11
+ MONGODB = 'MongoDB'.freeze
12
+
13
+ def self.metrics_for(name, payload)
14
+ payload ||= {}
15
+
16
+ return nil if collection_in_selector?(payload)
17
+
18
+ collection = payload[:collection]
19
+
20
+ if create_index?(name, payload)
21
+ collection = self.collection_name_from_index(payload)
22
+ elsif group?(name, payload)
23
+ collection = collection_name_from_group_selector(payload)
24
+ elsif rename_collection?(name, payload)
25
+ collection = collection_name_from_rename_selector(payload)
26
+ end
27
+
28
+ TingYun::Agent::Datastore::MetricHelper.metrics_for(MONGODB,
29
+ TingYun::Agent::Datastore::Mongo.transform_operation(name),
30
+ collection)
31
+ rescue => e
32
+ TingYun::Agent.logger.debug("Failure during Mongo metric generation", e)
33
+ nil
34
+ end
35
+
36
+
37
+ def self.collection_in_selector?(payload)
38
+ payload[:collection] == '$cmd'
39
+ end
40
+
41
+ def self.create_index?(name, payload)
42
+ name == :insert && payload[:collection] == "system.indexes"
43
+ end
44
+
45
+ def self.group?(name, payload)
46
+ name == :group
47
+ end
48
+
49
+ def self.rename_collection?(name, payload)
50
+ name == :renameCollection
51
+ end
52
+
53
+ def self.collection_name_from_index(payload)
54
+ if payload[:documents]
55
+ if payload[:documents].is_a?(Array)
56
+ # mongo gem versions pre 1.10.0
57
+ document = payload[:documents].first
58
+ else
59
+ # mongo gem versions 1.10.0 and later
60
+ document = payload[:documents]
61
+ end
62
+
63
+ if document && document[:ns]
64
+ return document[:ns].split('.').last
65
+ end
66
+ end
67
+
68
+ 'system.indexes'
69
+ end
70
+
71
+ def self.collection_name_from_group_selector(payload)
72
+ payload[:selector]["group"]["ns"]
73
+ end
74
+
75
+ def self.collection_name_from_rename_selector(payload)
76
+ parts = payload[:selector][:renameCollection].split('.')
77
+ parts.shift
78
+ parts.join('.')
79
+ end
80
+
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+
4
+ require 'ting_yun/agent/datastores/mongo/obfuscator'
5
+
6
+ module TingYun
7
+ module Instrumentation
8
+ module Support
9
+ module MongoFormatter
10
+
11
+ PLAINTEXT_KEYS = [
12
+ :database,
13
+ :collection,
14
+ :operation,
15
+ :fields,
16
+ :skip,
17
+ :limit,
18
+ :order
19
+ ]
20
+
21
+ OBFUSCATE_KEYS = [
22
+ :selector
23
+ ]
24
+
25
+ def self.format(statement, operation)
26
+
27
+ result = {:operation => operation}
28
+
29
+ PLAINTEXT_KEYS.each do |key|
30
+ result[key] = statement[key] if statement.key?(key)
31
+ end
32
+
33
+ OBFUSCATE_KEYS.each do |key|
34
+ if statement.key?(key) && statement[key]
35
+ obfuscated = obfuscate(statement[key])
36
+ result[key] = obfuscated if obfuscated
37
+ end
38
+ end
39
+ result
40
+ end
41
+
42
+ def self.obfuscate(statement)
43
+ statement = Obfuscator.obfuscate_statement(statement)
44
+ statement
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+
4
+
5
+ module TingYun
6
+ module Instrumentation
7
+ module Support
8
+ module ParameterFiltering
9
+
10
+ module_function
11
+
12
+ def filter_rails_request_parameters(params)
13
+ result = params.dup
14
+ result.delete("controller")
15
+ result.delete("action")
16
+ result
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end