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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2624cf34ca90d31f96673c15f890643480506c38
4
+ data.tar.gz: 2f85347327a7bd560ebb68824c98038af8cb7560
5
+ SHA512:
6
+ metadata.gz: b213b4a36871b7c8d08b0b55bb1db0c8234cfeda539ddbf95e8b0b3cd95be8431cbea647514540054c8fc489a7689452a16c68f986f1da6b878e253c24651b85
7
+ data.tar.gz: 131855e493b0216d0885a61f16fd3eb7df50a2b5a8175b421937724a83af3ad1390c97bef01d9c663870bcafb80c3037ff517757ebd3fca59b30d0ef1cd2d6a6
data/.DS_Store ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ log/
11
+ .ruby-version
12
+ .idea/
13
+ todo
14
+
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ before_install: gem install bundler -v 1.10.6
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,25 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ # directories %w(app lib config test spec features) \
6
+ # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
7
+
8
+ ## Note: if you are using the `directories` clause above and you are not
9
+ ## watching the project directory ('.'), then you will want to move
10
+ ## the Guardfile to a watched dir and symlink it back, e.g.
11
+ #
12
+ # $ mkdir config
13
+ # $ mv Guardfile config/
14
+ # $ ln -s config/Guardfile .
15
+ #
16
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17
+
18
+ guard :minitest, :test_folders => ['test/ting_yun'], :all_after_pass => false do
19
+ # with Minitest::Unit
20
+ watch(%r{^lib/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
21
+ watch(%r{^test/.+_test\.rb$})
22
+ watch('test/test_helper.rb') { "test/tingyun" }
23
+ watch('test/agent_helper.rb') { "test/tingyun" }
24
+
25
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+
4
+ Copyright (c) 2015 anehing
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # TingyunRpm
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/tingyun_rpm`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'tingyun_rpm'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install tingyun_rpm
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake false` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/tingyun_rpm. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
36
+
37
+
38
+ ## License
39
+
40
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
41
+
data/cert/cacert.pem ADDED
File without changes
@@ -0,0 +1,128 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under Ting Yun's license terms.
3
+ require 'ting_yun/logger/agent_logger'
4
+ require 'ting_yun/agent/class_methods'
5
+ require 'ting_yun/agent/instance_methods'
6
+ require 'ting_yun/ting_yun_service'
7
+ require 'ting_yun/frameworks'
8
+ require 'ting_yun/agent/event/event_listener'
9
+ require 'ting_yun/agent/dispatcher'
10
+ require 'ting_yun/agent/collector/middle_ware_collector'
11
+ require 'ting_yun/agent/cross_app/cross_app_monitor'
12
+
13
+
14
+ # The Agent is a singleton that is instantiated when the plugin is
15
+ # activated. It collects performance data from ruby applications
16
+ # in realtime as the application runs, and periodically sends that
17
+ # data to the server. TingYun::Agent::Agent.instance
18
+
19
+ module TingYun
20
+ module Agent
21
+ class Agent
22
+
23
+ class << self
24
+ private :new
25
+ end
26
+
27
+ # service for communicating with collector
28
+ attr_accessor :service, :cross_app_monitor
29
+ attr_reader :events
30
+
31
+ extend ClassMethods
32
+ include InstanceMethods
33
+
34
+
35
+ def initialize
36
+ @started = false
37
+ @environment_report = nil
38
+ @service = TingYunService.new
39
+ @connect_state = :pending #[:pending, :connected, :disconnected]
40
+ @connect_attempts = 0
41
+ @events = TingYun::Agent::Event::EventListener.new
42
+ @after_fork_lock = Mutex.new
43
+ @dispatcher = TingYun::Agent::Dispatcher.new(@events)
44
+ @cross_app_monitor = TingYun::Agent::CrossAppMonitor.new(@events)
45
+
46
+ init_containers
47
+ end
48
+
49
+ def start
50
+ # should hava the vaild app_name, unstart-state and able to start
51
+ return unless agent_should_start?
52
+ log_startup
53
+ check_config_and_start_agent
54
+ log_version_and_pid
55
+ end
56
+
57
+ # Attempt a graceful shutdown of the agent, flushing any remaining
58
+ # data.
59
+ def shutdown
60
+ return unless started?
61
+ TingYun::Agent.logger.info "Starting Agent shutdown"
62
+
63
+ stop_event_loop
64
+ reset_to_default_configuration
65
+
66
+ @started = nil
67
+
68
+ TingYun::Frameworks::Framework.reset
69
+ end
70
+
71
+ # Connect to the server and validate the license. If successful,
72
+ # connected? returns true when finished. If not successful, you can
73
+ # keep calling this. Return false if we could not establish a
74
+ # connection with the server and we should not retry, such as if
75
+ # there's a bad license key.
76
+
77
+ def connect!(option={})
78
+ defaults = {
79
+ :keep_retrying => ::TingYun::Agent.config[:keep_retrying],
80
+ :force_reconnect => ::TingYun::Agent.config[:force_reconnect]
81
+ }
82
+ opts = defaults.merge(option)
83
+ return unless should_connect?(opts[:force_reconnect])
84
+ TingYun::Agent.logger.debug "Connecting Process to Ting Yun: #$0"
85
+ query_server_for_configuration
86
+ @connected_pid = $$
87
+ @connect_state = :connected
88
+ rescue TingYun::Support::Exception::LicenseException => e
89
+ handle_license_error(e)
90
+ rescue TingYun::Support::Exception::UnrecoverableAgentException => e
91
+ handle_unrecoverable_agent_error(e)
92
+ rescue StandardError, Timeout::Error, TingYun::Support::Exception::ServerConnectionException, TingYun::Support::Exception::AgentEnableException => e
93
+ log_error(e)
94
+ if TingYun::Agent.config[:keep_retrying]
95
+ note_connect_failure
96
+ ::TingYun::Agent.logger.info "Will re-attempt in 60 seconds"
97
+ sleep 60
98
+ retry
99
+ else
100
+ disconnect
101
+ end
102
+ rescue Exception => e
103
+ ::TingYun::Agent.logger.error "Exception of unexpected type during Agent#connect():", e
104
+ raise
105
+ end
106
+
107
+
108
+ def install_exit_handler
109
+ TingYun::Agent.logger.debug("Installing at_exit handler")
110
+ at_exit do
111
+ if need_exit_code_workaround?
112
+ exit_status = $!.status if $!.is_a?(SystemExit)
113
+ shutdown
114
+ exit exit_status if exit_status
115
+ else
116
+ shutdown
117
+ end
118
+ end
119
+ end
120
+
121
+ def need_exit_code_workaround?
122
+ defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION.match(/^1\.9/)
123
+ end
124
+
125
+
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under Ting Yun's license terms.
3
+ require 'ting_yun/agent'
4
+
5
+ module TingYun
6
+ module Agent
7
+ module ClassMethods
8
+ def config
9
+ ::TingYun::Agent.config
10
+ end
11
+
12
+ def logger
13
+ ::TingYun::Agent.logger
14
+ end
15
+
16
+ def instance
17
+ @instance ||= new
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,2 @@
1
+ class BaseSampler
2
+ end
@@ -0,0 +1,88 @@
1
+ # encoding: utf-8
2
+
3
+ require 'ting_yun/agent'
4
+
5
+ module TingYun
6
+ module Agent
7
+ module Collector
8
+ class ErrorTraceArray
9
+ def initialize(capacity)
10
+ @capacity = capacity
11
+ @lock = Mutex.new
12
+ @errors = []
13
+ end
14
+
15
+ def enabled?
16
+ ::TingYun::Agent.config[:'nbs.error_collector.enabled']
17
+ end
18
+
19
+ def merge!(errors)
20
+ errors.each do |error|
21
+ add_to_error_queue(error)
22
+ end
23
+ end
24
+
25
+
26
+ def reset!
27
+ @lock.synchronize do
28
+ @errors = []
29
+ end
30
+ end
31
+
32
+
33
+ # Get the errors currently queued up. Unsent errors are left
34
+ # over from a previous unsuccessful attempt to send them to the server.
35
+ def harvest!
36
+ @lock.synchronize do
37
+ errors = @errors
38
+ @errors = []
39
+ errors
40
+ end
41
+ end
42
+
43
+ # Synchronizes adding an error to the error queue, and checks if
44
+ # the error queue is too long - if so, we drop the error on the
45
+ # floor after logging a warning.
46
+ def add_to_error_queue(noticed_error)
47
+ return unless enabled?
48
+ @lock.synchronize do
49
+ if !over_queue_limit?(noticed_error.message) && !@errors.include?(noticed_error)
50
+ @errors << noticed_error
51
+ end
52
+ end
53
+ end
54
+
55
+
56
+ # checks the size of the error queue to make sure we are under
57
+ # the maximum limit, and logs a warning if we are over the limit.
58
+ def over_queue_limit?(message)
59
+ over_limit = (@errors.reject { |err| err.is_internal }.length >= @capacity)
60
+ if over_limit
61
+ ::TingYun::Agent.logger.warn("The error reporting queue has reached #{@capacity}. The error detail for this and subsequent errors will not be transmitted to TingYun until the queued errors have been sent: #{message}")
62
+ end
63
+ over_limit
64
+ end
65
+
66
+ # see TingYun::Agent::Instance.error_collector.notice_agent_error
67
+ def notice_agent_error(exception)
68
+ return unless exception.class < TingYun::Support::Exception::InternalAgentError
69
+
70
+ TingYun::Agent.logger.info(exception)
71
+
72
+ @lock.synchronize do
73
+ return if @errors.any? { |err| err.exception_class_name == exception.class.name }
74
+
75
+ trace = exception.backtrace || caller.dup
76
+ noticed_error = TingYun::Agent::Collector::NoticedError.new("TingYun/AgentError", exception)
77
+ noticed_error.stack_trace = trace
78
+ @errors << noticed_error
79
+ end
80
+ rescue => e
81
+ TingYun::Agent.logger.info("Unable to capture internal agent error due to an exception:", e)
82
+ end
83
+
84
+ end
85
+ end
86
+ end
87
+ end
88
+
@@ -0,0 +1,129 @@
1
+ # encoding: utf-8
2
+
3
+ # A Hash-like class for storing errorTraceData data.
4
+ #
5
+
6
+ require 'ting_yun/support/exception'
7
+ require 'ting_yun/support/coerce'
8
+
9
+
10
+ module TingYun
11
+ module Agent
12
+ module Collector
13
+ class NoticedError
14
+
15
+ attr_accessor :metric_name, :timestamp, :message, :exception_class_name,
16
+ :request_uri, :request_port, :file_name, :line_number,
17
+ :stack_trace, :attributes_from_notice_error, :attributes,
18
+ :count_error, :thread_name, :is_external_error, :external_metric_name, :code, :trace
19
+
20
+
21
+ attr_reader :exception_id, :is_internal
22
+
23
+
24
+ def initialize(metric_name, exception, timestamp = Time.now)
25
+ @stack_trace = []
26
+ @count_error = 1
27
+ @exception_id = exception.object_id
28
+ @metric_name = metric_name
29
+ @timestamp = timestamp
30
+ @exception_class_name = exception.is_a?(Exception) ? exception.class.name : 'Error'
31
+ @external_metric_name = exception.instance_variable_get :@tingyun_klass
32
+ @is_external_error = exception.instance_variable_get :@tingyun_external
33
+ @code = exception.instance_variable_get :@tingyun_code
34
+ @trace = exception.instance_variable_get :@tingyun_trace
35
+ # It's critical that we not hold onto the exception class constant in this
36
+ # class. These objects get serialized for Resque to a process that might
37
+ # not have the original exception class loaded, so do all processing now
38
+ # while we have the actual exception!
39
+ @is_internal = (exception.class < TingYun::Support::Exception::InternalAgentError)
40
+
41
+ if exception.nil?
42
+ @message = '<no message>'
43
+ elsif exception.respond_to?('original_exception')
44
+ @message = (exception.original_exception || exception).to_s
45
+ else # exception is not nil, but does not respond to original_exception
46
+ @message = exception.to_s
47
+ end
48
+
49
+
50
+ unless @message.is_a?(String)
51
+ # In pre-1.9.3, Exception.new({}).to_s.class != String
52
+ # That is, Exception#to_s may not return a String instance if one wasn't
53
+ # passed in upon creation of the Exception. So, try to generate a useful
54
+ # String representation of the exception message, falling back to failsafe
55
+ @message = String(@message.inspect) rescue '<unknown message type>'
56
+ end
57
+
58
+ # clamp long messages to 4k so that we don't send a lot of
59
+ # overhead across the wire
60
+ @message = @message[0..4095] if @message.length > 4096
61
+ end
62
+
63
+
64
+ def ==(other)
65
+ if other.respond_to?(:exception_id)
66
+ exception_id == other.exception_id
67
+ else
68
+ false
69
+ end
70
+ end
71
+
72
+ include TingYun::Support::Coerce
73
+
74
+ def to_collector_array(encoder)
75
+ if is_external_error
76
+ [timestamp.to_i,
77
+ string(external_metric_name),
78
+ int(code),
79
+ string(exception_class_name),
80
+ count_error,
81
+ string(metric_name),
82
+ encoder.encode(error_params)
83
+ ]
84
+ else
85
+ [timestamp.to_i,
86
+ string(metric_name),
87
+ int(attributes.agent_attributes[:httpStatus]),
88
+ string(exception_class_name),
89
+ string(message),
90
+ count_error,
91
+ string(request_uri),
92
+ encoder.encode(error_params)
93
+ ]
94
+ end
95
+ end
96
+
97
+ def error_params
98
+ hash = {
99
+ :params => custom_params
100
+ }
101
+ if is_external_error
102
+ hash[:stacktrace] = trace
103
+ else
104
+ hash[:stacktrace] = stack_trace
105
+ hash[:requestParams] = request_params
106
+ end
107
+ hash
108
+ end
109
+
110
+ def custom_params
111
+ hash = {:threadName => string(attributes.agent_attributes[:threadName])}
112
+ if is_external_error
113
+ hash[:httpStatus] = int(code)
114
+ else
115
+ hash[:httpStatus] = int(attributes.agent_attributes[:httpStatus])
116
+ hash[:referer] = string(attributes.agent_attributes[:referer]) || ''
117
+ end
118
+ hash
119
+ end
120
+
121
+ def request_params
122
+ attributes.agent_attributes[:request_params]
123
+ end
124
+
125
+ end
126
+ end
127
+ end
128
+ end
129
+
@@ -0,0 +1,165 @@
1
+ # encoding: utf-8
2
+
3
+ require 'ting_yun/agent'
4
+ require 'ting_yun/agent/transaction/transaction_state'
5
+ require 'ting_yun/agent/collector/error_collector/noticed_error'
6
+ require 'ting_yun/agent/collector/error_collector/error_trace_array'
7
+
8
+ module TingYun
9
+ module Agent
10
+ module Collector
11
+ class ErrorCollector
12
+ ERRORS_ACTION = "Errors/Count/".freeze
13
+ ERRORS_ALL = "Errors/Count/All".freeze
14
+ ERRORS_ALL_WEB = "Errors/Count/AllWeb".freeze
15
+ ERRORS_ALL_BACK_GROUND = "Errors/Count/AllBackground".freeze
16
+
17
+ # Maximum possible length of the queue - defaults to 20, may be
18
+ MAX_ERROR_QUEUE_LENGTH = 20 unless defined? MAX_ERROR_QUEUE_LENGTH
19
+
20
+ #tag the exception,avoid the same exception record multiple times in the middlwars and other point
21
+ module Tag
22
+
23
+ EXCEPTION_TAG_IVAR = :'@__ty_seen_exception' unless defined? EXCEPTION_TAG_IVAR
24
+
25
+ def tag_exception(exception)
26
+ begin
27
+ exception.instance_variable_set(EXCEPTION_TAG_IVAR, true)
28
+ rescue => e
29
+ TingYun::Agent.logger.warn("Failed to tag exception: #{exception}: ", e)
30
+ end
31
+ end
32
+
33
+ def exception_tagged?(exception)
34
+ exception.instance_variable_defined?(EXCEPTION_TAG_IVAR)
35
+ end
36
+
37
+ end
38
+ include Tag
39
+
40
+ module Metric
41
+ def aggregated_metric_names(txn)
42
+ metric_names = [ERRORS_ALL]
43
+ return metric_names unless txn
44
+
45
+ if txn.recording_web_transaction?
46
+ metric_names << ERRORS_ALL_WEB
47
+ else
48
+ metric_names << ERRORS_ALL_BACK_GROUND
49
+ end
50
+
51
+ metric_names
52
+ end
53
+
54
+ def action_metric_name(txn,options)
55
+ "#{ERRORS_ACTION}#{txn.best_name}" if txn
56
+ end
57
+
58
+ end
59
+ include Metric
60
+
61
+ attr_reader :error_trace_array, :external_error_array
62
+
63
+ def initialize
64
+ # lookup of exception class names to ignore. Hash for fast access
65
+ @ignore = {}
66
+
67
+ @lock = Mutex.new
68
+
69
+ @error_trace_array = ::TingYun::Agent::Collector::ErrorTraceArray.new(MAX_ERROR_QUEUE_LENGTH)
70
+ @external_error_array = ::TingYun::Agent::Collector::ErrorTraceArray.new(MAX_ERROR_QUEUE_LENGTH)
71
+ end
72
+
73
+ # See TingYun::Agent.notice_error for options and commentary
74
+ def notice_error(exception, options={})
75
+ tag_exception(exception)
76
+ state = ::TingYun::Agent::TransactionState.tl_get
77
+ increment_error_count!(state, exception, options)
78
+ noticed_error = create_noticed_error(exception, options)
79
+ if noticed_error.is_external_error
80
+ external_error_array.add_to_error_queue(noticed_error)
81
+ else
82
+ error_trace_array.add_to_error_queue(noticed_error)
83
+ end
84
+ rescue => e
85
+ ::TingYun::Agent.logger.warn("Failure when capturing error '#{exception}':", e)
86
+ nil
87
+ end
88
+
89
+ # Increments a statistic that tracks total error rate
90
+ def increment_error_count!(state, exception, options={})
91
+ txn = state.current_transaction
92
+
93
+ metric_names = aggregated_metric_names(txn)
94
+
95
+ action_metric = action_metric_name(txn, options)
96
+ metric_names << action_metric if action_metric
97
+
98
+ stats_engine = TingYun::Agent.agent.stats_engine
99
+ stats_engine.record_unscoped_metrics(state, metric_names) do |stats|
100
+ stats.increment_count
101
+ end
102
+ end
103
+
104
+ EMPTY_STRING = ''.freeze
105
+
106
+ def create_noticed_error(exception, options)
107
+ error_metric = options.delete(:metric_name) || EMPTY_STRING
108
+
109
+ noticed_error = TingYun::Agent::Collector::NoticedError.new(error_metric, exception)
110
+ noticed_error.request_uri = options.delete(:uri) || EMPTY_STRING
111
+ noticed_error.request_port = options.delete(:port)
112
+ noticed_error.attributes = options.delete(:attributes)
113
+
114
+ noticed_error.file_name = sense_method(exception, :file_name)
115
+ noticed_error.line_number = sense_method(exception, :line_number)
116
+ noticed_error.stack_trace = extract_stack_trace(exception)
117
+
118
+ noticed_error.attributes_from_notice_error = options.delete(:custom_params) || {}
119
+
120
+ # Any options that are passed to notice_error which aren't known keys
121
+ # get treated as custom attributes, so merge them into that hash.
122
+ noticed_error.attributes_from_notice_error.merge!(options)
123
+
124
+ noticed_error
125
+ end
126
+
127
+ def skip_notice_error?(exception)
128
+ exception_tagged?(exception)
129
+ end
130
+
131
+ # calls a method on an object, if it responds to it - used for
132
+ # detection and soft fail-safe. Returns nil if the method does
133
+ # not exist
134
+ def sense_method(object, method)
135
+ object.send(method) if object.respond_to?(method)
136
+ end
137
+
138
+ # extracts a stack trace from the exception for debugging purposes
139
+ def extract_stack_trace(exception)
140
+ actual_exception = sense_method(exception, 'original_exception') || exception
141
+ sense_method(actual_exception, 'backtrace') || '<no stack trace>'
142
+ end
143
+
144
+ # *Use sparingly for difficult to track bugs.*
145
+ #
146
+ # Track internal agent errors for communication back to TingYun
147
+ # To use, make a specific subclass of TingYun::Support::Exception::InternalAgentError,
148
+ # then pass an instance of it to this method when your problem occurs.
149
+ #
150
+ # Limits are treated differently for these errors. We only gather one per
151
+ # class per harvest, disregarding (and not impacting) the app error queue
152
+ # limit.
153
+ def notice_agent_error(exception)
154
+ error_trace_array.notice_agent_error(exception)
155
+ end
156
+
157
+ def reset!
158
+ @error_trace_array.reset!
159
+ @external_error_array.reset!
160
+ nil
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end