appoptics_apm 4.0.2

Sign up to get free protection for your applications and to get access to all the features.
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,210 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require "minitest_helper"
5
+
6
+ if defined?(::Rails)
7
+
8
+ describe "Rails5xAPI" do
9
+ before do
10
+ clear_all_traces
11
+ AppOpticsAPM.config_lock.synchronize {
12
+ @tm = AppOpticsAPM::Config[:tracing_mode]
13
+ @collect_backtraces = AppOpticsAPM::Config[:action_controller_api][:collect_backtraces]
14
+ @sample_rate = AppOpticsAPM::Config[:sample_rate]
15
+ }
16
+ ENV['DBTYPE'] = "postgresql" unless ENV['DBTYPE']
17
+ end
18
+
19
+ after do
20
+ AppOpticsAPM.config_lock.synchronize {
21
+ AppOpticsAPM::Config[:action_controller_api][:collect_backtraces] = @collect_backtraces
22
+ AppOpticsAPM::Config[:tracing_mode] = @tm
23
+ AppOpticsAPM::Config[:sample_rate] = @sample_rate
24
+ }
25
+ end
26
+
27
+ it "should trace a request to a rails api stack" do
28
+ uri = URI.parse('http://127.0.0.1:8150/monkey/hello')
29
+ r = Net::HTTP.get_response(uri)
30
+
31
+ traces = get_all_traces
32
+
33
+ traces.count.must_equal 7
34
+ unless defined?(JRUBY_VERSION)
35
+ # We don't test this under JRuby because the Java instrumentation
36
+ # for the DB drivers doesn't use our test reporter hence we won't
37
+ # see all trace events. :-( To be improved.
38
+ valid_edges?(traces).must_equal true
39
+ end
40
+ validate_outer_layers(traces, 'rack')
41
+
42
+ traces[0]['Layer'].must_equal "rack"
43
+ traces[0]['Label'].must_equal "entry"
44
+ traces[0]['URL'].must_equal "/monkey/hello"
45
+
46
+ traces[1]['Layer'].must_equal "rack"
47
+ traces[1]['Label'].must_equal "info"
48
+
49
+ traces[2]['Layer'].must_equal "rails-api"
50
+ traces[2]['Label'].must_equal "entry"
51
+ traces[2]['Controller'].must_equal "MonkeyController"
52
+ traces[2]['Action'].must_equal "hello"
53
+
54
+ traces[3]['Layer'].must_equal "actionview"
55
+ traces[3]['Label'].must_equal "entry"
56
+
57
+ traces[4]['Layer'].must_equal "actionview"
58
+ traces[4]['Label'].must_equal "exit"
59
+
60
+ traces[5]['Layer'].must_equal "rails-api"
61
+ traces[5]['Label'].must_equal "exit"
62
+
63
+ traces[6]['Layer'].must_equal "rack"
64
+ traces[6]['Label'].must_equal "exit"
65
+
66
+ # Validate the existence of the response header
67
+ r.header.key?('X-Trace').must_equal true
68
+ r.header['X-Trace'].must_equal traces[6]['X-Trace']
69
+ end
70
+
71
+ it "should capture errors" do
72
+ uri = URI.parse('http://127.0.0.1:8150/monkey/error')
73
+ r = Net::HTTP.get_response(uri)
74
+
75
+ traces = get_all_traces
76
+
77
+ traces.count.must_equal 6
78
+ unless defined?(JRUBY_VERSION)
79
+ # We don't test this under JRuby because the Java instrumentation
80
+ # for the DB drivers doesn't use our test reporter hence we won't
81
+ # see all trace events. :-( To be improved.
82
+ valid_edges?(traces).must_equal true
83
+ end
84
+ validate_outer_layers(traces, 'rack')
85
+
86
+ traces[0]['Layer'].must_equal "rack"
87
+ traces[0]['Label'].must_equal "entry"
88
+ traces[0]['URL'].must_equal "/monkey/error"
89
+
90
+ traces[1]['Layer'].must_equal "rack"
91
+ traces[1]['Label'].must_equal "info"
92
+
93
+ traces[2]['Layer'].must_equal "rails-api"
94
+ traces[2]['Label'].must_equal "entry"
95
+ traces[2]['Controller'].must_equal "MonkeyController"
96
+ traces[2]['Action'].must_equal "error"
97
+
98
+ traces[3]['Label'].must_equal "error"
99
+ traces[3]['ErrorClass'].must_equal "RuntimeError"
100
+ traces[3]['ErrorMsg'].must_equal "Rails API fake error from controller"
101
+ traces[3].key?('Backtrace').must_equal true
102
+
103
+ traces[4]['Layer'].must_equal "rails-api"
104
+ traces[4]['Label'].must_equal "exit"
105
+
106
+ traces[5]['Layer'].must_equal "rack"
107
+ traces[5]['Label'].must_equal "exit"
108
+
109
+ # Validate the existence of the response header
110
+ r.header.key?('X-Trace').must_equal true
111
+ r.header['X-Trace'].must_equal traces[5]['X-Trace']
112
+ end
113
+
114
+ it "should collect backtraces when true" do
115
+ AppOpticsAPM::Config[:action_controller_api][:collect_backtraces] = true
116
+
117
+ uri = URI.parse('http://127.0.0.1:8150/monkey/hello')
118
+ r = Net::HTTP.get_response(uri)
119
+
120
+ traces = get_all_traces
121
+
122
+ traces.count.must_equal 7
123
+ unless defined?(JRUBY_VERSION)
124
+ # We don't test this under JRuby because the Java instrumentation
125
+ # for the DB drivers doesn't use our test reporter hence we won't
126
+ # see all trace events. :-( To be improved.
127
+ valid_edges?(traces).must_equal true
128
+ end
129
+ validate_outer_layers(traces, 'rack')
130
+
131
+ traces[0]['Layer'].must_equal "rack"
132
+ traces[0]['Label'].must_equal "entry"
133
+ traces[0]['URL'].must_equal "/monkey/hello"
134
+
135
+ traces[1]['Layer'].must_equal "rack"
136
+ traces[1]['Label'].must_equal "info"
137
+
138
+ traces[2]['Layer'].must_equal "rails-api"
139
+ traces[2]['Label'].must_equal "entry"
140
+ traces[2]['Controller'].must_equal "MonkeyController"
141
+ traces[2]['Action'].must_equal "hello"
142
+ traces[2].key?('Backtrace').must_equal true
143
+
144
+ traces[3]['Layer'].must_equal "actionview"
145
+ traces[3]['Label'].must_equal "entry"
146
+
147
+ traces[4]['Layer'].must_equal "actionview"
148
+ traces[4]['Label'].must_equal "exit"
149
+
150
+ traces[5]['Layer'].must_equal "rails-api"
151
+ traces[5]['Label'].must_equal "exit"
152
+
153
+ traces[6]['Layer'].must_equal "rack"
154
+ traces[6]['Label'].must_equal "exit"
155
+
156
+ # Validate the existence of the response header
157
+ r.header.key?('X-Trace').must_equal true
158
+ r.header['X-Trace'].must_equal traces[6]['X-Trace']
159
+ end
160
+
161
+ it "should NOT collect backtraces when false" do
162
+ AppOpticsAPM::Config[:action_controller_api][:collect_backtraces] = false
163
+
164
+ uri = URI.parse('http://127.0.0.1:8150/monkey/hello')
165
+ r = Net::HTTP.get_response(uri)
166
+
167
+ traces = get_all_traces
168
+
169
+ traces.count.must_equal 7
170
+ unless defined?(JRUBY_VERSION)
171
+ # We don't test this under JRuby because the Java instrumentation
172
+ # for the DB drivers doesn't use our test reporter hence we won't
173
+ # see all trace events. :-( To be improved.
174
+ valid_edges?(traces).must_equal true
175
+ end
176
+ validate_outer_layers(traces, 'rack')
177
+
178
+ traces[0]['Layer'].must_equal "rack"
179
+ traces[0]['Label'].must_equal "entry"
180
+ traces[0]['URL'].must_equal "/monkey/hello"
181
+
182
+ traces[1]['Layer'].must_equal "rack"
183
+ traces[1]['Label'].must_equal "info"
184
+
185
+ traces[2]['Layer'].must_equal "rails-api"
186
+ traces[2]['Label'].must_equal "entry"
187
+ traces[2]['Controller'].must_equal "MonkeyController"
188
+ traces[2]['Action'].must_equal "hello"
189
+ traces[2].key?('Backtrace').must_equal false
190
+
191
+ traces[3]['Layer'].must_equal "actionview"
192
+ traces[3]['Label'].must_equal "entry"
193
+
194
+ traces[4]['Layer'].must_equal "actionview"
195
+ traces[4]['Label'].must_equal "exit"
196
+
197
+ traces[5]['Layer'].must_equal "rails-api"
198
+ traces[5]['Label'].must_equal "exit"
199
+
200
+ traces[6]['Layer'].must_equal "rack"
201
+ traces[6]['Label'].must_equal "exit"
202
+
203
+ # Validate the existence of the response header
204
+ r.header.key?('X-Trace').must_equal true
205
+ r.header['X-Trace'].must_equal traces[6]['X-Trace']
206
+ end
207
+
208
+ require_relative "rails_shared_tests"
209
+ end
210
+ end
@@ -0,0 +1,376 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require "minitest_helper"
5
+
6
+ if defined?(::Rails)
7
+
8
+ describe "Rails5x" do
9
+ before do
10
+ clear_all_traces
11
+ AppOpticsAPM.config_lock.synchronize {
12
+ @tm = AppOpticsAPM::Config[:tracing_mode]
13
+ @collect_backtraces = AppOpticsAPM::Config[:action_controller][:collect_backtraces]
14
+ @sample_rate = AppOpticsAPM::Config[:sample_rate]
15
+ @sanitize_sql = AppOpticsAPM::Config[:sanitize_sql]
16
+ }
17
+ ENV['DBTYPE'] = "postgresql" unless ENV['DBTYPE']
18
+ end
19
+
20
+ after do
21
+ AppOpticsAPM.config_lock.synchronize {
22
+ AppOpticsAPM::Config[:action_controller][:collect_backtraces] = @collect_backtraces
23
+ AppOpticsAPM::Config[:tracing_mode] = @tm
24
+ AppOpticsAPM::Config[:sample_rate] = @sample_rate
25
+ AppOpticsAPM::Config[:sanitize_sql] = @sanitize_sql
26
+ }
27
+ end
28
+
29
+ it "should trace a request to a rails stack" do
30
+ uri = URI.parse('http://127.0.0.1:8140/hello/world')
31
+ r = Net::HTTP.get_response(uri)
32
+
33
+ traces = get_all_traces
34
+
35
+ traces.count.must_equal 7
36
+ unless defined?(JRUBY_VERSION)
37
+ # We don't test this under JRuby because the Java instrumentation
38
+ # for the DB drivers doesn't use our test reporter hence we won't
39
+ # see all trace events. :-( To be improved.
40
+ valid_edges?(traces).must_equal true
41
+ end
42
+ validate_outer_layers(traces, 'rack')
43
+
44
+ traces[0]['Layer'].must_equal "rack"
45
+ traces[0]['Label'].must_equal "entry"
46
+ traces[0]['URL'].must_equal "/hello/world"
47
+
48
+ traces[1]['Layer'].must_equal "rack"
49
+ traces[1]['Label'].must_equal "info"
50
+
51
+ traces[2]['Layer'].must_equal "rails"
52
+ traces[2]['Label'].must_equal "entry"
53
+ traces[2]['Controller'].must_equal "HelloController"
54
+ traces[2]['Action'].must_equal "world"
55
+
56
+ traces[3]['Layer'].must_equal "actionview"
57
+ traces[3]['Label'].must_equal "entry"
58
+
59
+ traces[4]['Layer'].must_equal "actionview"
60
+ traces[4]['Label'].must_equal "exit"
61
+
62
+ traces[5]['Layer'].must_equal "rails"
63
+ traces[5]['Label'].must_equal "exit"
64
+
65
+ traces[6]['Layer'].must_equal "rack"
66
+ traces[6]['Label'].must_equal "exit"
67
+
68
+ # Validate the existence of the response header
69
+ r.header.key?('X-Trace').must_equal true
70
+ r.header['X-Trace'].must_equal traces[6]['X-Trace']
71
+ end
72
+
73
+ it "should trace rails postgres db calls" do
74
+ # Skip for JRuby since the java instrumentation
75
+ # handles DB instrumentation for JRuby
76
+ skip if defined?(JRUBY_VERSION) || ENV['DBTYPE'] != 'postgresql'
77
+
78
+ uri = URI.parse('http://127.0.0.1:8140/hello/db')
79
+ r = Net::HTTP.get_response(uri)
80
+
81
+ traces = get_all_traces
82
+
83
+ traces.count.must_equal 13
84
+ valid_edges?(traces).must_equal true
85
+ validate_outer_layers(traces, 'rack')
86
+
87
+ traces[3]['Layer'].must_equal "activerecord"
88
+ traces[3]['Label'].must_equal "entry"
89
+ traces[3]['Flavor'].must_equal "postgresql"
90
+ traces[3]['Query'].must_equal "INSERT INTO \"widgets\" (\"name\", \"description\", \"created_at\", \"updated_at\") VALUES ($?, $?, $?, $?) RETURNING \"id\""
91
+ traces[3]['Name'].must_equal "SQL"
92
+ traces[3].key?('Backtrace').must_equal true
93
+
94
+ traces[4]['Layer'].must_equal "activerecord"
95
+ traces[4]['Label'].must_equal "exit"
96
+
97
+ traces[5]['Layer'].must_equal "activerecord"
98
+ traces[5]['Label'].must_equal "entry"
99
+ traces[5]['Flavor'].must_equal "postgresql"
100
+ traces[5]['Query'].must_equal "SELECT \"widgets\".* FROM \"widgets\" WHERE \"widgets\".\"name\" = $? ORDER BY \"widgets\".\"id\" ASC LIMIT $?"
101
+ traces[5]['Name'].must_equal "Widget Load"
102
+ traces[5].key?('Backtrace').must_equal true
103
+ traces[5].key?('QueryArgs').must_equal false
104
+
105
+ traces[6]['Layer'].must_equal "activerecord"
106
+ traces[6]['Label'].must_equal "exit"
107
+
108
+ traces[7]['Layer'].must_equal "activerecord"
109
+ traces[7]['Label'].must_equal "entry"
110
+ traces[7]['Flavor'].must_equal "postgresql"
111
+ traces[7]['Query'].must_equal "DELETE FROM \"widgets\" WHERE \"widgets\".\"id\" = $?"
112
+ traces[7]['Name'].must_equal "SQL"
113
+ traces[7].key?('Backtrace').must_equal true
114
+ traces[7].key?('QueryArgs').must_equal false
115
+
116
+ traces[8]['Layer'].must_equal "activerecord"
117
+ traces[8]['Label'].must_equal "exit"
118
+
119
+ # Validate the existence of the response header
120
+ r.header.key?('X-Trace').must_equal true
121
+ r.header['X-Trace'].must_equal traces[12]['X-Trace']
122
+ end
123
+
124
+ it "should trace rails mysql2 db calls" do
125
+ # Skip for JRuby since the java instrumentation
126
+ # handles DB instrumentation for JRuby
127
+ skip if defined?(JRUBY_VERSION) || ENV['DBTYPE'] != 'mysql2'
128
+
129
+ AppOpticsAPM::Config[:sanitize_sql] = false
130
+
131
+ uri = URI.parse('http://127.0.0.1:8140/hello/db')
132
+ r = Net::HTTP.get_response(uri)
133
+
134
+ traces = get_all_traces
135
+
136
+ traces.count.must_equal 15
137
+ valid_edges?(traces).must_equal true
138
+ validate_outer_layers(traces, 'rack')
139
+
140
+ entry_traces = traces.select { |tr| tr['Label'] == 'entry' }
141
+ entry_traces.count.must_equal 7
142
+
143
+ exit_traces = traces.select { |tr| tr['Label'] == 'exit' }
144
+ exit_traces.count.must_equal 7
145
+
146
+ entry_traces[2]['Layer'].must_equal "activerecord"
147
+ entry_traces[2]['Flavor'].must_equal "mysql"
148
+ entry_traces[2]['Query'].gsub!(/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/, 'the_date')
149
+ entry_traces[2]['Query'].must_equal "INSERT INTO `widgets` (`name`, `description`, `created_at`, `updated_at`) VALUES ('blah', 'This is an amazing widget.', 'the_date', 'the_date')"
150
+ entry_traces[2]['Name'].must_equal "SQL"
151
+ entry_traces[2].key?('Backtrace').must_equal true
152
+ entry_traces[2].key?('QueryArgs').must_equal true
153
+
154
+ entry_traces[3]['Layer'].must_equal "activerecord"
155
+ entry_traces[3]['Flavor'].must_equal "mysql"
156
+ entry_traces[3]['Query'].gsub!(/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/, 'the_date')
157
+ entry_traces[3]['Query'].must_equal "INSERT INTO `widgets` (`name`, `description`, `created_at`, `updated_at`) VALUES ('blah', 'This is an amazing widget.', 'the_date', 'the_date')"
158
+ entry_traces[3]['Name'].must_equal "SQL"
159
+ entry_traces[3].key?('Backtrace').must_equal true
160
+ entry_traces[3].key?('QueryArgs').must_equal true
161
+
162
+ entry_traces[4]['Layer'].must_equal "activerecord"
163
+ entry_traces[4]['Flavor'].must_equal "mysql"
164
+ entry_traces[4]['Query'].must_equal "SELECT `widgets`.* FROM `widgets` WHERE `widgets`.`name` = 'blah' ORDER BY `widgets`.`id` ASC LIMIT 1"
165
+ entry_traces[4]['Name'].must_equal "Widget Load"
166
+ entry_traces[4].key?('Backtrace').must_equal true
167
+ entry_traces[4].key?('QueryArgs').must_equal true
168
+
169
+ entry_traces[5]['Layer'].must_equal "activerecord"
170
+ entry_traces[5]['Flavor'].must_equal "mysql"
171
+ entry_traces[5]['Query'].gsub!(/\d+/, 'ID')
172
+ entry_traces[5]['Query'].must_equal "DELETE FROM `widgets` WHERE `widgets`.`id` = ID"
173
+ entry_traces[5]['Name'].must_equal "SQL"
174
+ entry_traces[5].key?('Backtrace').must_equal true
175
+ entry_traces[5].key?('QueryArgs').must_equal true
176
+
177
+ # Validate the existence of the response header
178
+ r.header.key?('X-Trace').must_equal true
179
+ r.header['X-Trace'].must_equal traces[14]['X-Trace']
180
+ end
181
+
182
+ it "should trace rails mysql2 db calls with sanitize sql" do
183
+ # Skip for JRuby since the java instrumentation
184
+ # handles DB instrumentation for JRuby
185
+ skip if defined?(JRUBY_VERSION) || ENV['DBTYPE'] != 'mysql2'
186
+
187
+ AppOpticsAPM::Config[:sanitize_sql] = true
188
+
189
+ uri = URI.parse('http://127.0.0.1:8140/hello/db')
190
+ r = Net::HTTP.get_response(uri)
191
+
192
+ traces = get_all_traces
193
+
194
+ traces.count.must_equal 15
195
+ valid_edges?(traces).must_equal true
196
+ validate_outer_layers(traces, 'rack')
197
+
198
+ entry_traces = traces.select { |tr| tr['Label'] == 'entry' }
199
+ entry_traces.count.must_equal 7
200
+
201
+ exit_traces = traces.select { |tr| tr['Label'] == 'exit' }
202
+ exit_traces.count.must_equal 7
203
+
204
+ entry_traces[2]['Layer'].must_equal "activerecord"
205
+ entry_traces[2]['Flavor'].must_equal "mysql"
206
+ entry_traces[2]['Query'].must_equal "INSERT INTO `widgets` (`name`, `description`, `created_at`, `updated_at`) VALUES (?, ?, ?, ?)"
207
+ entry_traces[2]['Name'].must_equal "SQL"
208
+ entry_traces[2].key?('Backtrace').must_equal true
209
+ entry_traces[2].key?('QueryArgs').must_equal false
210
+
211
+ entry_traces[3]['Layer'].must_equal "activerecord"
212
+ entry_traces[3]['Flavor'].must_equal "mysql"
213
+ entry_traces[3]['Query'].must_equal "INSERT INTO `widgets` (`name`, `description`, `created_at`, `updated_at`) VALUES (?, ?, ?, ?)"
214
+ entry_traces[3]['Name'].must_equal "SQL"
215
+ entry_traces[3].key?('Backtrace').must_equal true
216
+ entry_traces[3].key?('QueryArgs').must_equal false
217
+
218
+ entry_traces[4]['Layer'].must_equal "activerecord"
219
+ entry_traces[4]['Flavor'].must_equal "mysql"
220
+ entry_traces[4]['Query'].must_equal "SELECT `widgets`.* FROM `widgets` WHERE `widgets`.`name` = ? ORDER BY `widgets`.`id` ASC LIMIT ?"
221
+ entry_traces[4]['Name'].must_equal "Widget Load"
222
+ entry_traces[4].key?('Backtrace').must_equal true
223
+ entry_traces[4].key?('QueryArgs').must_equal false
224
+
225
+ entry_traces[5]['Layer'].must_equal "activerecord"
226
+ entry_traces[5]['Flavor'].must_equal "mysql"
227
+ entry_traces[5]['Query'].must_equal "DELETE FROM `widgets` WHERE `widgets`.`id` = ?"
228
+ entry_traces[5]['Name'].must_equal "SQL"
229
+ entry_traces[5].key?('Backtrace').must_equal true
230
+ entry_traces[5].key?('QueryArgs').must_equal false
231
+
232
+ # Validate the existence of the response header
233
+ r.header.key?('X-Trace').must_equal true
234
+ r.header['X-Trace'].must_equal traces[14]['X-Trace']
235
+ end
236
+
237
+ it "should trace a request to a rails metal stack" do
238
+
239
+ uri = URI.parse('http://127.0.0.1:8140/hello/metal')
240
+ r = Net::HTTP.get_response(uri)
241
+
242
+ traces = get_all_traces
243
+
244
+ traces.count.must_equal 5
245
+ unless defined?(JRUBY_VERSION)
246
+ # We don't test this under JRuby because the Java instrumentation
247
+ # for the DB drivers doesn't use our test reporter hence we won't
248
+ # see all trace events. :-( To be improved.
249
+ valid_edges?(traces).must_equal true
250
+ end
251
+ validate_outer_layers(traces, 'rack')
252
+
253
+ traces[0]['Layer'].must_equal "rack"
254
+ traces[0]['Label'].must_equal "entry"
255
+ traces[0]['URL'].must_equal "/hello/metal"
256
+
257
+ traces[1]['Layer'].must_equal "rack"
258
+ traces[1]['Label'].must_equal "info"
259
+
260
+ traces[2]['Label'].must_equal "profile_entry"
261
+ traces[2]['Language'].must_equal "ruby"
262
+ traces[2]['ProfileName'].must_equal "world"
263
+ traces[2]['MethodName'].must_equal "world"
264
+ traces[2]['Class'].must_equal "FerroController"
265
+ traces[2]['Controller'].must_equal "FerroController"
266
+ traces[2]['Action'].must_equal "world"
267
+
268
+ traces[3]['Label'].must_equal "profile_exit"
269
+ traces[3]['Language'].must_equal "ruby"
270
+ traces[3]['ProfileName'].must_equal "world"
271
+
272
+ traces[4]['Layer'].must_equal "rack"
273
+ traces[4]['Label'].must_equal "exit"
274
+
275
+ # Validate the existence of the response header
276
+ r.header.key?('X-Trace').must_equal true
277
+ r.header['X-Trace'].must_equal traces[4]['X-Trace']
278
+ end
279
+
280
+ it "should collect backtraces when true" do
281
+ AppOpticsAPM::Config[:action_controller][:collect_backtraces] = true
282
+
283
+ uri = URI.parse('http://127.0.0.1:8140/hello/world')
284
+ r = Net::HTTP.get_response(uri)
285
+
286
+ traces = get_all_traces
287
+
288
+ traces.count.must_equal 7
289
+ unless defined?(JRUBY_VERSION)
290
+ # We don't test this under JRuby because the Java instrumentation
291
+ # for the DB drivers doesn't use our test reporter hence we won't
292
+ # see all trace events. :-( To be improved.
293
+ valid_edges?(traces).must_equal true
294
+ end
295
+ validate_outer_layers(traces, 'rack')
296
+
297
+ traces[0]['Layer'].must_equal "rack"
298
+ traces[0]['Label'].must_equal "entry"
299
+ traces[0]['URL'].must_equal "/hello/world"
300
+
301
+ traces[1]['Layer'].must_equal "rack"
302
+ traces[1]['Label'].must_equal "info"
303
+
304
+ traces[2]['Layer'].must_equal "rails"
305
+ traces[2]['Label'].must_equal "entry"
306
+ traces[2]['Controller'].must_equal "HelloController"
307
+ traces[2]['Action'].must_equal "world"
308
+ traces[2].key?('Backtrace').must_equal true
309
+
310
+ traces[3]['Layer'].must_equal "actionview"
311
+ traces[3]['Label'].must_equal "entry"
312
+
313
+ traces[4]['Layer'].must_equal "actionview"
314
+ traces[4]['Label'].must_equal "exit"
315
+
316
+ traces[5]['Layer'].must_equal "rails"
317
+ traces[5]['Label'].must_equal "exit"
318
+
319
+ traces[6]['Layer'].must_equal "rack"
320
+ traces[6]['Label'].must_equal "exit"
321
+
322
+ # Validate the existence of the response header
323
+ r.header.key?('X-Trace').must_equal true
324
+ r.header['X-Trace'].must_equal traces[6]['X-Trace']
325
+ end
326
+
327
+ it "should NOT collect backtraces when false" do
328
+ AppOpticsAPM::Config[:action_controller][:collect_backtraces] = false
329
+
330
+ uri = URI.parse('http://127.0.0.1:8140/hello/world')
331
+ r = Net::HTTP.get_response(uri)
332
+
333
+ traces = get_all_traces
334
+
335
+ traces.count.must_equal 7
336
+ unless defined?(JRUBY_VERSION)
337
+ # We don't test this under JRuby because the Java instrumentation
338
+ # for the DB drivers doesn't use our test reporter hence we won't
339
+ # see all trace events. :-( To be improved.
340
+ valid_edges?(traces).must_equal true
341
+ end
342
+ validate_outer_layers(traces, 'rack')
343
+
344
+ traces[0]['Layer'].must_equal "rack"
345
+ traces[0]['Label'].must_equal "entry"
346
+ traces[0]['URL'].must_equal "/hello/world"
347
+
348
+ traces[1]['Layer'].must_equal "rack"
349
+ traces[1]['Label'].must_equal "info"
350
+
351
+ traces[2]['Layer'].must_equal "rails"
352
+ traces[2]['Label'].must_equal "entry"
353
+ traces[2]['Controller'].must_equal "HelloController"
354
+ traces[2]['Action'].must_equal "world"
355
+ traces[2].key?('Backtrace').must_equal false
356
+
357
+ traces[3]['Layer'].must_equal "actionview"
358
+ traces[3]['Label'].must_equal "entry"
359
+
360
+ traces[4]['Layer'].must_equal "actionview"
361
+ traces[4]['Label'].must_equal "exit"
362
+
363
+ traces[5]['Layer'].must_equal "rails"
364
+ traces[5]['Label'].must_equal "exit"
365
+
366
+ traces[6]['Layer'].must_equal "rack"
367
+ traces[6]['Label'].must_equal "exit"
368
+
369
+ # Validate the existence of the response header
370
+ r.header.key?('X-Trace').must_equal true
371
+ r.header['X-Trace'].must_equal traces[6]['X-Trace']
372
+ end
373
+
374
+ require_relative "rails_shared_tests"
375
+ end
376
+ end