appoptics_apm 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +43 -0
  3. data/.dockerignore +5 -0
  4. data/.gitignore +23 -0
  5. data/.rubocop.yml +5 -0
  6. data/.travis.yml +82 -0
  7. data/CHANGELOG.md +769 -0
  8. data/CONFIG.md +33 -0
  9. data/Dockerfile +41 -0
  10. data/Dockerfile_test +66 -0
  11. data/Gemfile +41 -0
  12. data/LICENSE +193 -0
  13. data/README.md +351 -0
  14. data/Rakefile +202 -0
  15. data/Vagrantfile +67 -0
  16. data/appoptics_apm.gemspec +55 -0
  17. data/build_gems.sh +15 -0
  18. data/docker-compose.yml +73 -0
  19. data/examples/DNT.md +35 -0
  20. data/examples/carrying_context.rb +220 -0
  21. data/examples/instrumenting_metal_controller.rb +8 -0
  22. data/examples/puma_on_heroku_config.rb +17 -0
  23. data/examples/tracing_async_threads.rb +124 -0
  24. data/examples/tracing_background_jobs.rb +53 -0
  25. data/examples/tracing_forked_processes.rb +99 -0
  26. data/examples/unicorn_on_heroku_config.rb +28 -0
  27. data/ext/oboe_metal/extconf.rb +54 -0
  28. data/ext/oboe_metal/lib/.keep +0 -0
  29. data/ext/oboe_metal/lib/liboboe-1.0.so.0.0.0 +0 -0
  30. data/ext/oboe_metal/noop/noop.c +7 -0
  31. data/ext/oboe_metal/src/VERSION +1 -0
  32. data/ext/oboe_metal/src/bson/bson.h +221 -0
  33. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  34. data/ext/oboe_metal/src/oboe.h +883 -0
  35. data/ext/oboe_metal/src/oboe.hpp +793 -0
  36. data/ext/oboe_metal/src/oboe_debug.h +50 -0
  37. data/ext/oboe_metal/src/oboe_wrap.cxx +6088 -0
  38. data/ext/oboe_metal/tests/test.rb +11 -0
  39. data/gemfiles/delayed_job.gemfile +36 -0
  40. data/gemfiles/frameworks.gemfile +44 -0
  41. data/gemfiles/instrumentation_mocked.gemfile +29 -0
  42. data/gemfiles/libraries.gemfile +85 -0
  43. data/gemfiles/rails23.gemfile +39 -0
  44. data/gemfiles/rails30.gemfile +42 -0
  45. data/gemfiles/rails31.gemfile +44 -0
  46. data/gemfiles/rails32.gemfile +54 -0
  47. data/gemfiles/rails40.gemfile +27 -0
  48. data/gemfiles/rails41.gemfile +27 -0
  49. data/gemfiles/rails42.gemfile +35 -0
  50. data/gemfiles/rails50.gemfile +44 -0
  51. data/gemfiles/rails51.gemfile +44 -0
  52. data/get_version.rb +5 -0
  53. data/init.rb +4 -0
  54. data/lib/appoptics_apm/api/layerinit.rb +39 -0
  55. data/lib/appoptics_apm/api/logging.rb +359 -0
  56. data/lib/appoptics_apm/api/memcache.rb +34 -0
  57. data/lib/appoptics_apm/api/profiling.rb +201 -0
  58. data/lib/appoptics_apm/api/tracing.rb +152 -0
  59. data/lib/appoptics_apm/api/util.rb +128 -0
  60. data/lib/appoptics_apm/api.rb +18 -0
  61. data/lib/appoptics_apm/base.rb +252 -0
  62. data/lib/appoptics_apm/config.rb +281 -0
  63. data/lib/appoptics_apm/frameworks/grape.rb +93 -0
  64. data/lib/appoptics_apm/frameworks/padrino/templates.rb +58 -0
  65. data/lib/appoptics_apm/frameworks/padrino.rb +52 -0
  66. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +106 -0
  67. data/lib/appoptics_apm/frameworks/rails/inst/action_controller2.rb +61 -0
  68. data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +58 -0
  69. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
  70. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  71. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  72. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +58 -0
  73. data/lib/appoptics_apm/frameworks/rails/inst/action_view_2x.rb +56 -0
  74. data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +50 -0
  75. data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
  76. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  77. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
  78. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
  79. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +120 -0
  80. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +101 -0
  81. data/lib/appoptics_apm/frameworks/rails.rb +116 -0
  82. data/lib/appoptics_apm/frameworks/sinatra/templates.rb +56 -0
  83. data/lib/appoptics_apm/frameworks/sinatra.rb +71 -0
  84. data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
  85. data/lib/appoptics_apm/inst/bunny-consumer.rb +92 -0
  86. data/lib/appoptics_apm/inst/curb.rb +329 -0
  87. data/lib/appoptics_apm/inst/dalli.rb +85 -0
  88. data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
  89. data/lib/appoptics_apm/inst/em-http-request.rb +105 -0
  90. data/lib/appoptics_apm/inst/excon.rb +130 -0
  91. data/lib/appoptics_apm/inst/faraday.rb +77 -0
  92. data/lib/appoptics_apm/inst/http.rb +83 -0
  93. data/lib/appoptics_apm/inst/httpclient.rb +176 -0
  94. data/lib/appoptics_apm/inst/memcache.rb +102 -0
  95. data/lib/appoptics_apm/inst/memcached.rb +94 -0
  96. data/lib/appoptics_apm/inst/mongo.rb +242 -0
  97. data/lib/appoptics_apm/inst/mongo2.rb +225 -0
  98. data/lib/appoptics_apm/inst/moped.rb +466 -0
  99. data/lib/appoptics_apm/inst/rack.rb +146 -0
  100. data/lib/appoptics_apm/inst/redis.rb +275 -0
  101. data/lib/appoptics_apm/inst/resque.rb +151 -0
  102. data/lib/appoptics_apm/inst/rest-client.rb +50 -0
  103. data/lib/appoptics_apm/inst/sequel.rb +178 -0
  104. data/lib/appoptics_apm/inst/sidekiq-client.rb +53 -0
  105. data/lib/appoptics_apm/inst/sidekiq-worker.rb +67 -0
  106. data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
  107. data/lib/appoptics_apm/inst/typhoeus.rb +113 -0
  108. data/lib/appoptics_apm/instrumentation.rb +22 -0
  109. data/lib/appoptics_apm/legacy_method_profiling.rb +97 -0
  110. data/lib/appoptics_apm/loading.rb +66 -0
  111. data/lib/appoptics_apm/logger.rb +41 -0
  112. data/lib/appoptics_apm/method_profiling.rb +33 -0
  113. data/lib/appoptics_apm/ruby.rb +35 -0
  114. data/lib/appoptics_apm/support.rb +135 -0
  115. data/lib/appoptics_apm/test.rb +94 -0
  116. data/lib/appoptics_apm/thread_local.rb +26 -0
  117. data/lib/appoptics_apm/util.rb +312 -0
  118. data/lib/appoptics_apm/version.rb +15 -0
  119. data/lib/appoptics_apm/xtrace.rb +103 -0
  120. data/lib/appoptics_apm.rb +72 -0
  121. data/lib/joboe_metal.rb +214 -0
  122. data/lib/oboe/README +2 -0
  123. data/lib/oboe/backward_compatibility.rb +80 -0
  124. data/lib/oboe/inst/rack.rb +11 -0
  125. data/lib/oboe.rb +7 -0
  126. data/lib/oboe_metal.rb +187 -0
  127. data/lib/rails/generators/appoptics_apm/install_generator.rb +45 -0
  128. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +222 -0
  129. data/ruby_setup.sh +47 -0
  130. data/run_docker_build_gem_upload_to_packagecloud.sh +20 -0
  131. data/run_tests_docker.rb +32 -0
  132. data/test/benchmark/README.md +65 -0
  133. data/test/benchmark/logging_bench.rb +54 -0
  134. data/test/benchmark/with_libraries_gemfile/bunny_bench.rb +69 -0
  135. data/test/benchmark/with_rails5x_gemfile/action_controller5x_bench.rb +43 -0
  136. data/test/frameworks/apps/grape_nested.rb +33 -0
  137. data/test/frameworks/apps/grape_simple.rb +80 -0
  138. data/test/frameworks/apps/padrino_simple.rb +80 -0
  139. data/test/frameworks/apps/sinatra_simple.rb +55 -0
  140. data/test/frameworks/grape_test.rb +286 -0
  141. data/test/frameworks/padrino_test.rb +222 -0
  142. data/test/frameworks/rails3x_test.rb +554 -0
  143. data/test/frameworks/rails4x_test.rb +570 -0
  144. data/test/frameworks/rails5x_api_test.rb +210 -0
  145. data/test/frameworks/rails5x_test.rb +376 -0
  146. data/test/frameworks/rails_shared_tests.rb +172 -0
  147. data/test/frameworks/sinatra_test.rb +140 -0
  148. data/test/instrumentation/bunny_client_test.rb +276 -0
  149. data/test/instrumentation/bunny_consumer_test.rb +204 -0
  150. data/test/instrumentation/curb_test.rb +398 -0
  151. data/test/instrumentation/dalli_test.rb +177 -0
  152. data/test/instrumentation/em_http_request_test.rb +89 -0
  153. data/test/instrumentation/excon_test.rb +231 -0
  154. data/test/instrumentation/faraday_test.rb +228 -0
  155. data/test/instrumentation/http_test.rb +143 -0
  156. data/test/instrumentation/httpclient_test.rb +320 -0
  157. data/test/instrumentation/memcache_test.rb +260 -0
  158. data/test/instrumentation/memcached_test.rb +229 -0
  159. data/test/instrumentation/mongo_v1_test.rb +479 -0
  160. data/test/instrumentation/mongo_v2_index_test.rb +124 -0
  161. data/test/instrumentation/mongo_v2_test.rb +584 -0
  162. data/test/instrumentation/mongo_v2_view_test.rb +435 -0
  163. data/test/instrumentation/moped_test.rb +517 -0
  164. data/test/instrumentation/rack_test.rb +165 -0
  165. data/test/instrumentation/redis_hashes_test.rb +268 -0
  166. data/test/instrumentation/redis_keys_test.rb +321 -0
  167. data/test/instrumentation/redis_lists_test.rb +310 -0
  168. data/test/instrumentation/redis_misc_test.rb +163 -0
  169. data/test/instrumentation/redis_sets_test.rb +296 -0
  170. data/test/instrumentation/redis_sortedsets_test.rb +328 -0
  171. data/test/instrumentation/redis_strings_test.rb +349 -0
  172. data/test/instrumentation/resque_test.rb +185 -0
  173. data/test/instrumentation/rest-client_test.rb +288 -0
  174. data/test/instrumentation/sequel_mysql2_test.rb +353 -0
  175. data/test/instrumentation/sequel_mysql_test.rb +334 -0
  176. data/test/instrumentation/sequel_pg_test.rb +336 -0
  177. data/test/instrumentation/sidekiq-client_test.rb +159 -0
  178. data/test/instrumentation/sidekiq-worker_test.rb +180 -0
  179. data/test/instrumentation/twitter-cassandra_test.rb +424 -0
  180. data/test/instrumentation/typhoeus_test.rb +284 -0
  181. data/test/jobs/delayed_job/db_worker_job.rb +29 -0
  182. data/test/jobs/delayed_job/error_worker_job.rb +10 -0
  183. data/test/jobs/delayed_job/remote_call_worker_job.rb +20 -0
  184. data/test/jobs/resque/db_worker_job.rb +29 -0
  185. data/test/jobs/resque/error_worker_job.rb +10 -0
  186. data/test/jobs/resque/remote_call_worker_job.rb +20 -0
  187. data/test/jobs/sidekiq/db_worker_job.rb +29 -0
  188. data/test/jobs/sidekiq/error_worker_job.rb +10 -0
  189. data/test/jobs/sidekiq/remote_call_worker_job.rb +20 -0
  190. data/test/minitest_helper.rb +276 -0
  191. data/test/mocked/curb_mocked_test.rb +311 -0
  192. data/test/mocked/excon_mocked_test.rb +166 -0
  193. data/test/mocked/faraday_mocked_test.rb +93 -0
  194. data/test/mocked/http_mocked_test.rb +129 -0
  195. data/test/mocked/httpclient_mocked_test.rb +245 -0
  196. data/test/mocked/rest_client_mocked_test.rb +103 -0
  197. data/test/mocked/typhoeus_mocked_test.rb +192 -0
  198. data/test/models/widget.rb +36 -0
  199. data/test/profiling/legacy_method_profiling_test.rb +201 -0
  200. data/test/profiling/method_profiling_test.rb +631 -0
  201. data/test/queues/delayed_job-client_test.rb +95 -0
  202. data/test/queues/delayed_job-worker_test.rb +91 -0
  203. data/test/reporter/reporter_test.rb +14 -0
  204. data/test/servers/delayed_job.rb +107 -0
  205. data/test/servers/rackapp_8101.rb +29 -0
  206. data/test/servers/rails3x_8140.rb +96 -0
  207. data/test/servers/rails4x_8140.rb +96 -0
  208. data/test/servers/rails5x_8140.rb +95 -0
  209. data/test/servers/rails5x_api_8150.rb +78 -0
  210. data/test/servers/sidekiq.rb +29 -0
  211. data/test/servers/sidekiq.yml +7 -0
  212. data/test/servers/sidekiq_initializer.rb +25 -0
  213. data/test/settings +0 -0
  214. data/test/support/auto_tracing_test.rb +50 -0
  215. data/test/support/backcompat_test.rb +276 -0
  216. data/test/support/config_test.rb +149 -0
  217. data/test/support/dnt_test.rb +98 -0
  218. data/test/support/init_report_test.rb +25 -0
  219. data/test/support/liboboe_settings_test.rb +110 -0
  220. data/test/support/logging_test.rb +130 -0
  221. data/test/support/noop_test.rb +88 -0
  222. data/test/support/sql_sanitize_test.rb +55 -0
  223. data/test/support/tracing_mode_test.rb +33 -0
  224. data/test/support/tvalias_test.rb +15 -0
  225. data/test/support/xtrace_test.rb +41 -0
  226. metadata +475 -0
