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