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,194 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under Ting Yun's license terms.
3
+ require 'ting_yun/support/exception'
4
+
5
+
6
+ module TingYun
7
+ module Agent
8
+ module Event
9
+ class EventLoop
10
+ class Timer
11
+ attr_reader :next_fire_time, :event, :interval, :last_fired_at
12
+
13
+ def initialize(interval, event, repeat=false)
14
+ @interval = interval
15
+ @event = event
16
+ @repeat = repeat
17
+ @started_at = Time.now
18
+ @last_fired_at = nil
19
+ reschedule
20
+ end
21
+
22
+ def reschedule
23
+ @next_fire_time = calculate_next_fire_time
24
+ end
25
+
26
+ def advance(amount)
27
+ @next_fire_time -= amount
28
+ end
29
+
30
+ def last_interval_start
31
+ @last_fired_at || @started_at
32
+ end
33
+
34
+ def calculate_next_fire_time
35
+ now = Time.now
36
+ return now if @interval == 0
37
+ fire_time = @last_fired_at || now
38
+ while fire_time <= now
39
+ fire_time += @interval
40
+ end
41
+ fire_time
42
+ end
43
+
44
+ def set_fired_time
45
+ @last_fired_at = Time.now
46
+ end
47
+
48
+ def due?(now=Time.now)
49
+ now >= @next_fire_time
50
+ end
51
+
52
+ def finished?
53
+ !@repeat && @last_fired_at
54
+ end
55
+ end
56
+
57
+ def initialize
58
+ @self_pipe_rd, @self_pipe_wr = IO.pipe
59
+ @event_queue = Queue.new
60
+ @stopped = false
61
+ @timers = {}
62
+
63
+ @subscriptions = Hash.new { |h,k| h[k] = [] }
64
+ @subscriptions[:__add_timer] << Proc.new { |t| set_timer(t) }
65
+ @subscriptions[:__add_event] << Proc.new { |e, blk| @subscriptions[e] << blk }
66
+ end
67
+
68
+ def set_timer(timer)
69
+ existing_timer = @timers[timer.event]
70
+
71
+ if existing_timer
72
+ elapsed_interval = Time.now - existing_timer.last_interval_start
73
+ timer.advance(elapsed_interval)
74
+ end
75
+
76
+ @timers[timer.event] = timer
77
+
78
+ fire_timer(timer)
79
+ end
80
+
81
+ def next_timeout
82
+ return nil if @timers.empty?
83
+ timeout = @timers.values.map(&:next_fire_time).min - Time.now
84
+ timeout < 0 ? 0 : timeout
85
+ end
86
+
87
+ def stopped?
88
+ @stopped
89
+ end
90
+
91
+ def stop
92
+ @stopped = true
93
+ wakeup
94
+ end
95
+
96
+ def run
97
+ ::TingYun::Agent.logger.debug "Running event loop"
98
+ while !stopped?
99
+ run_once
100
+ end
101
+ end
102
+
103
+ def run_once(nonblock=false)
104
+ wait_to_run(nonblock)
105
+
106
+ prune_timers
107
+ fire_timers
108
+
109
+ until @event_queue.empty?
110
+ evt, args = @event_queue.pop
111
+ dispatch_event(evt, args)
112
+ reschedule_timer_for_event(evt)
113
+ end
114
+ end
115
+
116
+ def wait_to_run(nonblock)
117
+ timeout = nonblock ? 0 : next_timeout
118
+ ready = IO.select([@self_pipe_rd], nil, nil, timeout)
119
+
120
+ if ready && ready[0] && ready[0][0] && ready[0][0] == @self_pipe_rd
121
+ @self_pipe_rd.read(1)
122
+ end
123
+ end
124
+
125
+ def fire_timers
126
+ @timers.each do |event, timer|
127
+ fire_timer(timer)
128
+ end
129
+ end
130
+
131
+ def fire_timer(timer)
132
+ if timer.due?
133
+ @event_queue << [timer.event]
134
+ timer.set_fired_time
135
+ end
136
+ end
137
+
138
+ def prune_timers
139
+ @timers.delete_if { |e, t| t.finished? }
140
+ end
141
+
142
+ def dispatch_event(event, args)
143
+ TingYun::Agent.logger.debug("EventLoop: Dispatching event '#{event}' with #{@subscriptions[event].size} callback(s).")
144
+
145
+ errors = []
146
+ @subscriptions[event].each do |s|
147
+ begin
148
+ s.call(*args)
149
+ rescue TingYun::Support::Exception::ExpiredConfigurationException, TingYun::Support::Exception::InvalidDataTokenException, TingYun::Support::Exception::InvalidDataException
150
+ raise
151
+ rescue => e
152
+ errors << e
153
+ end
154
+ end
155
+
156
+ if !errors.empty?
157
+ ::TingYun::Agent.logger.error "#{errors.size} error(s) running task for event '#{event}' in Agent Event Loop:", *errors
158
+ end
159
+ end
160
+
161
+ def reschedule_timer_for_event(e)
162
+ @timers[e].reschedule if @timers[e]
163
+ end
164
+
165
+ def on(event, &blk)
166
+ fire(:__add_event, event, blk)
167
+ end
168
+
169
+ def fire(event, *args)
170
+ @event_queue << [event, args]
171
+ wakeup
172
+ end
173
+
174
+ def fire_every(interval, event)
175
+ ::TingYun::Agent.logger.debug "Firing event #{event} every #{interval} seconds."
176
+ fire(:__add_timer, Timer.new(interval, event, true))
177
+ end
178
+
179
+ def fire_after(interval, event)
180
+ ::TingYun::Agent.logger.debug "Firing event #{event} after #{interval} seconds."
181
+ fire(:__add_timer, Timer.new(interval, event, false))
182
+ end
183
+
184
+ def wakeup
185
+ begin
186
+ @self_pipe_wr.write_nonblock '.'
187
+ rescue Errno::EAGAIN
188
+ ::TingYun::Agent.logger.debug "Failed to wakeup event loop"
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,164 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under Ting Yun's license terms.
3
+ require 'ting_yun/support/exception'
4
+ require 'ting_yun/support/hostname'
5
+ require 'ting_yun/configuration/server_source'
6
+ require 'ting_yun/agent/instance_methods/handle_errors'
7
+ require 'ting_yun/environment_report'
8
+
9
+
10
+ module TingYun
11
+ module Agent
12
+ module InstanceMethods
13
+ module Connect
14
+
15
+ include HandleErrors
16
+
17
+ # number of attempts we've made to contact the server
18
+ attr_accessor :connect_attempts
19
+
20
+ # Disconnect just sets connected to false, which prevents
21
+ # the agent from trying to connect again
22
+ def disconnect
23
+ @connect_state = :disconnected
24
+ true
25
+ end
26
+
27
+ def connected?
28
+ @connect_state == :connected
29
+ end
30
+
31
+ def disconnected?
32
+ @connect_state == :disconnected
33
+ end
34
+
35
+ # Don't connect if we're already connected, or if we tried to connect
36
+ # and were rejected with prejudice because of a license issue, unless
37
+ # we're forced to by force_reconnect.
38
+ def should_connect?(force=false)
39
+ force || (!connected? && !disconnected?)
40
+ end
41
+
42
+ # Retry period is a minute for each failed attempt that
43
+ # we've made. This should probably do some sort of sane TCP
44
+ # backoff to prevent hammering the server, but a minute for
45
+ # each attempt seems to work reasonably well.
46
+ def connect_retry_period
47
+ [600, connect_attempts * 60].min
48
+ end
49
+
50
+ def note_connect_failure
51
+ self.connect_attempts += 1
52
+ end
53
+
54
+ def generate_environment_report
55
+ @environment_report = environment_for_connect
56
+ end
57
+
58
+ # We've seen objects in the environment report (Rails.env in
59
+ # particular) that can't seralize to JSON. Cope with that here and
60
+ # clear out so downstream code doesn't have to check again.
61
+ def sanitize_environment_report
62
+ if !@service.valid_to_marshal?(@environment_report)
63
+ @environment_report = {}
64
+ end
65
+ end
66
+
67
+
68
+ # Checks whether we should send environment info, and if so,
69
+ # returns the snapshot from the local environment.
70
+ # Generating the EnvironmentReport has the potential to trigger
71
+ # require calls in Rails environments, so this method should only
72
+ # be called synchronously from on the main thread.
73
+ def environment_for_connect
74
+ ::TingYun::Agent.config[:send_environment_info] ? TingYun::EnvironmentReport.new.data : {}
75
+ end
76
+
77
+
78
+ # Initializes the hash of settings that we send to the
79
+ # server. Returns a literal hash containing the options
80
+ def connect_settings
81
+ sanitize_environment_report
82
+ settings = {
83
+ :pid => $$,
84
+ :port => ::TingYun::Agent.config[:port],
85
+ :host => local_host,
86
+ :appName => ::TingYun::Agent.config.app_names,
87
+ :language => 'Ruby',
88
+ :agentVersion => ::TingYun::VERSION::STRING,
89
+ :env => @environment_report,
90
+ :config => ::TingYun::Agent.config.to_collector_hash
91
+ }
92
+ settings
93
+ end
94
+
95
+ def local_host
96
+ TingYun::Support::Hostname.get
97
+ end
98
+
99
+ # Returns connect data passed back from the server
100
+ def connect_to_server
101
+ @service.connect(connect_settings)
102
+ end
103
+
104
+ #merge server config
105
+ def query_server_for_configuration
106
+ finish_setup(connect_to_server)
107
+ end
108
+
109
+ # * <tt>:keep_retrying => false</tt> to only try to connect once, and
110
+ # return with the connection set to nil. This ensures we may try again
111
+ # later (default true).
112
+ # * <tt>force_reconnect => true</tt> if you want to establish a new connection
113
+ # to the server before running the worker loop. This means you get a separate
114
+ # agent run and Ting Yun sees it as a separate instance (default is false).
115
+ def catch_errors
116
+ yield
117
+
118
+ rescue TingYun::Support::Exception::ExpiredConfigurationException => e
119
+ handle_force_restart(e)
120
+ retry
121
+ rescue TingYun::Support::Exception::InvalidDataTokenException => e
122
+ handle_force_restart(e)
123
+ retry
124
+ rescue TingYun::Support::Exception::InvalidDataException => e
125
+ handle_server_error(e)
126
+ rescue => e
127
+ handle_other_error(e)
128
+ end
129
+
130
+ # Takes a hash of configuration data returned from the
131
+ # server and uses it to set local variables and to
132
+ # initialize various parts of the agent that are configured
133
+ # separately.
134
+ #
135
+ def finish_setup(config_data)
136
+ return if config_data == nil
137
+
138
+ if config_data['config']
139
+ ::TingYun::Agent.logger.debug "Using config from server"
140
+ end
141
+ ::TingYun::Agent.logger.debug "Server provided config: #{config_data.inspect}"
142
+ server_config = TingYun::Configuration::ServerSource.new(config_data)
143
+ ::TingYun::Agent.config.replace_or_add_config(server_config)
144
+ #log_connection!(config_data)
145
+ end
146
+
147
+ def log_connection!(config_data)
148
+ ::TingYun::Agent.logger.debug "Connected to TingYun Service at #{@service.collector.name}"
149
+ ::TingYun::Agent.logger.debug "Application Run = #{@service.applicationId}."
150
+ ::TingYun::Agent.logger.debug "Connection data = #{config_data.inspect}"
151
+ if config_data['messages'] && config_data['messages'].any?
152
+ log_collector_messages(config_data['messages'])
153
+ end
154
+ end
155
+
156
+ def log_collector_messages(messages)
157
+ messages.each do |message|
158
+ ::TingYun::Agent.logger.send(message['level'].downcase, message['message'])
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,137 @@
1
+ # encoding: utf-8
2
+ require 'ting_yun/support/exception'
3
+ require 'ting_yun/agent/collector/stats_engine'
4
+ require 'ting_yun/agent/collector/error_collector'
5
+
6
+ require 'ting_yun/agent/collector/transaction_sampler'
7
+
8
+ require 'ting_yun/agent/collector/sql_sampler'
9
+
10
+
11
+ module TingYun
12
+ module Agent
13
+ module InstanceMethods
14
+ module ContainerDataManager
15
+
16
+
17
+ attr_reader :stats_engine, :error_collector, :transaction_sampler, :sql_sampler, :middleware
18
+
19
+
20
+ def drop_buffered_data
21
+ @stats_engine.reset!
22
+ @transaction_sampler.reset!
23
+ @sql_sampler.reset!
24
+ @error_collector.reset!
25
+ end
26
+
27
+ def reset_objects_with_locks
28
+ init_containers
29
+ end
30
+
31
+
32
+ def init_containers
33
+ @stats_engine = TingYun::Agent::Collector::StatsEngine.new
34
+ @error_collector = TingYun::Agent::Collector::ErrorCollector.new
35
+ @transaction_sampler = TingYun::Agent::Collector::TransactionSampler.new
36
+ @sql_sampler = TingYun::Agent::Collector::SqlSampler.new
37
+ @middleware = TingYun::Agent::Collector::MiddleWareCollector.new(@events)
38
+ end
39
+
40
+ def container_for_endpoint(endpoint)
41
+ case endpoint
42
+ when :metric_data then
43
+ @stats_engine
44
+ # type code here
45
+ end
46
+ end
47
+
48
+ def transmit_data
49
+ ::TingYun::Agent.logger.debug('Sending data to Ting Yun Service')
50
+
51
+ @events.notify(:middleware_harvest)
52
+ @service.session do # use http keep-alive
53
+ harvest_and_send_errors
54
+ harvest_and_send_external_errors
55
+ harvest_and_send_timeslice_data
56
+ harvest_and_send_transaction_traces
57
+ harvest_and_send_slowest_sql
58
+ end
59
+ end
60
+
61
+ def harvest_and_send_timeslice_data
62
+ harvest_and_send_from_container(@stats_engine, :metric_data)
63
+ end
64
+
65
+ def harvest_and_send_errors
66
+ harvest_and_send_from_container(@error_collector.error_trace_array, :error_data)
67
+ end
68
+
69
+ def harvest_and_send_external_errors
70
+ harvest_and_send_from_container(@error_collector.external_error_array, :external_error_data)
71
+ end
72
+
73
+
74
+ def harvest_and_send_transaction_traces
75
+ harvest_and_send_from_container(@transaction_sampler, :action_trace_data)
76
+
77
+ end
78
+
79
+ def harvest_and_send_slowest_sql
80
+ harvest_and_send_from_container(@sql_sampler, :sql_trace)
81
+
82
+ end
83
+
84
+ # Harvests data from the given container, sends it to the named endpoint
85
+ # on the service, and automatically merges back in upon a recoverable
86
+ # failure.
87
+ #
88
+ # The given container should respond to:
89
+ #
90
+ # #harvest!
91
+ # returns an enumerable collection of data items to be sent to the
92
+ # collector.
93
+ #
94
+ # #reset!
95
+ # drop any stored data and reset to a clean state.
96
+ #
97
+ # #merge!(items)
98
+ # merge the given items back into the internal buffer of the
99
+ # container, so that they may be harvested again later.
100
+ #
101
+ def harvest_and_send_from_container(container, endpoint)
102
+ items = harvest_from_container(container, endpoint)
103
+ send_data_to_endpoint(endpoint, items, container)
104
+ end
105
+
106
+ def harvest_from_container(container, endpoint)
107
+ items =[]
108
+ begin
109
+ if TingYun::Agent.config[:'nbs.agent_enabled']
110
+ items = container.harvest!
111
+ else
112
+ container.reset!
113
+ end
114
+ rescue => e
115
+ TingYun::Agent.logger.error("Failed to harvest #{endpoint} data, resetting. Error: ", e)
116
+ container.reset!
117
+ end
118
+ items
119
+ end
120
+
121
+ def send_data_to_endpoint(endpoint, items, container)
122
+ TingYun::Agent.logger.info("Sending #{items.size} items to #{endpoint}")
123
+ begin
124
+ @service.send(endpoint, items)
125
+ rescue => e
126
+ TingYun::Agent.logger.info("Unable to send #{endpoint} data, will try again later. Error: ", e)
127
+ container.merge!(items)
128
+ raise
129
+ end
130
+
131
+ end
132
+
133
+ end
134
+
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,71 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under Ting Yun's license terms.
3
+
4
+ #
5
+
6
+ module TingYun
7
+ module Agent
8
+ module InstanceMethods
9
+ module HandleErrors
10
+ # When the server sends us an error with the license key, we
11
+ # want to tell the user that something went wrong, and let
12
+ # them know where to go to get a valid license key
13
+ #
14
+ # After this runs, it disconnects the agent so that it will
15
+ # no longer try to connect to the server, saving the
16
+ # application and the server load
17
+ def handle_license_error(error)
18
+ TingYun::Agent.logger.error(\
19
+ error.message, \
20
+ "You need to obtain a valid license key, or to upgrade your account.")
21
+ disconnect
22
+ end
23
+
24
+ def handle_unrecoverable_agent_error(error)
25
+ TingYun::Agent.logger.error(error.message)
26
+ disconnect
27
+ shutdown
28
+ end
29
+
30
+ # When we have a problem connecting to the server, we need
31
+ # to tell the user what happened, since this is not an error
32
+ # we can handle gracefully.
33
+ def log_error(error)
34
+ TingYun::Agent.logger.error "Error establishing connection with Ting Yun Service at #{service.inspect}:", error
35
+ end
36
+
37
+ # Handles an unknown error in the worker thread by logging
38
+ # it and disconnecting the agent, since we are now in an
39
+ # unknown state.
40
+ def handle_other_error(error)
41
+ TingYun::Agent.logger.error "Unhandled error in worker thread, disconnecting this agent process:"
42
+ # These errors are fatal (that is, they will prevent the agent from
43
+ # reporting entirely), so we really want backtraces when they happen
44
+ TingYun::Agent.logger.log_exception(:error, error)
45
+ disconnect
46
+ end
47
+
48
+ # Handles the case where the server tells us to restart -
49
+ # this clears the data, clears connection attempts, and
50
+ # waits a while to reconnect.
51
+ def handle_force_restart(error)
52
+ TingYun::Agent.logger.debug error.message
53
+ drop_buffered_data
54
+ @service.force_restart if @service
55
+ @connect_state = :pending
56
+ sleep 30
57
+ end
58
+ def handle_force_disconnect(error)
59
+ TingYun::Agent.logger.warn "Ting Yun forced this agent to disconnect (#{error.message})"
60
+ disconnect
61
+ end
62
+
63
+ def handle_server_error(error)
64
+ TingYun::Agent.logger.error(error.message)
65
+ drop_buffered_data
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end