@@ -0,0 +1,101 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Inst
6
+ module ConnectionAdapters
7
+ module Utils
8
+
9
+ def extract_trace_details(sql, name = nil, binds = [])
10
+ opts = {}
11
+
12
+ begin
13
+ if AppOpticsAPM::Config[:sanitize_sql]
14
+ # Sanitize SQL and don't report binds
15
+ opts[:Query] = AppOpticsAPM::Util.sanitize_sql(sql)
16
+ else
17
+ # Report raw SQL and any binds if they exist
18
+ opts[:Query] = sql.to_s
19
+ if binds && !binds.empty?
20
+ opts[:QueryArgs] = binds.map(&:value)
21
+ end
22
+ end
23
+
24
+ opts[:Name] = name.to_s if name
25
+ if AppOpticsAPM::Config[:active_record] && AppOpticsAPM::Config[:active_record][:collect_backtraces]
26
+ opts[:Backtrace] = AppOpticsAPM::API.backtrace
27
+ end
28
+
29
+ if ::Rails::VERSION::MAJOR == 2
30
+ config = ::Rails.configuration.database_configuration[::Rails.env]
31
+ else
32
+ config = ActiveRecord::Base.connection.instance_variable_get(:@config)
33
+ end
34
+
35
+ if config
36
+ opts[:Database] = config['database'] if config.key?('database')
37
+ opts[:RemoteHost] = config['host'] if config.key?('host')
38
+ adapter_name = config[:adapter]
39
+
40
+ case adapter_name
41
+ when /mysql/i
42
+ opts[:Flavor] = 'mysql'
43
+ when /postgres/i
44
+ opts[:Flavor] = 'postgresql'
45
+ end
46
+ end
47
+ rescue StandardError => e
48
+ AppOpticsAPM.logger.debug "Exception raised capturing ActiveRecord KVs: #{e.inspect}"
49
+ AppOpticsAPM.logger.debug e.backtrace.join('\n')
50
+ end
51
+
52
+ opts || {}
53
+ end
54
+
55
+ # We don't want to trace framework caches. Only instrument SQL that
56
+ # directly hits the database.
57
+ def ignore_payload?(name)
58
+ %w(SCHEMA EXPLAIN CACHE).include?(name.to_s) ||
59
+ (name && name.to_sym == :skip_logging) ||
60
+ name == 'ActiveRecord::SchemaMigration Load'
61
+ end
62
+
63
+ def exec_query_with_appoptics(sql, name = nil, binds = [], prepare: false)
64
+ if AppOpticsAPM.tracing? && !ignore_payload?(name)
65
+
66
+ opts = extract_trace_details(sql, name, binds)
67
+ AppOpticsAPM::API.trace('activerecord', opts || {}) do
68
+ exec_query_without_appoptics(sql, name, binds)
69
+ end
70
+ else
71
+ exec_query_without_appoptics(sql, name, binds)
72
+ end
73
+ end
74
+
75
+ def exec_insert_with_appoptics(sql, name = nil, binds = [], *args)
76
+ if AppOpticsAPM.tracing? && !ignore_payload?(name)
77
+
78
+ opts = extract_trace_details(sql, name, binds)
79
+ AppOpticsAPM::API.trace('activerecord', opts || {}) do
80
+ exec_insert_without_appoptics(sql, name, binds, *args)
81
+ end
82
+ else
83
+ exec_insert_without_appoptics(sql, name, binds, *args)
84
+ end
85
+ end
86
+
87
+ def exec_delete_with_appoptics(sql, name = nil, binds = [])
88
+ if AppOpticsAPM.tracing? && !ignore_payload?(name)
89
+
90
+ opts = extract_trace_details(sql, name, binds)
91
+ AppOpticsAPM::API.trace('activerecord', opts || {}) do
92
+ exec_delete_without_appoptics(sql, name, binds)
93
+ end
94
+ else
95
+ exec_delete_without_appoptics(sql, name, binds)
96
+ end
97
+ end
98
+ end # Utils
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,116 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Rails
6
+ module Helpers
7
+ extend ActiveSupport::Concern if defined?(::Rails) and ::Rails::VERSION::MAJOR > 2
8
+
9
+ def appoptics_rum_header
10
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] Note that appoptics_rum_header is deprecated. It is now a no-op and should be removed from your application code.'
11
+ return ''
12
+ end
13
+ alias_method :oboe_rum_header, :appoptics_rum_header
14
+
15
+ def appoptics_rum_footer
16
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] Note that appoptics_rum_footer is deprecated. It is now a no-op and should be removed from your application code.'
17
+ return ''
18
+ end
19
+ alias_method :oboe_rum_footer, :appoptics_rum_footer
20
+ end # Helpers
21
+
22
+ def self.load_initializer
23
+ # Force load the AppOpticsAPM Rails initializer if there is one
24
+ # Prefer appoptics_apm.rb but give priority to the legacy tracelytics.rb if it exists
25
+ if ::Rails::VERSION::MAJOR > 2
26
+ rails_root = ::Rails.root.to_s
27
+ else
28
+ rails_root = RAILS_ROOT.to_s
29
+ end
30
+
31
+ #
32
+ # We've been through 3 initializer names. Try each one.
33
+ #
34
+ if File.exist?("#{rails_root}/config/initializers/tracelytics.rb")
35
+ tr_initializer = "#{rails_root}/config/initializers/tracelytics.rb"
36
+
37
+ elsif File.exist?("#{rails_root}/config/initializers/oboe.rb")
38
+ tr_initializer = "#{rails_root}/config/initializers/oboe.rb"
39
+
40
+ else
41
+ tr_initializer = "#{rails_root}/config/initializers/appoptics_apm.rb"
42
+ end
43
+ require tr_initializer if File.exist?(tr_initializer)
44
+ end
45
+
46
+ def self.load_instrumentation
47
+ # Load the Rails specific instrumentation
48
+ require 'appoptics_apm/frameworks/rails/inst/action_controller'
49
+ require 'appoptics_apm/frameworks/rails/inst/action_view'
50
+ require 'appoptics_apm/frameworks/rails/inst/action_view_2x'
51
+ require 'appoptics_apm/frameworks/rails/inst/action_view_30'
52
+ require 'appoptics_apm/frameworks/rails/inst/active_record'
53
+
54
+ AppOpticsAPM.logger.info "AppOpticsAPM gem #{AppOpticsAPM::Version::STRING} successfully loaded."
55
+ end
56
+
57
+ def self.include_helpers
58
+ # TBD: This would make the helpers available to controllers which is occasionally desired.
59
+ # ActiveSupport.on_load(:action_controller) do
60
+ # include AppOpticsAPM::Rails::Helpers
61
+ # end
62
+ if ::Rails::VERSION::MAJOR > 2
63
+ ActiveSupport.on_load(:action_view) do
64
+ include AppOpticsAPM::Rails::Helpers
65
+ end
66
+ else
67
+ ActionView::Base.send :include, AppOpticsAPM::Rails::Helpers
68
+ end
69
+ end
70
+ end # Rails
71
+ end # AppOpticsAPM
72
+
73
+ if defined?(::Rails)
74
+ require 'appoptics_apm/inst/rack'
75
+
76
+ if ::Rails::VERSION::MAJOR > 2
77
+ module AppOpticsAPM
78
+ class Railtie < ::Rails::Railtie
79
+ initializer 'appoptics_apm.helpers' do
80
+ AppOpticsAPM::Rails.include_helpers
81
+ end
82
+
83
+ initializer 'appoptics_apm.rack' do |app|
84
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting rack' if AppOpticsAPM::Config[:verbose]
85
+ app.config.middleware.insert 0, AppOpticsAPM::Rack
86
+ end
87
+
88
+ config.after_initialize do
89
+ AppOpticsAPM.logger = ::Rails.logger if ::Rails.logger && !ENV.key?('APPOPTICS_GEM_TEST')
90
+
91
+ AppOpticsAPM::Inst.load_instrumentation
92
+ AppOpticsAPM::Rails.load_instrumentation
93
+
94
+ # Report __Init after fork when in Heroku
95
+ AppOpticsAPM::API.report_init unless AppOpticsAPM.heroku?
96
+ end
97
+ end
98
+ end
99
+ else
100
+ AppOpticsAPM.logger = ::Rails.logger if ::Rails.logger
101
+
102
+ AppOpticsAPM::Rails.load_initializer
103
+
104
+ Rails.configuration.after_initialize do
105
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting rack' if AppOpticsAPM::Config[:verbose]
106
+ Rails.configuration.middleware.insert 0, 'AppOpticsAPM::Rack'
107
+
108
+ AppOpticsAPM::Inst.load_instrumentation
109
+ AppOpticsAPM::Rails.load_instrumentation
110
+ AppOpticsAPM::Rails.include_helpers
111
+
112
+ # Report __Init after fork when in Heroku
113
+ AppOpticsAPM::API.report_init unless AppOpticsAPM.heroku?
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,56 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Sinatra
6
+ module Templates
7
+ def self.included(klass)
8
+ ::AppOpticsAPM::Util.method_alias(klass, :render, ::Sinatra::Templates)
9
+ end
10
+
11
+ def render_with_appoptics(engine, data, options = {}, locals = {}, &block)
12
+ if AppOpticsAPM.tracing?
13
+ report_kvs = {}
14
+
15
+ report_kvs[:engine] = engine
16
+ report_kvs[:template] = data
17
+
18
+ if AppOpticsAPM.tracing_layer_op?(:render)
19
+ # For recursive calls to :render (for sub-partials and layouts),
20
+ # use method profiling.
21
+ begin
22
+ name = data
23
+ report_kvs[:FunctionName] = :render
24
+ report_kvs[:Class] = :Templates
25
+ report_kvs[:Module] = :'Sinatra::Templates'
26
+ report_kvs[:File] = __FILE__
27
+ report_kvs[:LineNumber] = __LINE__
28
+ rescue StandardError => e
29
+ ::AppOpticsAPM.logger.debug e.message
30
+ ::AppOpticsAPM.logger.debug e.backtrace.join(', ')
31
+ end
32
+
33
+ AppOpticsAPM::API.profile(name, report_kvs, false) do
34
+ render_without_appoptics(engine, data, options, locals, &block)
35
+ end
36
+
37
+ else
38
+ # Fall back to the raw tracing API so we can pass KVs
39
+ # back on exit (a limitation of the AppOpticsAPM::API.trace
40
+ # block method) This removes the need for an info
41
+ # event to send additonal KVs
42
+ ::AppOpticsAPM::API.log_entry(:render, {}, :render)
43
+
44
+ begin
45
+ render_without_appoptics(engine, data, options, locals, &block)
46
+ ensure
47
+ ::AppOpticsAPM::API.log_exit(:render, report_kvs)
48
+ end
49
+ end
50
+ else
51
+ render_without_appoptics(engine, data, options, locals, &block)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,71 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Sinatra
6
+ module Base
7
+ def self.included(klass)
8
+ ::AppOpticsAPM::Util.method_alias(klass, :dispatch!, ::Sinatra::Base)
9
+ ::AppOpticsAPM::Util.method_alias(klass, :handle_exception!, ::Sinatra::Base)
10
+ end
11
+
12
+ def dispatch_with_appoptics
13
+
14
+ ::AppOpticsAPM::API.log_entry('sinatra', {})
15
+
16
+ response = dispatch_without_appoptics
17
+
18
+ # Report Controller/Action and transaction as best possible
19
+ report_kvs = {}
20
+ report_kvs[:Controller] = self.class
21
+ report_kvs[:Action] = env['sinatra.route']
22
+ env['appoptics_apm.controller'] = report_kvs[:Controller]
23
+ env['appoptics_apm.action'] = report_kvs[:Action]
24
+
25
+ response
26
+ ensure
27
+ ::AppOpticsAPM::API.log_exit('sinatra', report_kvs)
28
+ end
29
+
30
+ def handle_exception_with_appoptics(boom)
31
+ AppOpticsAPM::API.log_exception(nil, boom)
32
+ handle_exception_without_appoptics(boom)
33
+ end
34
+
35
+ def appoptics_rum_header
36
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] Note that appoptics_rum_header is deprecated. It is now a no-op and should be removed from your application code.'
37
+ return ''
38
+ end
39
+ alias_method :oboe_rum_header, :appoptics_rum_header
40
+
41
+ def appoptics_rum_footer
42
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] Note that appoptics_rum_footer is deprecated. It is now a no-op and should be removed from your application code.'
43
+ return ''
44
+ end
45
+ alias_method :oboe_rum_footer, :appoptics_rum_footer
46
+ end
47
+ end
48
+ end
49
+
50
+ if defined?(::Sinatra)
51
+ require 'appoptics_apm/inst/rack'
52
+ require 'appoptics_apm/frameworks/sinatra/templates'
53
+
54
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting Sinatra' if AppOpticsAPM::Config[:verbose]
55
+
56
+ AppOpticsAPM::Inst.load_instrumentation
57
+
58
+ ::Sinatra::Base.use AppOpticsAPM::Rack
59
+
60
+ # When in the gem TEST environment, we load this instrumentation regardless.
61
+ # Otherwise, only when Padrino isn't around.
62
+ unless defined?(::Padrino) && !ENV.key?('APPOPTICS_GEM_TEST')
63
+ # Padrino has 'enhanced' routes and rendering so the Sinatra
64
+ # instrumentation won't work anyways. Only load for pure Sinatra apps.
65
+ ::AppOpticsAPM::Util.send_include(::Sinatra::Base, ::AppOpticsAPM::Sinatra::Base)
66
+ ::AppOpticsAPM::Util.send_include(::Sinatra::Templates, ::AppOpticsAPM::Sinatra::Templates)
67
+
68
+ # Report __Init after fork when in Heroku
69
+ AppOpticsAPM::API.report_init unless AppOpticsAPM.heroku?
70
+ end
71
+ end
@@ -0,0 +1,148 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Inst
6
+ module BunnyExchange
7
+ def self.included(klass)
8
+ ::AppOpticsAPM::Util.method_alias(klass, :delete, ::Bunny::Exchange)
9
+ end
10
+
11
+ def delete_with_appoptics(opts = {})
12
+ # If we're not tracing, just do a fast return.
13
+ return delete_without_appoptics(opts) if !AppOpticsAPM.tracing?
14
+
15
+ begin
16
+ kvs = {}
17
+ kvs[:Spec] = :pushq
18
+ kvs[:Flavor] = :rabbitmq
19
+ kvs[:Op] = :delete
20
+ kvs[:ExchangeType] = @type
21
+ kvs[:RemoteHost] = channel.connection.host
22
+ kvs[:RemotePort] = channel.connection.port.to_i
23
+ kvs[:VirtualHost] = channel.connection.vhost
24
+
25
+ if @name.is_a?(String) && !@name.empty?
26
+ kvs[:ExchangeName] = @name
27
+ else
28
+ kvs[:ExchangeName] = :default
29
+ end
30
+
31
+ AppOpticsAPM::API.log_entry(:'rabbitmq-client')
32
+
33
+ delete_without_appoptics(opts)
34
+ rescue => e
35
+ AppOpticsAPM::API.log_exception(nil, e)
36
+ raise e
37
+ ensure
38
+ AppOpticsAPM::API.log_exit(:'rabbitmq-client', kvs)
39
+ end
40
+ end
41
+ end
42
+
43
+ module BunnyChannel
44
+ def self.included(klass)
45
+ ::AppOpticsAPM::Util.method_alias(klass, :basic_publish, ::Bunny::Channel)
46
+ ::AppOpticsAPM::Util.method_alias(klass, :queue, ::Bunny::Channel)
47
+ ::AppOpticsAPM::Util.method_alias(klass, :wait_for_confirms, ::Bunny::Channel)
48
+ end
49
+
50
+ def collect_channel_kvs
51
+ begin
52
+ kvs = {}
53
+ kvs[:Spec] = :pushq
54
+ kvs[:Flavor] = :rabbitmq
55
+ kvs[:RemoteHost] = @connection.host
56
+ kvs[:RemotePort] = @connection.port.to_i
57
+ kvs[:VirtualHost] = @connection.vhost
58
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:bunnyclient][:collect_backtraces]
59
+ kvs
60
+ rescue => e
61
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
62
+ ensure
63
+ return kvs
64
+ end
65
+ end
66
+
67
+ def basic_publish_with_appoptics(payload, exchange, routing_key, opts = {})
68
+ # If we're not tracing, just do a fast return.
69
+ return basic_publish_without_appoptics(payload, exchange, routing_key, opts) if !AppOpticsAPM.tracing?
70
+
71
+ begin
72
+ kvs = collect_channel_kvs
73
+
74
+ if exchange.respond_to?(:name)
75
+ kvs[:ExchangeName] = exchange.name
76
+ elsif exchange.respond_to?(:empty?) && !exchange.empty?
77
+ kvs[:ExchangeName] = exchange
78
+ else
79
+ kvs[:ExchangeName] = :default
80
+ end
81
+
82
+ kvs[:Queue] = opts[:queue] if opts.key?(:queue)
83
+ kvs[:RoutingKey] = routing_key if routing_key
84
+ kvs[:Op] = :publish
85
+
86
+ AppOpticsAPM::API.log_entry(:'rabbitmq-client')
87
+
88
+ # Pass the tracing context as a header
89
+ opts[:headers] ||= {}
90
+ opts[:headers][:SourceTrace] = AppOpticsAPM::Context.toString if AppOpticsAPM.tracing?
91
+
92
+ basic_publish_without_appoptics(payload, exchange, routing_key, opts)
93
+ rescue => e
94
+ AppOpticsAPM::API.log_exception(nil, e)
95
+ raise e
96
+ ensure
97
+ AppOpticsAPM::API.log_exit(:'rabbitmq-client', kvs)
98
+ end
99
+ end
100
+
101
+ def queue_with_appoptics(name = AMQ::Protocol::EMPTY_STRING, opts = {})
102
+ # If we're not tracing, just do a fast return.
103
+ return queue_without_appoptics(name, opts) if !AppOpticsAPM.tracing?
104
+
105
+ begin
106
+ kvs = collect_channel_kvs
107
+ kvs[:Op] = :queue
108
+
109
+ AppOpticsAPM::API.log_entry(:'rabbitmq-client')
110
+
111
+ result = queue_without_appoptics(name, opts)
112
+ kvs[:Queue] = result.name
113
+ result
114
+ rescue => e
115
+ AppOpticsAPM::API.log_exception(nil, e)
116
+ raise e
117
+ ensure
118
+ AppOpticsAPM::API.log_exit(:'rabbitmq-client', kvs)
119
+ end
120
+ end
121
+
122
+ def wait_for_confirms_with_appoptics
123
+ # If we're not tracing, just do a fast return.
124
+ return wait_for_confirms_without_appoptics if !AppOpticsAPM.tracing?
125
+
126
+ begin
127
+ kvs = collect_channel_kvs
128
+ kvs[:Op] = :wait_for_confirms
129
+
130
+ AppOpticsAPM::API.log_entry(:'rabbitmq-client')
131
+
132
+ wait_for_confirms_without_appoptics
133
+ rescue => e
134
+ AppOpticsAPM::API.log_exception(nil, e)
135
+ raise e
136
+ ensure
137
+ AppOpticsAPM::API.log_exit(:'rabbitmq-client', kvs)
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+ if AppOpticsAPM::Config[:bunnyclient][:enabled] && defined?(::Bunny)
145
+ ::AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting bunny client' if AppOpticsAPM::Config[:verbose]
146
+ ::AppOpticsAPM::Util.send_include(::Bunny::Exchange, ::AppOpticsAPM::Inst::BunnyExchange)
147
+ ::AppOpticsAPM::Util.send_include(::Bunny::Channel, ::AppOpticsAPM::Inst::BunnyChannel)
148
+ end
@@ -0,0 +1,92 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Inst
6
+ module BunnyConsumer
7
+ def self.included(klass)
8
+ ::AppOpticsAPM::Util.method_alias(klass, :call, ::Bunny::Consumer)
9
+ end
10
+
11
+ def collect_consumer_kvs(args)
12
+ begin
13
+ kvs = {}
14
+ kvs[:Spec] = :job
15
+ kvs[:Flavor] = :rabbitmq
16
+ kvs[:RemoteHost] = @channel.connection.host
17
+ kvs[:RemotePort] = @channel.connection.port.to_i
18
+ kvs[:VirtualHost] = @channel.connection.vhost
19
+
20
+ mp = args[1]
21
+ kvs[:RoutingKey] = args[0].routing_key if args[0].routing_key
22
+ kvs[:MsgID] = args[1].message_id if mp.message_id
23
+ kvs[:AppID] = args[1].app_id if mp.app_id
24
+ kvs[:Priority] = args[1].priority if mp.priority
25
+
26
+ if @queue.respond_to?(:name)
27
+ kvs[:Queue] = @queue.name
28
+ else
29
+ kvs[:Queue] = @queue
30
+ end
31
+
32
+ # Report configurable Controller/Action KVs
33
+ # See AppOpticsAPM::Config[:bunnyconsumer] in lib/appoptics_apm/config.rb
34
+ # Used for dashboard trace filtering
35
+ controller_key = AppOpticsAPM::Config[:bunnyconsumer][:controller]
36
+ if mp.respond_to?(controller_key)
37
+ value = mp.method(controller_key).call
38
+ kvs[:Controller] = value if value
39
+ end
40
+
41
+ action_key = AppOpticsAPM::Config[:bunnyconsumer][:action]
42
+ if mp.respond_to?(action_key)
43
+ value = mp.method(action_key).call
44
+ kvs[:Action] = value if value
45
+ end
46
+
47
+ if kvs[:Queue]
48
+ kvs[:URL] = "/bunny/#{kvs[:Queue]}"
49
+ else
50
+ kvs[:URL] = "/bunny/consumer"
51
+ end
52
+
53
+ if AppOpticsAPM::Config[:bunnyconsumer][:log_args] && @arguments
54
+ kvs[:Args] = @arguments.to_s
55
+ end
56
+
57
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:bunnyconsumer][:collect_backtraces]
58
+
59
+ kvs
60
+ rescue => e
61
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
62
+ ensure
63
+ return kvs
64
+ end
65
+ end
66
+
67
+ def call_with_appoptics(*args)
68
+ report_kvs = collect_consumer_kvs(args)
69
+
70
+ # If SourceTrace was passed, capture and report it
71
+ headers = args[1][:headers]
72
+
73
+ if headers && headers['SourceTrace']
74
+ report_kvs[:SourceTrace] = headers['SourceTrace']
75
+
76
+ # Remove SourceTrace
77
+ headers.delete('SourceTrace')
78
+ end
79
+
80
+ result = AppOpticsAPM::API.start_trace(:'rabbitmq-consumer', nil, report_kvs) do
81
+ call_without_appoptics(*args)
82
+ end
83
+ result[0]
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ if AppOpticsAPM::Config[:bunnyconsumer][:enabled] && defined?(::Bunny)
90
+ ::AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting bunny consumer' if AppOpticsAPM::Config[:verbose]
91
+ ::AppOpticsAPM::Util.send_include(::Bunny::Consumer, ::AppOpticsAPM::Inst::BunnyConsumer)
92
+ end