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,554 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require "minitest_helper"
5
+
6
+ if defined?(::Rails)
7
+
8
+ describe "Rails3x" 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
+ ENV['TEST_DB_URI'] ||= 'http://127.0.0.1:8140'
19
+ end
20
+
21
+ after do
22
+ AppOpticsAPM.config_lock.synchronize {
23
+ AppOpticsAPM::Config[:action_controller][:collect_backtraces] = @collect_backtraces
24
+ AppOpticsAPM::Config[:tracing_mode] = @tm
25
+ AppOpticsAPM::Config[:sample_rate] = @sample_rate
26
+ AppOpticsAPM::Config[:sanitize_sql] = @sanitize_sql
27
+ }
28
+ end
29
+
30
+ it "should trace a request to a rails stack" do
31
+
32
+ uri = URI.parse("#{ENV['TEST_DB_URI']}/hello/world")
33
+ r = Net::HTTP.get_response(uri)
34
+
35
+ traces = get_all_traces
36
+
37
+ traces.count.must_equal 8
38
+ unless defined?(JRUBY_VERSION)
39
+ # We don't test this under JRuby because the Java instrumentation
40
+ # for the DB drivers doesn't use our test reporter hence we won't
41
+ # see all trace events. :-( To be improved.
42
+ valid_edges?(traces).must_equal true
43
+ end
44
+ validate_outer_layers(traces, 'rack')
45
+
46
+ traces[0]['Layer'].must_equal "rack"
47
+ traces[0]['Label'].must_equal "entry"
48
+ traces[0]['URL'].must_equal "/hello/world"
49
+
50
+ traces[1]['Layer'].must_equal "rack"
51
+ traces[1]['Label'].must_equal "info"
52
+
53
+ traces[2]['Layer'].must_equal "rails"
54
+ traces[2]['Label'].must_equal "entry"
55
+
56
+ traces[3]['Label'].must_equal "info"
57
+ traces[3]['Controller'].must_equal "HelloController"
58
+ traces[3]['Action'].must_equal "world"
59
+
60
+ traces[4]['Layer'].must_equal "actionview"
61
+ traces[4]['Label'].must_equal "entry"
62
+
63
+ traces[5]['Layer'].must_equal "actionview"
64
+ traces[5]['Label'].must_equal "exit"
65
+
66
+ traces[6]['Layer'].must_equal "rails"
67
+ traces[6]['Label'].must_equal "exit"
68
+
69
+ traces[7]['Layer'].must_equal "rack"
70
+ traces[7]['Label'].must_equal "exit"
71
+
72
+ # Validate the existence of the response header
73
+ r.header.key?('X-Trace').must_equal true
74
+ r.header['X-Trace'].must_equal traces[7]['X-Trace']
75
+ end
76
+
77
+ it "should trace a request to a rails metal stack" do
78
+
79
+ uri = URI.parse("#{ENV['TEST_DB_URI']}/hello/metal")
80
+ r = Net::HTTP.get_response(uri)
81
+
82
+ traces = get_all_traces
83
+
84
+ traces.count.must_equal 5
85
+ unless defined?(JRUBY_VERSION)
86
+ # We don't test this under JRuby because the Java instrumentation
87
+ # for the DB drivers doesn't use our test reporter hence we won't
88
+ # see all trace events. :-( To be improved.
89
+ valid_edges?(traces).must_equal true
90
+ end
91
+ validate_outer_layers(traces, 'rack')
92
+
93
+ traces[0]['Layer'].must_equal "rack"
94
+ traces[0]['Label'].must_equal "entry"
95
+ traces[0]['URL'].must_equal "/hello/metal"
96
+
97
+ traces[1]['Layer'].must_equal "rack"
98
+ traces[1]['Label'].must_equal "info"
99
+
100
+ traces[2]['Label'].must_equal "profile_entry"
101
+ traces[2]['Language'].must_equal "ruby"
102
+ traces[2]['ProfileName'].must_equal "world"
103
+ traces[2]['Class'].must_equal "FerroController"
104
+
105
+ traces[3]['Label'].must_equal "profile_exit"
106
+ traces[3]['Language'].must_equal "ruby"
107
+ traces[3]['ProfileName'].must_equal "world"
108
+
109
+ traces[4]['Layer'].must_equal "rack"
110
+ traces[4]['Label'].must_equal "exit"
111
+
112
+ # Validate the existence of the response header
113
+ r.header.key?('X-Trace').must_equal true
114
+ r.header['X-Trace'].must_equal traces[4]['X-Trace']
115
+ end
116
+
117
+ # TODO: should we have this test for other rails versions as well?
118
+ # TODO: review this test and why it fails (sometimes?)
119
+ it "should trace rails postgresql db calls" do
120
+ # Skip for JRuby since the java instrumentation
121
+ # handles DB instrumentation for JRuby
122
+ skip if defined?(JRUBY_VERSION) || ENV['DBTYPE'] != "postgresql"
123
+
124
+ uri = URI.parse('http://127.0.0.1:8140/hello/db')
125
+ r = Net::HTTP.get_response(uri)
126
+
127
+ traces = get_all_traces
128
+
129
+ traces.count.must_equal 14
130
+ valid_edges?(traces).must_equal true
131
+ validate_outer_layers(traces, 'rack')
132
+
133
+ traces[4]['Layer'].must_equal "activerecord"
134
+ traces[4]['Label'].must_equal "entry"
135
+ traces[4]['Flavor'].must_equal "postgresql"
136
+
137
+ # Some versions of rails adds in another space before the ORDER keyword.
138
+ # Make 2 or more consecutive spaces just 1
139
+ sql = traces[4]['Query'].gsub(/\s{2,}/, ' ')
140
+ sql.must_equal "INSERT INTO \"widgets\" (\"created_at\", \"description\", \"name\", \"updated_at\") VALUES ($?, $?, $?, $?) RETURNING \"id\""
141
+
142
+ traces[4]['Name'].must_equal "SQL"
143
+ traces[4].key?('Backtrace').must_equal true
144
+
145
+ traces[5]['Layer'].must_equal "activerecord"
146
+ traces[5]['Label'].must_equal "exit"
147
+
148
+ traces[6]['Layer'].must_equal "activerecord"
149
+ traces[6]['Label'].must_equal "entry"
150
+ traces[6]['Flavor'].must_equal "postgresql"
151
+ traces[6]['Query'].must_equal "SELECT \"widgets\".* FROM \"widgets\" WHERE \"widgets\".\"name\" = ? LIMIT ?"
152
+ traces[6]['Name'].must_equal "Widget Load"
153
+ traces[6].key?('Backtrace').must_equal true
154
+ traces[6].key?('QueryArgs').must_equal false
155
+
156
+ traces[7]['Layer'].must_equal "activerecord"
157
+ traces[7]['Label'].must_equal "exit"
158
+
159
+ traces[8]['Layer'].must_equal "activerecord"
160
+ traces[8]['Label'].must_equal "entry"
161
+ traces[8]['Flavor'].must_equal "postgresql"
162
+
163
+ # Remove the widget id so we can test everything else
164
+ sql = traces[8]['Query'].gsub(/\d+/, 'xxx')
165
+ sql.must_equal "DELETE FROM \"widgets\" WHERE \"widgets\".\"id\" = ?"
166
+
167
+ traces[8]['Name'].must_equal "SQL"
168
+ traces[8].key?('Backtrace').must_equal true
169
+ traces[8].key?('QueryArgs').must_equal false
170
+
171
+ traces[9]['Layer'].must_equal "activerecord"
172
+ traces[9]['Label'].must_equal "exit"
173
+
174
+ # Validate the existence of the response header
175
+ r['X-Trace'].must_equal traces[13]['X-Trace']
176
+ end
177
+
178
+ it "should trace rails mysql db calls" do
179
+ # Skip for JRuby since the java instrumentation
180
+ # handles DB instrumentation for JRuby
181
+ skip if defined?(JRUBY_VERSION) || ENV['DBTYPE'] != "mysql"
182
+
183
+ AppOpticsAPM::Config[:sanitize_sql] = false
184
+
185
+ uri = URI.parse("#{ENV['TEST_DB_URI']}/hello/db")
186
+ r = Net::HTTP.get_response(uri)
187
+
188
+ traces = get_all_traces
189
+ traces.count.must_equal 18
190
+ valid_edges?(traces).must_equal true
191
+ validate_outer_layers(traces, 'rack')
192
+
193
+ traces[4]['Layer'].must_equal "activerecord"
194
+ traces[4]['Label'].must_equal "entry"
195
+ traces[4]['Flavor'].must_equal "mysql"
196
+ traces[4]['Query'].must_equal "BEGIN"
197
+ traces[4].key?('Backtrace').must_equal true
198
+
199
+ traces[5]['Layer'].must_equal "activerecord"
200
+ traces[5]['Label'].must_equal "exit"
201
+
202
+ traces[6]['Layer'].must_equal "activerecord"
203
+ traces[6]['Label'].must_equal "entry"
204
+ traces[6]['Flavor'].must_equal "mysql"
205
+ traces[6]['Query'].must_equal "INSERT INTO `widgets` (`created_at`, `description`, `name`, `updated_at`) VALUES (?, ?, ?, ?)"
206
+ traces[6]['Name'].must_equal "SQL"
207
+ traces[6].key?('Backtrace').must_equal true
208
+ traces[6].key?('QueryArgs').must_equal true
209
+
210
+ traces[7]['Layer'].must_equal "activerecord"
211
+ traces[7]['Label'].must_equal "exit"
212
+
213
+ traces[8]['Layer'].must_equal "activerecord"
214
+ traces[8]['Label'].must_equal "entry"
215
+ traces[8]['Flavor'].must_equal "mysql"
216
+ traces[8]['Query'].must_equal "COMMIT"
217
+ traces[8].key?('Backtrace').must_equal true
218
+
219
+ traces[9]['Layer'].must_equal "activerecord"
220
+ traces[9]['Label'].must_equal "exit"
221
+
222
+ traces[10]['Layer'].must_equal "activerecord"
223
+ traces[10]['Label'].must_equal "entry"
224
+ traces[10]['Flavor'].must_equal "mysql"
225
+ traces[10]['Name'].must_equal "Widget Load"
226
+ traces[10].key?('Backtrace').must_equal true
227
+
228
+ # Some versions of rails adds in another space before the ORDER keyword.
229
+ # Make 2 or more consecutive spaces just 1
230
+ sql = traces[10]['Query'].gsub(/\s{2,}/, ' ')
231
+ sql.must_equal "SELECT `widgets`.* FROM `widgets` WHERE `widgets`.`name` = 'blah' LIMIT 1"
232
+
233
+ traces[11]['Layer'].must_equal "activerecord"
234
+ traces[11]['Label'].must_equal "exit"
235
+
236
+ traces[12]['Layer'].must_equal "activerecord"
237
+ traces[12]['Label'].must_equal "entry"
238
+ traces[12]['Flavor'].must_equal "mysql"
239
+ traces[12]['Name'].must_equal "SQL"
240
+ traces[12].key?('Backtrace').must_equal true
241
+ traces[12].key?('QueryArgs').must_equal false
242
+
243
+ # Replace the datestamps with xxx to make testing easier
244
+ sql = traces[12]['Query'].gsub(/\d+/, 'xxx')
245
+ sql.must_equal "DELETE FROM `widgets` WHERE `widgets`.`id` = xxx"
246
+
247
+ traces[13]['Layer'].must_equal "activerecord"
248
+ traces[13]['Label'].must_equal "exit"
249
+
250
+ traces[14]['Layer'].must_equal "actionview"
251
+ traces[14]['Label'].must_equal "entry"
252
+
253
+ # Validate the existence of the response header
254
+ r['X-Trace'].must_equal traces[17]['X-Trace']
255
+ end
256
+
257
+ it "should trace rails mysql db calls with sanitize sql" do
258
+ # Skip for JRuby since the java instrumentation
259
+ # handles DB instrumentation for JRuby
260
+ skip if defined?(JRUBY_VERSION) || ENV['DBTYPE'] != "mysql"
261
+
262
+ AppOpticsAPM::Config[:sanitize_sql] = true
263
+
264
+ uri = URI.parse("#{ENV['TEST_DB_URI']}/hello/db")
265
+ r = Net::HTTP.get_response(uri)
266
+
267
+ traces = get_all_traces
268
+ traces.count.must_equal 18
269
+ valid_edges?(traces).must_equal true
270
+ validate_outer_layers(traces, 'rack')
271
+
272
+ traces[4]['Layer'].must_equal "activerecord"
273
+ traces[4]['Label'].must_equal "entry"
274
+ traces[4]['Flavor'].must_equal "mysql"
275
+ traces[4]['Query'].must_equal "BEGIN"
276
+ traces[4].key?('Backtrace').must_equal true
277
+
278
+ traces[5]['Layer'].must_equal "activerecord"
279
+ traces[5]['Label'].must_equal "exit"
280
+
281
+ traces[6]['Layer'].must_equal "activerecord"
282
+ traces[6]['Label'].must_equal "entry"
283
+ traces[6]['Flavor'].must_equal "mysql"
284
+ traces[6]['Query'].must_equal "INSERT INTO `widgets` (`created_at`, `description`, `name`, `updated_at`) VALUES (?, ?, ?, ?)"
285
+ traces[6]['Name'].must_equal "SQL"
286
+ traces[6].key?('Backtrace').must_equal true
287
+ traces[6].key?('QueryArgs').must_equal false
288
+
289
+ traces[7]['Layer'].must_equal "activerecord"
290
+ traces[7]['Label'].must_equal "exit"
291
+
292
+ traces[8]['Layer'].must_equal "activerecord"
293
+ traces[8]['Label'].must_equal "entry"
294
+ traces[8]['Flavor'].must_equal "mysql"
295
+ traces[8]['Query'].must_equal "COMMIT"
296
+ traces[8].key?('Backtrace').must_equal true
297
+
298
+ traces[9]['Layer'].must_equal "activerecord"
299
+ traces[9]['Label'].must_equal "exit"
300
+
301
+ traces[10]['Layer'].must_equal "activerecord"
302
+ traces[10]['Label'].must_equal "entry"
303
+ traces[10]['Flavor'].must_equal "mysql"
304
+ traces[10]['Name'].must_equal "Widget Load"
305
+ traces[10].key?('Backtrace').must_equal true
306
+ traces[10]['Query'].gsub!(/ /, ' ')
307
+ traces[10]['Query'].must_equal "SELECT `widgets`.* FROM `widgets` WHERE `widgets`.`name` = ? LIMIT ?"
308
+
309
+ traces[11]['Layer'].must_equal "activerecord"
310
+ traces[11]['Label'].must_equal "exit"
311
+
312
+ traces[12]['Layer'].must_equal "activerecord"
313
+ traces[12]['Label'].must_equal "entry"
314
+ traces[12]['Flavor'].must_equal "mysql"
315
+ traces[12]['Name'].must_equal "SQL"
316
+ traces[12].key?('Backtrace').must_equal true
317
+ traces[12].key?('QueryArgs').must_equal false
318
+
319
+ # Replace the datestamps with xxx to make testing easier
320
+ sql = traces[12]['Query'].gsub(/\d+/, 'xxx')
321
+ sql.must_equal "DELETE FROM `widgets` WHERE `widgets`.`id` = ?"
322
+
323
+ traces[13]['Layer'].must_equal "activerecord"
324
+ traces[13]['Label'].must_equal "exit"
325
+
326
+ traces[14]['Layer'].must_equal "actionview"
327
+ traces[14]['Label'].must_equal "entry"
328
+
329
+ # Validate the existence of the response header
330
+ r['X-Trace'].must_equal traces[17]['X-Trace']
331
+ end
332
+
333
+ it "should trace rails mysql2 db calls" do
334
+ # Skip for JRuby since the java instrumentation
335
+ # handles DB instrumentation for JRuby
336
+ skip if defined?(JRUBY_VERSION) || ENV['DBTYPE'] != 'mysql2'
337
+
338
+ AppOpticsAPM::Config[:sanitize_sql] = false
339
+
340
+ uri = URI.parse("#{ENV['TEST_DB_URI']}/hello/db")
341
+ r = Net::HTTP.get_response(uri)
342
+
343
+ traces = get_all_traces
344
+
345
+ traces.count.must_equal 14
346
+ valid_edges?(traces).must_equal true
347
+ validate_outer_layers(traces, 'rack')
348
+
349
+ traces[4]['Layer'].must_equal "activerecord"
350
+ traces[4]['Label'].must_equal "entry"
351
+ traces[4]['Flavor'].must_equal "mysql"
352
+
353
+ # Replace the datestamps with xxx to make testing easier
354
+ traces[4]['Query'].gsub!(/\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d/, 'xxx')
355
+ traces[4]['Query'].must_equal "INSERT INTO `widgets` (`created_at`, `description`, `name`, `updated_at`) VALUES ('xxx', 'This is an amazing widget.', 'blah', 'xxx')"
356
+
357
+ traces[4]['Name'].must_equal "SQL"
358
+ traces[4].key?('Backtrace').must_equal true
359
+
360
+ traces[5]['Layer'].must_equal "activerecord"
361
+ traces[5]['Label'].must_equal "exit"
362
+
363
+ traces[6]['Layer'].must_equal "activerecord"
364
+ traces[6]['Label'].must_equal "entry"
365
+ traces[6]['Flavor'].must_equal "mysql"
366
+ traces[6]['Query'].must_equal "SELECT `widgets`.* FROM `widgets` WHERE `widgets`.`name` = 'blah' LIMIT 1"
367
+ traces[6]['Name'].must_equal "Widget Load"
368
+ traces[6].key?('Backtrace').must_equal true
369
+
370
+ traces[7]['Layer'].must_equal "activerecord"
371
+ traces[7]['Label'].must_equal "exit"
372
+
373
+ traces[8]['Layer'].must_equal "activerecord"
374
+ traces[8]['Label'].must_equal "entry"
375
+ traces[8]['Flavor'].must_equal "mysql"
376
+
377
+ # Replace the datestamps with xxx to make testing easier
378
+ sql = traces[8]['Query'].gsub(/\d+/, 'xxx')
379
+ sql.must_equal "DELETE FROM `widgets` WHERE `widgets`.`id` = xxx"
380
+
381
+ traces[8]['Name'].must_equal "SQL"
382
+ traces[8].key?('Backtrace').must_equal true
383
+ traces[8].key?('QueryArgs').must_equal false
384
+
385
+ traces[9]['Layer'].must_equal "activerecord"
386
+ traces[9]['Label'].must_equal "exit"
387
+
388
+ # Validate the existence of the response header
389
+ r.header.key?('X-Trace').must_equal true
390
+ r.header['X-Trace'].must_equal traces[13]['X-Trace']
391
+ end
392
+
393
+ it "should trace rails mysql2 db calls with sanitize sql" do
394
+ # Skip for JRuby since the java instrumentation
395
+ # handles DB instrumentation for JRuby
396
+ skip if defined?(JRUBY_VERSION) || ENV['DBTYPE'] != 'mysql2'
397
+
398
+ AppOpticsAPM::Config[:sanitize_sql] = true
399
+
400
+ uri = URI.parse("#{ENV['TEST_DB_URI']}/hello/db")
401
+ r = Net::HTTP.get_response(uri)
402
+
403
+ traces = get_all_traces
404
+
405
+ traces.count.must_equal 14
406
+ valid_edges?(traces).must_equal true
407
+ validate_outer_layers(traces, 'rack')
408
+
409
+ traces[4]['Layer'].must_equal "activerecord"
410
+ traces[4]['Label'].must_equal "entry"
411
+ traces[4]['Flavor'].must_equal "mysql"
412
+
413
+ traces[4]['Query'].must_equal "INSERT INTO `widgets` (`created_at`, `description`, `name`, `updated_at`) VALUES (?, ?, ?, ?)"
414
+
415
+ traces[4]['Name'].must_equal "SQL"
416
+ traces[4].key?('Backtrace').must_equal true
417
+
418
+ traces[5]['Layer'].must_equal "activerecord"
419
+ traces[5]['Label'].must_equal "exit"
420
+
421
+ traces[6]['Layer'].must_equal "activerecord"
422
+ traces[6]['Label'].must_equal "entry"
423
+ traces[6]['Flavor'].must_equal "mysql"
424
+ traces[6]['Query'].must_equal "SELECT `widgets`.* FROM `widgets` WHERE `widgets`.`name` = ? LIMIT ?"
425
+ traces[6]['Name'].must_equal "Widget Load"
426
+ traces[6].key?('Backtrace').must_equal true
427
+ traces[6].key?('QueryArgs').must_equal false
428
+
429
+ traces[7]['Layer'].must_equal "activerecord"
430
+ traces[7]['Label'].must_equal "exit"
431
+
432
+ traces[8]['Layer'].must_equal "activerecord"
433
+ traces[8]['Label'].must_equal "entry"
434
+ traces[8]['Flavor'].must_equal "mysql"
435
+
436
+ # Replace the datestamps with xxx to make testing easier
437
+ sql = traces[8]['Query'].gsub(/\d+/, 'xxx')
438
+ sql.must_equal "DELETE FROM `widgets` WHERE `widgets`.`id` = ?"
439
+
440
+ traces[8]['Name'].must_equal "SQL"
441
+ traces[8].key?('Backtrace').must_equal true
442
+ traces[8].key?('QueryArgs').must_equal false
443
+
444
+ traces[9]['Layer'].must_equal "activerecord"
445
+ traces[9]['Label'].must_equal "exit"
446
+
447
+ # Validate the existence of the response header
448
+ r.header.key?('X-Trace').must_equal true
449
+ r.header['X-Trace'].must_equal traces[13]['X-Trace']
450
+ end
451
+
452
+ it "should collect backtraces when true" do
453
+
454
+ AppOpticsAPM::Config[:action_controller][:collect_backtraces] = true
455
+
456
+ uri = URI.join(ENV['TEST_DB_URI'], '/hello/world')
457
+ r = Net::HTTP.get_response(uri)
458
+
459
+ traces = get_all_traces
460
+
461
+ traces.count.must_equal 8
462
+ unless defined?(JRUBY_VERSION)
463
+ # We don't test this under JRuby because the Java instrumentation
464
+ # for the DB drivers doesn't use our test reporter hence we won't
465
+ # see all trace events. :-( To be improved.
466
+ valid_edges?(traces).must_equal true
467
+ end
468
+ validate_outer_layers(traces, 'rack')
469
+
470
+ traces[0]['Layer'].must_equal "rack"
471
+ traces[0]['Label'].must_equal "entry"
472
+ traces[0]['URL'].must_equal "/hello/world"
473
+
474
+ traces[1]['Layer'].must_equal "rack"
475
+ traces[1]['Label'].must_equal "info"
476
+
477
+ traces[2]['Layer'].must_equal "rails"
478
+ traces[2]['Label'].must_equal "entry"
479
+
480
+ traces[3]['Label'].must_equal "info"
481
+ traces[3]['Controller'].must_equal "HelloController"
482
+ traces[3]['Action'].must_equal "world"
483
+ traces[3].key?('Backtrace').must_equal true
484
+
485
+ traces[4]['Layer'].must_equal "actionview"
486
+ traces[4]['Label'].must_equal "entry"
487
+
488
+ traces[5]['Layer'].must_equal "actionview"
489
+ traces[5]['Label'].must_equal "exit"
490
+
491
+ traces[6]['Layer'].must_equal "rails"
492
+ traces[6]['Label'].must_equal "exit"
493
+
494
+ traces[7]['Layer'].must_equal "rack"
495
+ traces[7]['Label'].must_equal "exit"
496
+
497
+ # Validate the existence of the response header
498
+ r.header.key?('X-Trace').must_equal true
499
+ r.header['X-Trace'].must_equal traces[7]['X-Trace']
500
+ end
501
+
502
+ it "should NOT collect backtraces when false" do
503
+
504
+ AppOpticsAPM::Config[:action_controller][:collect_backtraces] = false
505
+
506
+ uri = URI.parse("#{ENV['TEST_DB_URI']}/hello/world")
507
+ r = Net::HTTP.get_response(uri)
508
+
509
+ traces = get_all_traces
510
+
511
+ traces.count.must_equal 8
512
+ unless defined?(JRUBY_VERSION)
513
+ # We don't test this under JRuby because the Java instrumentation
514
+ # for the DB drivers doesn't use our test reporter hence we won't
515
+ # see all trace events. :-( To be improved.
516
+ valid_edges?(traces).must_equal true
517
+ end
518
+ validate_outer_layers(traces, 'rack')
519
+
520
+ traces[0]['Layer'].must_equal "rack"
521
+ traces[0]['Label'].must_equal "entry"
522
+ traces[0]['URL'].must_equal "/hello/world"
523
+
524
+ traces[1]['Layer'].must_equal "rack"
525
+ traces[1]['Label'].must_equal "info"
526
+
527
+ traces[2]['Layer'].must_equal "rails"
528
+ traces[2]['Label'].must_equal "entry"
529
+
530
+ traces[3]['Label'].must_equal "info"
531
+ traces[3]['Controller'].must_equal "HelloController"
532
+ traces[3]['Action'].must_equal "world"
533
+ traces[3].key?('Backtrace').must_equal false
534
+
535
+ traces[4]['Layer'].must_equal "actionview"
536
+ traces[4]['Label'].must_equal "entry"
537
+
538
+ traces[5]['Layer'].must_equal "actionview"
539
+ traces[5]['Label'].must_equal "exit"
540
+
541
+ traces[6]['Layer'].must_equal "rails"
542
+ traces[6]['Label'].must_equal "exit"
543
+
544
+ traces[7]['Layer'].must_equal "rack"
545
+ traces[7]['Label'].must_equal "exit"
546
+
547
+ # Validate the existence of the response header
548
+ r.header.key?('X-Trace').must_equal true
549
+ r.header['X-Trace'].must_equal traces[7]['X-Trace']
550
+ end
551
+
552
+ require_relative "rails_shared_tests"
553
+ end
554
+ end