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,288 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'minitest_helper'
5
+
6
+ if RUBY_VERSION >= '2.0.0'
7
+ describe "RestClient" do
8
+ before do
9
+ clear_all_traces
10
+ @collect_backtraces = AppOpticsAPM::Config[:rest_client][:collect_backtraces]
11
+ end
12
+
13
+ after do
14
+ AppOpticsAPM::Config[:rest_client][:collect_backtraces] = @collect_backtraces
15
+ end
16
+
17
+ it 'RestClient should be defined and ready' do
18
+ defined?(::RestClient).wont_match nil
19
+ end
20
+
21
+ it 'RestClient should have appoptics_apm methods defined' do
22
+ [ :execute_with_appoptics ].each do |m|
23
+ ::RestClient::Request.method_defined?(m).must_equal true
24
+ end
25
+ end
26
+
27
+ it "should report rest-client version in __Init" do
28
+ init_kvs = ::AppOpticsAPM::Util.build_init_report
29
+
30
+ init_kvs.key?('Ruby.rest-client.Version').must_equal true
31
+ init_kvs['Ruby.rest-client.Version'].must_equal ::RestClient::VERSION
32
+ end
33
+
34
+ it "should trace a request to an instr'd app" do
35
+ response = nil
36
+
37
+ AppOpticsAPM::API.start_trace('rest_client_test') do
38
+ response = RestClient.get 'http://127.0.0.1:8101/'
39
+ end
40
+
41
+ traces = get_all_traces
42
+ traces.count.must_equal 10
43
+
44
+ valid_edges?(traces).must_equal true
45
+ validate_outer_layers(traces, 'rest_client_test')
46
+
47
+ traces[1]['Layer'].must_equal 'rest-client'
48
+ traces[1]['Label'].must_equal 'entry'
49
+
50
+ traces[2]['Layer'].must_equal 'net-http'
51
+ traces[2]['Label'].must_equal 'entry'
52
+
53
+ traces[6]['Layer'].must_equal 'net-http'
54
+ traces[6]['Label'].must_equal 'info'
55
+ traces[6]['IsService'].must_equal 1
56
+ traces[6]['RemoteProtocol'].must_equal 'HTTP'
57
+ traces[6]['RemoteHost'].must_equal '127.0.0.1:8101'
58
+ traces[6]['ServiceArg'].must_equal '/'
59
+ traces[6]['HTTPMethod'].must_equal 'GET'
60
+ traces[6]['HTTPStatus'].must_equal "200"
61
+ traces[6].key?('Backtrace').must_equal AppOpticsAPM::Config[:nethttp][:collect_backtraces]
62
+
63
+ traces[7]['Layer'].must_equal 'net-http'
64
+ traces[7]['Label'].must_equal 'exit'
65
+
66
+ traces[8]['Layer'].must_equal 'rest-client'
67
+ traces[8]['Label'].must_equal 'exit'
68
+
69
+ response.headers.key?(:x_trace).wont_equal nil
70
+ xtrace = response.headers[:x_trace]
71
+
72
+ AppOpticsAPM::XTrace.valid?(xtrace).must_equal true
73
+ end
74
+
75
+ it 'should trace a raw GET request' do
76
+ AppOpticsAPM::API.start_trace('rest_client_test') do
77
+ RestClient.get 'http://127.0.0.1:8101/?a=1'
78
+ end
79
+
80
+ traces = get_all_traces
81
+ traces.count.must_equal 10
82
+
83
+ valid_edges?(traces).must_equal true
84
+ validate_outer_layers(traces, 'rest_client_test')
85
+
86
+ traces[1]['Layer'].must_equal 'rest-client'
87
+ traces[1]['Label'].must_equal 'entry'
88
+
89
+ traces[2]['Layer'].must_equal 'net-http'
90
+ traces[2]['Label'].must_equal 'entry'
91
+
92
+ traces[6]['Layer'].must_equal 'net-http'
93
+ traces[6]['Label'].must_equal 'info'
94
+ traces[6]['IsService'].must_equal 1
95
+ traces[6]['RemoteProtocol'].must_equal 'HTTP'
96
+ traces[6]['RemoteHost'].must_equal '127.0.0.1:8101'
97
+ traces[6]['ServiceArg'].must_equal '/?a=1'
98
+ traces[6]['HTTPMethod'].must_equal 'GET'
99
+ traces[6]['HTTPStatus'].must_equal "200"
100
+ traces[6].key?('Backtrace').must_equal AppOpticsAPM::Config[:nethttp][:collect_backtraces]
101
+
102
+ traces[7]['Layer'].must_equal 'net-http'
103
+ traces[7]['Label'].must_equal 'exit'
104
+
105
+ traces[8]['Layer'].must_equal 'rest-client'
106
+ traces[8]['Label'].must_equal 'exit'
107
+ end
108
+
109
+ it 'should trace a raw POST request' do
110
+ AppOpticsAPM::API.start_trace('rest_client_test') do
111
+ RestClient.post 'http://127.0.0.1:8101/', :param1 => 'one', :nested => { :param2 => 'two' }
112
+ end
113
+
114
+ traces = get_all_traces
115
+ traces.count.must_equal 10
116
+
117
+ valid_edges?(traces).must_equal true
118
+ validate_outer_layers(traces, 'rest_client_test')
119
+
120
+ traces[1]['Layer'].must_equal 'rest-client'
121
+ traces[1]['Label'].must_equal 'entry'
122
+
123
+ traces[2]['Layer'].must_equal 'net-http'
124
+ traces[2]['Label'].must_equal 'entry'
125
+
126
+ traces[6]['Layer'].must_equal 'net-http'
127
+ traces[6]['Label'].must_equal 'info'
128
+ traces[6]['IsService'].must_equal 1
129
+ traces[6]['RemoteProtocol'].must_equal 'HTTP'
130
+ traces[6]['RemoteHost'].must_equal '127.0.0.1:8101'
131
+ traces[6]['ServiceArg'].must_equal '/'
132
+ traces[6]['HTTPMethod'].must_equal 'POST'
133
+ traces[6]['HTTPStatus'].must_equal "200"
134
+ traces[6].key?('Backtrace').must_equal AppOpticsAPM::Config[:nethttp][:collect_backtraces]
135
+
136
+ traces[7]['Layer'].must_equal 'net-http'
137
+ traces[7]['Label'].must_equal 'exit'
138
+
139
+ traces[8]['Layer'].must_equal 'rest-client'
140
+ traces[8]['Label'].must_equal 'exit'
141
+ end
142
+
143
+ it 'should trace a ActiveResource style GET request' do
144
+ AppOpticsAPM::API.start_trace('rest_client_test') do
145
+ resource = RestClient::Resource.new 'http://127.0.0.1:8101/?a=1'
146
+ resource.get
147
+ end
148
+
149
+ traces = get_all_traces
150
+ traces.count.must_equal 10
151
+
152
+ valid_edges?(traces).must_equal true
153
+ validate_outer_layers(traces, 'rest_client_test')
154
+
155
+ traces[1]['Layer'].must_equal 'rest-client'
156
+ traces[1]['Label'].must_equal 'entry'
157
+
158
+ traces[2]['Layer'].must_equal 'net-http'
159
+ traces[2]['Label'].must_equal 'entry'
160
+
161
+ traces[6]['Layer'].must_equal 'net-http'
162
+ traces[6]['Label'].must_equal 'info'
163
+ traces[6]['IsService'].must_equal 1
164
+ traces[6]['RemoteProtocol'].must_equal 'HTTP'
165
+ traces[6]['RemoteHost'].must_equal '127.0.0.1:8101'
166
+ traces[6]['ServiceArg'].must_equal '/?a=1'
167
+ traces[6]['HTTPMethod'].must_equal 'GET'
168
+ traces[6]['HTTPStatus'].must_equal "200"
169
+ traces[6].key?('Backtrace').must_equal AppOpticsAPM::Config[:nethttp][:collect_backtraces]
170
+
171
+ traces[7]['Layer'].must_equal 'net-http'
172
+ traces[7]['Label'].must_equal 'exit'
173
+
174
+ traces[8]['Layer'].must_equal 'rest-client'
175
+ traces[8]['Label'].must_equal 'exit'
176
+ end
177
+
178
+ it 'should trace requests with redirects' do
179
+ response = nil
180
+
181
+ AppOpticsAPM::API.start_trace('rest_client_test') do
182
+ resource = RestClient::Resource.new 'http://127.0.0.1:8101/redirectme?redirect_test'
183
+ response = resource.get
184
+ end
185
+
186
+ traces = get_all_traces
187
+ traces.count.must_equal 18
188
+
189
+ valid_edges?(traces).must_equal true
190
+ validate_outer_layers(traces, 'rest_client_test')
191
+
192
+ traces[1]['Layer'].must_equal 'rest-client'
193
+ traces[1]['Label'].must_equal 'entry'
194
+
195
+ traces[2]['Layer'].must_equal 'net-http'
196
+ traces[2]['Label'].must_equal 'entry'
197
+
198
+ traces[6]['Layer'].must_equal 'net-http'
199
+ traces[6]['Label'].must_equal 'info'
200
+ traces[6]['IsService'].must_equal 1
201
+ traces[6]['RemoteProtocol'].must_equal 'HTTP'
202
+ traces[6]['RemoteHost'].must_equal '127.0.0.1:8101'
203
+ traces[6]['ServiceArg'].must_equal '/redirectme?redirect_test'
204
+ traces[6]['HTTPMethod'].must_equal 'GET'
205
+ traces[6]['HTTPStatus'].must_equal "301"
206
+ traces[6].key?('Backtrace').must_equal AppOpticsAPM::Config[:nethttp][:collect_backtraces]
207
+
208
+ traces[7]['Layer'].must_equal 'net-http'
209
+ traces[7]['Label'].must_equal 'exit'
210
+
211
+ traces[8]['Layer'].must_equal 'rest-client'
212
+ traces[8]['Label'].must_equal 'entry'
213
+
214
+ traces[9]['Layer'].must_equal 'net-http'
215
+ traces[9]['Label'].must_equal 'entry'
216
+
217
+ traces[13]['Layer'].must_equal 'net-http'
218
+ traces[13]['Label'].must_equal 'info'
219
+ traces[13]['IsService'].must_equal 1
220
+ traces[13]['RemoteProtocol'].must_equal 'HTTP'
221
+ traces[13]['RemoteHost'].must_equal '127.0.0.1:8101'
222
+ traces[13]['ServiceArg'].must_equal '/'
223
+ traces[13]['HTTPMethod'].must_equal 'GET'
224
+ traces[13]['HTTPStatus'].must_equal "200"
225
+ traces[13].key?('Backtrace').must_equal AppOpticsAPM::Config[:nethttp][:collect_backtraces]
226
+
227
+ traces[14]['Layer'].must_equal 'net-http'
228
+ traces[14]['Label'].must_equal 'exit'
229
+
230
+ traces[15]['Layer'].must_equal 'rest-client'
231
+ traces[15]['Label'].must_equal 'exit'
232
+
233
+ traces[16]['Layer'].must_equal 'rest-client'
234
+ traces[16]['Label'].must_equal 'exit'
235
+ end
236
+
237
+ it 'should trace and capture raised exceptions' do
238
+ AppOpticsAPM::API.start_trace('rest_client_test') do
239
+ begin
240
+ RestClient.get 'http://s6KTgaz7636z/resource'
241
+ rescue
242
+ # We want an exception to be raised. Just don't raise
243
+ # it beyond this point.
244
+ end
245
+ end
246
+
247
+ traces = get_all_traces
248
+ traces.count.must_equal 5
249
+
250
+ valid_edges?(traces).must_equal true
251
+ validate_outer_layers(traces, 'rest_client_test')
252
+
253
+ traces[1]['Layer'].must_equal 'rest-client'
254
+ traces[1]['Label'].must_equal 'entry'
255
+
256
+ traces[2]['Layer'].must_equal 'rest-client'
257
+ traces[2]['Label'].must_equal 'error'
258
+ traces[2]['ErrorClass'].must_equal 'SocketError'
259
+ traces[2].key?('ErrorMsg').must_equal true
260
+ traces[2].key?('Backtrace').must_equal true
261
+
262
+ traces[3]['Layer'].must_equal 'rest-client'
263
+ traces[3]['Label'].must_equal 'exit'
264
+ end
265
+
266
+ it 'should obey :collect_backtraces setting when true' do
267
+ AppOpticsAPM::Config[:rest_client][:collect_backtraces] = true
268
+
269
+ AppOpticsAPM::API.start_trace('rest_client_test') do
270
+ RestClient.get('http://127.0.0.1:8101/', {:a => 1})
271
+ end
272
+
273
+ traces = get_all_traces
274
+ layer_has_key(traces, 'rest-client', 'Backtrace')
275
+ end
276
+
277
+ it 'should obey :collect_backtraces setting when false' do
278
+ AppOpticsAPM::Config[:rest_client][:collect_backtraces] = false
279
+
280
+ AppOpticsAPM::API.start_trace('rest_client_test') do
281
+ RestClient.get('http://127.0.0.1:8101/', {:a => 1})
282
+ end
283
+
284
+ traces = get_all_traces
285
+ layer_doesnt_have_key(traces, 'rest-client', 'Backtrace')
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,353 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'minitest_helper'
5
+
6
+ if defined?(::Sequel) && !defined?(JRUBY_VERSION)
7
+
8
+ AppOpticsAPM::Test.set_mysql2_env
9
+ MYSQL2_DB = Sequel.connect(ENV['DATABASE_URL'])
10
+
11
+ unless MYSQL2_DB.table_exists?(:items)
12
+ MYSQL2_DB.create_table :items do
13
+ primary_key :id
14
+ String :name
15
+ Float :price
16
+ end
17
+ end
18
+
19
+ describe "Sequel (mysql2)" do
20
+ before do
21
+ clear_all_traces
22
+
23
+ # These are standard entry/exit KVs that are passed up with all sequel operations
24
+ @entry_kvs = {
25
+ 'Layer' => 'sequel',
26
+ 'Label' => 'entry',
27
+ 'Database' => 'travis_ci_test',
28
+ 'RemoteHost' => ENV.key?('DOCKER_MYSQL_PASS') ? 'mysql' : '127.0.0.1',
29
+ 'RemotePort' => 3306 }
30
+
31
+ @exit_kvs = { 'Layer' => 'sequel', 'Label' => 'exit' }
32
+ @collect_backtraces = AppOpticsAPM::Config[:sequel][:collect_backtraces]
33
+ @sanitize_sql = AppOpticsAPM::Config[:sanitize_sql]
34
+ end
35
+
36
+ after do
37
+ AppOpticsAPM::Config[:sequel][:collect_backtraces] = @collect_backtraces
38
+ AppOpticsAPM::Config[:sanitize_sql] = @sanitize_sql
39
+ end
40
+
41
+ it 'Stock sequel should be loaded, defined and ready' do
42
+ defined?(::Sequel).wont_match nil
43
+ end
44
+
45
+ it 'sequel should have appoptics_apm methods defined' do
46
+ # Sequel::Database
47
+ ::Sequel::Database.method_defined?(:run_with_appoptics).must_equal true
48
+
49
+ # Sequel::Dataset
50
+ ::Sequel::Dataset.method_defined?(:execute_with_appoptics).must_equal true
51
+ ::Sequel::Dataset.method_defined?(:execute_ddl_with_appoptics).must_equal true
52
+ ::Sequel::Dataset.method_defined?(:execute_dui_with_appoptics).must_equal true
53
+ ::Sequel::Dataset.method_defined?(:execute_insert_with_appoptics).must_equal true
54
+ end
55
+
56
+ it "should obey :collect_backtraces setting when true" do
57
+ AppOpticsAPM::Config[:sequel][:collect_backtraces] = true
58
+
59
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
60
+ MYSQL2_DB.run('select 1')
61
+ end
62
+
63
+ traces = get_all_traces
64
+ layer_has_key(traces, 'sequel', 'Backtrace')
65
+ end
66
+
67
+ it "should obey :collect_backtraces setting when false" do
68
+ AppOpticsAPM::Config[:sequel][:collect_backtraces] = false
69
+
70
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
71
+ MYSQL2_DB.run('select 1')
72
+ end
73
+
74
+ traces = get_all_traces
75
+ layer_doesnt_have_key(traces, 'sequel', 'Backtrace')
76
+ end
77
+
78
+ it 'should trace MYSQL2_DB.run insert' do
79
+ AppOpticsAPM::Config[:sanitize_sql] = false
80
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
81
+ MYSQL2_DB.run("insert into items (name, price) values ('blah', '12')")
82
+ end
83
+
84
+ traces = get_all_traces
85
+
86
+ traces.count.must_equal 4
87
+ validate_outer_layers(traces, 'sequel_test')
88
+
89
+ validate_event_keys(traces[1], @entry_kvs)
90
+ traces[1]['Query'].must_equal "insert into items (name, price) values ('blah', '12')"
91
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
92
+ validate_event_keys(traces[2], @exit_kvs)
93
+ end
94
+
95
+ it 'should trace MYSQL2_DB.run select' do
96
+ AppOpticsAPM::Config[:sanitize_sql] = false
97
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
98
+ MYSQL2_DB.run("select 1")
99
+ end
100
+
101
+ traces = get_all_traces
102
+
103
+ traces.count.must_equal 4
104
+ validate_outer_layers(traces, 'sequel_test')
105
+
106
+ validate_event_keys(traces[1], @entry_kvs)
107
+ traces[1]['Query'].must_equal "select 1"
108
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
109
+ validate_event_keys(traces[2], @exit_kvs)
110
+ end
111
+
112
+ it 'should trace a dataset insert and count' do
113
+ AppOpticsAPM::Config[:sanitize_sql] = false
114
+ items = MYSQL2_DB[:items]
115
+ items.count
116
+
117
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
118
+ items.insert(:name => 'abc', :price => 2.514)
119
+ items.count
120
+ end
121
+
122
+ traces = get_all_traces
123
+
124
+ traces.count.must_equal 6
125
+ validate_outer_layers(traces, 'sequel_test')
126
+
127
+ validate_event_keys(traces[1], @entry_kvs)
128
+
129
+ # SQL column/value order can vary between Ruby and gem versions
130
+ # Use must_include to test against one or the other
131
+ [
132
+ "INSERT INTO `items` (`price`, `name`) VALUES (2.514, 'abc')",
133
+ "INSERT INTO `items` (`name`, `price`) VALUES ('abc', 2.514)"
134
+ ].must_include traces[1]['Query']
135
+
136
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
137
+ traces[2]['Layer'].must_equal "sequel"
138
+ traces[2]['Label'].must_equal "exit"
139
+ traces[3]['Query'].downcase.must_equal "select count(*) as `count` from `items` limit 1"
140
+ validate_event_keys(traces[4], @exit_kvs)
141
+ end
142
+
143
+ it 'should trace a dataset insert and obey query privacy' do
144
+ AppOpticsAPM::Config[:sanitize_sql] = true
145
+ items = MYSQL2_DB[:items]
146
+ items.count
147
+
148
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
149
+ items.insert(:name => 'abc', :price => 2.514461383352462)
150
+ end
151
+
152
+ traces = get_all_traces
153
+
154
+ traces.count.must_equal 4
155
+ validate_outer_layers(traces, 'sequel_test')
156
+
157
+ validate_event_keys(traces[1], @entry_kvs)
158
+
159
+ # SQL column/value order can vary between Ruby and gem versions
160
+ # Use must_include to test against one or the other
161
+ [
162
+ "INSERT INTO `items` (`price`, `name`) VALUES (?, ?)",
163
+ "INSERT INTO `items` (`name`, `price`) VALUES (?, ?)"
164
+ ].must_include traces[1]['Query']
165
+
166
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
167
+ validate_event_keys(traces[2], @exit_kvs)
168
+ end
169
+
170
+ it 'should trace a dataset filter' do
171
+ AppOpticsAPM::Config[:sanitize_sql] = false
172
+ items = MYSQL2_DB[:items]
173
+ items.count
174
+
175
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
176
+ items.filter(:name => 'abc').all
177
+ end
178
+
179
+ traces = get_all_traces
180
+
181
+ traces.count.must_equal 4
182
+ validate_outer_layers(traces, 'sequel_test')
183
+
184
+ validate_event_keys(traces[1], @entry_kvs)
185
+ traces[1]['Query'].must_equal "SELECT * FROM `items` WHERE (`name` = 'abc')"
186
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
187
+ validate_event_keys(traces[2], @exit_kvs)
188
+ end
189
+
190
+ it 'should trace create table' do
191
+ AppOpticsAPM::Config[:sanitize_sql] = false
192
+ # Drop the table if it already exists
193
+ MYSQL2_DB.drop_table(:fake) if MYSQL2_DB.table_exists?(:fake)
194
+
195
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
196
+ MYSQL2_DB.create_table :fake do
197
+ primary_key :id
198
+ String :name
199
+ Float :price
200
+ end
201
+ end
202
+
203
+ traces = get_all_traces
204
+
205
+ traces.count.must_equal 4
206
+ validate_outer_layers(traces, 'sequel_test')
207
+
208
+ validate_event_keys(traces[1], @entry_kvs)
209
+ traces[1]['Query'].must_equal "CREATE TABLE `fake` (`id` integer PRIMARY KEY AUTO_INCREMENT, `name` varchar(255), `price` double precision)"
210
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
211
+ validate_event_keys(traces[2], @exit_kvs)
212
+ end
213
+
214
+ it 'should trace add index' do
215
+ AppOpticsAPM::Config[:sanitize_sql] = false
216
+ # Drop the table if it already exists
217
+ MYSQL2_DB.drop_table(:fake) if MYSQL2_DB.table_exists?(:fake)
218
+
219
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
220
+ MYSQL2_DB.create_table :fake do
221
+ primary_key :id
222
+ String :name
223
+ Float :price
224
+ end
225
+ end
226
+
227
+ traces = get_all_traces
228
+
229
+ traces.count.must_equal 4
230
+ validate_outer_layers(traces, 'sequel_test')
231
+
232
+ validate_event_keys(traces[1], @entry_kvs)
233
+ traces[1]['Query'].must_equal "CREATE TABLE `fake` (`id` integer PRIMARY KEY AUTO_INCREMENT, `name` varchar(255), `price` double precision)"
234
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
235
+ validate_event_keys(traces[2], @exit_kvs)
236
+ end
237
+
238
+ it 'should capture and report exceptions' do
239
+ begin
240
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
241
+ MYSQL2_DB.run("this is bad sql")
242
+ end
243
+ rescue
244
+ # Do nothing - we're testing exception logging
245
+ end
246
+
247
+ traces = get_all_traces
248
+
249
+ traces.count.must_equal 5
250
+ validate_outer_layers(traces, 'sequel_test')
251
+
252
+ validate_event_keys(traces[1], @entry_kvs)
253
+ traces[1]['Query'].must_equal "this is bad sql"
254
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
255
+ traces[2]['Layer'].must_equal "sequel"
256
+ traces[2]['Label'].must_equal "error"
257
+ traces[2].has_key?('Backtrace').must_equal true
258
+ traces[2]['ErrorClass'].must_equal "Sequel::DatabaseError"
259
+ validate_event_keys(traces[3], @exit_kvs)
260
+ end
261
+
262
+ it 'should trace placeholder queries with bound vars' do
263
+ AppOpticsAPM::Config[:sanitize_sql] = false
264
+ items = MYSQL2_DB[:items]
265
+ items.count
266
+
267
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
268
+ ds = items.where(:name=>:$n)
269
+ ds.call(:select, :n=>'abc')
270
+ ds.call(:delete, :n=>'cba')
271
+ end
272
+
273
+ traces = get_all_traces
274
+
275
+ traces.count.must_equal 6
276
+ validate_outer_layers(traces, 'sequel_test')
277
+
278
+ validate_event_keys(traces[1], @entry_kvs)
279
+ if ::Sequel::VERSION > '4.36.0'
280
+ traces[1]['Query'].must_equal "SELECT * FROM `items` WHERE (`name` = ?)"
281
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
282
+ traces[3]['Query'].must_equal "DELETE FROM `items` WHERE (`name` = ?)"
283
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
284
+ else
285
+ traces[1]['Query'].must_equal "SELECT * FROM `items` WHERE (`name` = 'abc')"
286
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
287
+ traces[3]['Query'].must_equal "DELETE FROM `items` WHERE (`name` = 'cba')"
288
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
289
+ end
290
+ validate_event_keys(traces[2], @exit_kvs)
291
+ end
292
+
293
+ it 'should trace prepared statements' do
294
+ AppOpticsAPM::Config[:sanitize_sql] = false
295
+ ds = MYSQL2_DB[:items].filter(:name=>:$n)
296
+ ps = ds.prepare(:select, :select_by_name)
297
+
298
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
299
+ ps.call(:n=>'abc')
300
+ end
301
+
302
+ traces = get_all_traces
303
+
304
+ traces.count.must_equal 4
305
+ validate_outer_layers(traces, 'sequel_test')
306
+
307
+ validate_event_keys(traces[1], @entry_kvs)
308
+
309
+ if ::Sequel::VERSION > '4.36.0'
310
+ traces[1]['Query'].must_equal "SELECT * FROM `items` WHERE (`name` = ?)"
311
+ else
312
+ traces[1]['Query'].must_equal "select_by_name"
313
+ end
314
+
315
+ if RUBY_VERSION < "1.9"
316
+ traces[1]['QueryArgs'].must_equal "abc"
317
+ else
318
+ traces[1]['QueryArgs'].must_equal "[\"abc\"]"
319
+ end
320
+ traces[1]['IsPreparedStatement'].must_equal "true"
321
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
322
+ validate_event_keys(traces[2], @exit_kvs)
323
+ end
324
+
325
+ it 'should trace prep\'d stmnts and obey query privacy' do
326
+ AppOpticsAPM::Config[:sanitize_sql] = true
327
+ ds = MYSQL2_DB[:items].filter(:name=>:$n)
328
+ ps = ds.prepare(:select, :select_by_name)
329
+
330
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
331
+ ps.call(:n=>'abc')
332
+ end
333
+
334
+ traces = get_all_traces
335
+
336
+ traces.count.must_equal 4
337
+ validate_outer_layers(traces, 'sequel_test')
338
+
339
+ validate_event_keys(traces[1], @entry_kvs)
340
+
341
+ if ::Sequel::VERSION > '4.36.0'
342
+ traces[1]['Query'].must_equal "SELECT * FROM `items` WHERE (`name` = ?)"
343
+ else
344
+ traces[1]['Query'].must_equal "select_by_name"
345
+ end
346
+
347
+ traces[1]['QueryArgs'].must_equal nil
348
+ traces[1]['IsPreparedStatement'].must_equal "true"
349
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
350
+ validate_event_keys(traces[2], @exit_kvs)
351
+ end
352
+ end
353
+ end