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