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,334 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'minitest_helper'
5
+
6
+ if defined?(::Sequel) && !defined?(JRUBY_VERSION) && (RUBY_VERSION < "2.4")
7
+
8
+ AppOpticsAPM::Test.set_mysql_env
9
+ MYSQL_DB = Sequel.connect(ENV['DATABASE_URL'])
10
+
11
+ unless MYSQL_DB.table_exists?(:items)
12
+ MYSQL_DB.create_table :items do
13
+ primary_key :id
14
+ String :name
15
+ Float :price
16
+ end
17
+ end
18
+
19
+ describe "Sequel (mysql)" 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
+ MYSQL_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
+ MYSQL_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 MYSQL_DB.run insert' do
79
+ AppOpticsAPM::Config[:sanitize_sql] = false
80
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
81
+ MYSQL_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 MYSQL_DB.run select' do
96
+ AppOpticsAPM::Config[:sanitize_sql] = false
97
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
98
+ MYSQL_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 = MYSQL_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 = MYSQL_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 = MYSQL_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
+ MYSQL_DB.drop_table(:fake) if MYSQL_DB.table_exists?(:fake)
194
+
195
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
196
+ MYSQL_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
+ MYSQL_DB.drop_table(:fake) if MYSQL_DB.table_exists?(:fake)
218
+
219
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
220
+ MYSQL_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
+ MYSQL_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 = MYSQL_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
+ traces[1]['Query'].must_equal "SELECT * FROM `items` WHERE (`name` = 'abc')"
280
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
281
+ traces[3]['Query'].must_equal "DELETE FROM `items` WHERE (`name` = 'cba')"
282
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
283
+ validate_event_keys(traces[2], @exit_kvs)
284
+ end
285
+
286
+ it 'should trace prepared statements' do
287
+ AppOpticsAPM::Config[:sanitize_sql] = false
288
+ ds = MYSQL_DB[:items].filter(:name=>:$n)
289
+ ps = ds.prepare(:select, :select_by_name)
290
+
291
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
292
+ ps.call(:n=>'abc')
293
+ end
294
+
295
+ traces = get_all_traces
296
+
297
+ traces.count.must_equal 4
298
+ validate_outer_layers(traces, 'sequel_test')
299
+
300
+ validate_event_keys(traces[1], @entry_kvs)
301
+ traces[1]['Query'].must_equal "select_by_name"
302
+ if RUBY_VERSION < "1.9"
303
+ traces[1]['QueryArgs'].must_equal "abc"
304
+ else
305
+ traces[1]['QueryArgs'].must_equal "[\"abc\"]"
306
+ end
307
+ traces[1]['IsPreparedStatement'].must_equal "true"
308
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
309
+ validate_event_keys(traces[2], @exit_kvs)
310
+ end
311
+
312
+ it 'should trace prep\'d stmnts and obey query privacy' do
313
+ AppOpticsAPM::Config[:sanitize_sql] = true
314
+ ds = MYSQL_DB[:items].filter(:name=>:$n)
315
+ ps = ds.prepare(:select, :select_by_name)
316
+
317
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
318
+ ps.call(:n=>'abc')
319
+ end
320
+
321
+ traces = get_all_traces
322
+
323
+ traces.count.must_equal 4
324
+ validate_outer_layers(traces, 'sequel_test')
325
+
326
+ validate_event_keys(traces[1], @entry_kvs)
327
+ traces[1]['Query'].must_equal "select_by_name"
328
+ traces[1]['QueryArgs'].must_equal nil
329
+ traces[1]['IsPreparedStatement'].must_equal "true"
330
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
331
+ validate_event_keys(traces[2], @exit_kvs)
332
+ end
333
+ end
334
+ end
@@ -0,0 +1,336 @@
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_postgresql_env
9
+ PG_DB = Sequel.connect(ENV['DATABASE_URL'])
10
+
11
+ unless PG_DB.table_exists?(:items)
12
+ PG_DB.create_table :items do
13
+ primary_key :id
14
+ String :name
15
+ Float :price
16
+ end
17
+ end
18
+
19
+ describe "Sequel (postgres)" 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' => '127.0.0.1',
29
+ 'RemotePort' => 5432 }
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
+ PG_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
+ PG_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 PG_DB.run insert' do
79
+ AppOpticsAPM::Config[:sanitize_sql] = false
80
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
81
+ PG_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 PG_DB.run select' do
96
+ AppOpticsAPM::Config[:sanitize_sql] = false
97
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
98
+ PG_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 = PG_DB[:items]
115
+ # Preload the primary key to avoid breaking tests with the seemingly
116
+ # random lookup (random due to random test order)
117
+ PG_DB.primary_key(:items)
118
+
119
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
120
+ items.insert(:name => 'abc', :price => 2.514)
121
+ items.count
122
+ end
123
+
124
+ traces = get_all_traces
125
+
126
+ traces.count.must_equal 6
127
+ validate_outer_layers(traces, 'sequel_test')
128
+
129
+ validate_event_keys(traces[1], @entry_kvs)
130
+
131
+ # SQL column/value order can vary between Ruby and gem versions
132
+ # Use must_include to test against one or the other
133
+ [
134
+ "INSERT INTO \"items\" (\"price\", \"name\") VALUES (2.514, 'abc') RETURNING \"id\"",
135
+ "INSERT INTO \"items\" (\"name\", \"price\") VALUES ('abc', 2.514) RETURNING \"id\""
136
+ ].must_include traces[1]['Query']
137
+
138
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
139
+ traces[2]['Layer'].must_equal "sequel"
140
+ traces[2]['Label'].must_equal "exit"
141
+ traces[3]['Query'].downcase.must_equal "select count(*) as \"count\" from \"items\" limit 1"
142
+ validate_event_keys(traces[4], @exit_kvs)
143
+ end
144
+
145
+ it 'should trace a dataset insert and obey query privacy' do
146
+ AppOpticsAPM::Config[:sanitize_sql] = true
147
+ items = PG_DB[:items]
148
+ # Preload the primary key to avoid breaking tests with the seemingly
149
+ # random lookup (random due to random test order)
150
+ PG_DB.primary_key(:items)
151
+
152
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
153
+ items.insert(:name => 'abc', :price => 2.514461383352462)
154
+ end
155
+
156
+ traces = get_all_traces
157
+
158
+ traces.count.must_equal 4
159
+ validate_outer_layers(traces, 'sequel_test')
160
+
161
+ validate_event_keys(traces[1], @entry_kvs)
162
+
163
+ # SQL column/value order can vary between Ruby and gem versions
164
+ # Use must_include to test against one or the other
165
+ [
166
+ "INSERT INTO \"items\" (\"price\", \"name\") VALUES (?, ?) RETURNING \"id\"",
167
+ "INSERT INTO \"items\" (\"name\", \"price\") VALUES (?, ?) RETURNING \"id\""
168
+ ].must_include traces[1]['Query']
169
+
170
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
171
+ validate_event_keys(traces[2], @exit_kvs)
172
+ end
173
+
174
+ it 'should trace a dataset filter' do
175
+ AppOpticsAPM::Config[:sanitize_sql] = false
176
+ items = PG_DB[:items]
177
+ items.count
178
+
179
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
180
+ items.filter(:name => 'abc').all
181
+ end
182
+
183
+ traces = get_all_traces
184
+
185
+ traces.count.must_equal 4
186
+ validate_outer_layers(traces, 'sequel_test')
187
+
188
+ validate_event_keys(traces[1], @entry_kvs)
189
+ traces[1]['Query'].must_equal "SELECT * FROM \"items\" WHERE (\"name\" = 'abc')"
190
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
191
+ validate_event_keys(traces[2], @exit_kvs)
192
+ end
193
+
194
+ it 'should trace create table' do
195
+ # Drop the table if it already exists
196
+ PG_DB.drop_table(:fake) if PG_DB.table_exists?(:fake)
197
+
198
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
199
+ PG_DB.create_table :fake do
200
+ primary_key :id
201
+ String :name
202
+ Float :price
203
+ end
204
+ end
205
+
206
+ traces = get_all_traces
207
+
208
+ traces.count.must_equal 4
209
+ validate_outer_layers(traces, 'sequel_test')
210
+
211
+ validate_event_keys(traces[1], @entry_kvs)
212
+ traces[1]['Query'].must_equal "CREATE TABLE \"fake\" (\"id\" serial PRIMARY KEY, \"name\" text, \"price\" double precision)"
213
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
214
+ validate_event_keys(traces[2], @exit_kvs)
215
+ end
216
+
217
+ it 'should trace add index' do
218
+ # Drop the table if it already exists
219
+ PG_DB.drop_table(:fake) if PG_DB.table_exists?(:fake)
220
+
221
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
222
+ PG_DB.create_table :fake do
223
+ primary_key :id
224
+ String :name
225
+ Float :price
226
+ end
227
+ end
228
+
229
+ traces = get_all_traces
230
+
231
+ traces.count.must_equal 4
232
+ validate_outer_layers(traces, 'sequel_test')
233
+
234
+ validate_event_keys(traces[1], @entry_kvs)
235
+ traces[1]['Query'].must_equal "CREATE TABLE \"fake\" (\"id\" serial PRIMARY KEY, \"name\" text, \"price\" double precision)"
236
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
237
+ validate_event_keys(traces[2], @exit_kvs)
238
+ end
239
+
240
+ it 'should capture and report exceptions' do
241
+ begin
242
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
243
+ PG_DB.run("this is bad sql")
244
+ end
245
+ rescue
246
+ # Do nothing - we're testing exception logging
247
+ end
248
+
249
+ traces = get_all_traces
250
+
251
+ traces.count.must_equal 5
252
+ validate_outer_layers(traces, 'sequel_test')
253
+
254
+ validate_event_keys(traces[1], @entry_kvs)
255
+ traces[1]['Query'].must_equal "this is bad sql"
256
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
257
+ traces[2]['Layer'].must_equal "sequel"
258
+ traces[2]['Label'].must_equal "error"
259
+ traces[2].has_key?('Backtrace').must_equal true
260
+ traces[2]['ErrorClass'].must_equal "Sequel::DatabaseError"
261
+ validate_event_keys(traces[3], @exit_kvs)
262
+ end
263
+
264
+ it 'should trace placeholder queries with bound vars' do
265
+ AppOpticsAPM::Config[:sanitize_sql] = false
266
+ items = PG_DB[:items]
267
+ items.count
268
+
269
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
270
+ ds = items.where(:name=>:$n)
271
+ ds.call(:select, :n=>'abc')
272
+ ds.call(:delete, :n=>'cba')
273
+ end
274
+
275
+ traces = get_all_traces
276
+
277
+ traces.count.must_equal 6
278
+ validate_outer_layers(traces, 'sequel_test')
279
+
280
+ validate_event_keys(traces[1], @entry_kvs)
281
+ traces[1]['Query'].must_equal "SELECT * FROM \"items\" WHERE (\"name\" = $1)"
282
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
283
+ traces[3]['Query'].must_equal "DELETE FROM \"items\" WHERE (\"name\" = $1)"
284
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
285
+ validate_event_keys(traces[2], @exit_kvs)
286
+ end
287
+
288
+ it 'should trace prepared statements' do
289
+ AppOpticsAPM::Config[:sanitize_sql] = false
290
+ ds = PG_DB[:items].filter(:name=>:$n)
291
+ ps = ds.prepare(:select, :select_by_name)
292
+
293
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
294
+ ps.call(:n=>'abc')
295
+ end
296
+
297
+ traces = get_all_traces
298
+
299
+ traces.count.must_equal 4
300
+ validate_outer_layers(traces, 'sequel_test')
301
+
302
+ validate_event_keys(traces[1], @entry_kvs)
303
+ traces[1]['Query'].must_equal "select_by_name"
304
+ if RUBY_VERSION < "1.9"
305
+ traces[1]['QueryArgs'].must_equal "abc"
306
+ else
307
+ traces[1]['QueryArgs'].must_equal "[\"abc\"]"
308
+ end
309
+ traces[1]['IsPreparedStatement'].must_equal "true"
310
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
311
+ validate_event_keys(traces[2], @exit_kvs)
312
+ end
313
+
314
+ it 'should trace prep\'d stmnts and obey query privacy' do
315
+ AppOpticsAPM::Config[:sanitize_sql] = true
316
+ ds = PG_DB[:items].filter(:name=>:$n)
317
+ ps = ds.prepare(:select, :select_by_name)
318
+
319
+ AppOpticsAPM::API.start_trace('sequel_test', '', {}) do
320
+ ps.call(:n=>'abc')
321
+ end
322
+
323
+ traces = get_all_traces
324
+
325
+ traces.count.must_equal 4
326
+ validate_outer_layers(traces, 'sequel_test')
327
+
328
+ validate_event_keys(traces[1], @entry_kvs)
329
+ traces[1]['Query'].must_equal "select_by_name"
330
+ traces[1]['QueryArgs'].must_equal nil
331
+ traces[1]['IsPreparedStatement'].must_equal "true"
332
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:sequel][:collect_backtraces]
333
+ validate_event_keys(traces[2], @exit_kvs)
334
+ end
335
+ end
336
+ end