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