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,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