appoptics_apm 4.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (226) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +43 -0
  3. data/.dockerignore +5 -0
  4. data/.gitignore +23 -0
  5. data/.rubocop.yml +5 -0
  6. data/.travis.yml +82 -0
  7. data/CHANGELOG.md +769 -0
  8. data/CONFIG.md +33 -0
  9. data/Dockerfile +41 -0
  10. data/Dockerfile_test +66 -0
  11. data/Gemfile +41 -0
  12. data/LICENSE +193 -0
  13. data/README.md +351 -0
  14. data/Rakefile +202 -0
  15. data/Vagrantfile +67 -0
  16. data/appoptics_apm.gemspec +55 -0
  17. data/build_gems.sh +15 -0
  18. data/docker-compose.yml +73 -0
  19. data/examples/DNT.md +35 -0
  20. data/examples/carrying_context.rb +220 -0
  21. data/examples/instrumenting_metal_controller.rb +8 -0
  22. data/examples/puma_on_heroku_config.rb +17 -0
  23. data/examples/tracing_async_threads.rb +124 -0
  24. data/examples/tracing_background_jobs.rb +53 -0
  25. data/examples/tracing_forked_processes.rb +99 -0
  26. data/examples/unicorn_on_heroku_config.rb +28 -0
  27. data/ext/oboe_metal/extconf.rb +54 -0
  28. data/ext/oboe_metal/lib/.keep +0 -0
  29. data/ext/oboe_metal/lib/liboboe-1.0.so.0.0.0 +0 -0
  30. data/ext/oboe_metal/noop/noop.c +7 -0
  31. data/ext/oboe_metal/src/VERSION +1 -0
  32. data/ext/oboe_metal/src/bson/bson.h +221 -0
  33. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  34. data/ext/oboe_metal/src/oboe.h +883 -0
  35. data/ext/oboe_metal/src/oboe.hpp +793 -0
  36. data/ext/oboe_metal/src/oboe_debug.h +50 -0
  37. data/ext/oboe_metal/src/oboe_wrap.cxx +6088 -0
  38. data/ext/oboe_metal/tests/test.rb +11 -0
  39. data/gemfiles/delayed_job.gemfile +36 -0
  40. data/gemfiles/frameworks.gemfile +44 -0
  41. data/gemfiles/instrumentation_mocked.gemfile +29 -0
  42. data/gemfiles/libraries.gemfile +85 -0
  43. data/gemfiles/rails23.gemfile +39 -0
  44. data/gemfiles/rails30.gemfile +42 -0
  45. data/gemfiles/rails31.gemfile +44 -0
  46. data/gemfiles/rails32.gemfile +54 -0
  47. data/gemfiles/rails40.gemfile +27 -0
  48. data/gemfiles/rails41.gemfile +27 -0
  49. data/gemfiles/rails42.gemfile +35 -0
  50. data/gemfiles/rails50.gemfile +44 -0
  51. data/gemfiles/rails51.gemfile +44 -0
  52. data/get_version.rb +5 -0
  53. data/init.rb +4 -0
  54. data/lib/appoptics_apm/api/layerinit.rb +39 -0
  55. data/lib/appoptics_apm/api/logging.rb +359 -0
  56. data/lib/appoptics_apm/api/memcache.rb +34 -0
  57. data/lib/appoptics_apm/api/profiling.rb +201 -0
  58. data/lib/appoptics_apm/api/tracing.rb +152 -0
  59. data/lib/appoptics_apm/api/util.rb +128 -0
  60. data/lib/appoptics_apm/api.rb +18 -0
  61. data/lib/appoptics_apm/base.rb +252 -0
  62. data/lib/appoptics_apm/config.rb +281 -0
  63. data/lib/appoptics_apm/frameworks/grape.rb +93 -0
  64. data/lib/appoptics_apm/frameworks/padrino/templates.rb +58 -0
  65. data/lib/appoptics_apm/frameworks/padrino.rb +52 -0
  66. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +106 -0
  67. data/lib/appoptics_apm/frameworks/rails/inst/action_controller2.rb +61 -0
  68. data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +58 -0
  69. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
  70. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  71. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  72. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +58 -0
  73. data/lib/appoptics_apm/frameworks/rails/inst/action_view_2x.rb +56 -0
  74. data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +50 -0
  75. data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
  76. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  77. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
  78. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
  79. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +120 -0
  80. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +101 -0
  81. data/lib/appoptics_apm/frameworks/rails.rb +116 -0
  82. data/lib/appoptics_apm/frameworks/sinatra/templates.rb +56 -0
  83. data/lib/appoptics_apm/frameworks/sinatra.rb +71 -0
  84. data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
  85. data/lib/appoptics_apm/inst/bunny-consumer.rb +92 -0
  86. data/lib/appoptics_apm/inst/curb.rb +329 -0
  87. data/lib/appoptics_apm/inst/dalli.rb +85 -0
  88. data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
  89. data/lib/appoptics_apm/inst/em-http-request.rb +105 -0
  90. data/lib/appoptics_apm/inst/excon.rb +130 -0
  91. data/lib/appoptics_apm/inst/faraday.rb +77 -0
  92. data/lib/appoptics_apm/inst/http.rb +83 -0
  93. data/lib/appoptics_apm/inst/httpclient.rb +176 -0
  94. data/lib/appoptics_apm/inst/memcache.rb +102 -0
  95. data/lib/appoptics_apm/inst/memcached.rb +94 -0
  96. data/lib/appoptics_apm/inst/mongo.rb +242 -0
  97. data/lib/appoptics_apm/inst/mongo2.rb +225 -0
  98. data/lib/appoptics_apm/inst/moped.rb +466 -0
  99. data/lib/appoptics_apm/inst/rack.rb +146 -0
  100. data/lib/appoptics_apm/inst/redis.rb +275 -0
  101. data/lib/appoptics_apm/inst/resque.rb +151 -0
  102. data/lib/appoptics_apm/inst/rest-client.rb +50 -0
  103. data/lib/appoptics_apm/inst/sequel.rb +178 -0
  104. data/lib/appoptics_apm/inst/sidekiq-client.rb +53 -0
  105. data/lib/appoptics_apm/inst/sidekiq-worker.rb +67 -0
  106. data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
  107. data/lib/appoptics_apm/inst/typhoeus.rb +113 -0
  108. data/lib/appoptics_apm/instrumentation.rb +22 -0
  109. data/lib/appoptics_apm/legacy_method_profiling.rb +97 -0
  110. data/lib/appoptics_apm/loading.rb +66 -0
  111. data/lib/appoptics_apm/logger.rb +41 -0
  112. data/lib/appoptics_apm/method_profiling.rb +33 -0
  113. data/lib/appoptics_apm/ruby.rb +35 -0
  114. data/lib/appoptics_apm/support.rb +135 -0
  115. data/lib/appoptics_apm/test.rb +94 -0
  116. data/lib/appoptics_apm/thread_local.rb +26 -0
  117. data/lib/appoptics_apm/util.rb +312 -0
  118. data/lib/appoptics_apm/version.rb +15 -0
  119. data/lib/appoptics_apm/xtrace.rb +103 -0
  120. data/lib/appoptics_apm.rb +72 -0
  121. data/lib/joboe_metal.rb +214 -0
  122. data/lib/oboe/README +2 -0
  123. data/lib/oboe/backward_compatibility.rb +80 -0
  124. data/lib/oboe/inst/rack.rb +11 -0
  125. data/lib/oboe.rb +7 -0
  126. data/lib/oboe_metal.rb +187 -0
  127. data/lib/rails/generators/appoptics_apm/install_generator.rb +45 -0
  128. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +222 -0
  129. data/ruby_setup.sh +47 -0
  130. data/run_docker_build_gem_upload_to_packagecloud.sh +20 -0
  131. data/run_tests_docker.rb +32 -0
  132. data/test/benchmark/README.md +65 -0
  133. data/test/benchmark/logging_bench.rb +54 -0
  134. data/test/benchmark/with_libraries_gemfile/bunny_bench.rb +69 -0
  135. data/test/benchmark/with_rails5x_gemfile/action_controller5x_bench.rb +43 -0
  136. data/test/frameworks/apps/grape_nested.rb +33 -0
  137. data/test/frameworks/apps/grape_simple.rb +80 -0
  138. data/test/frameworks/apps/padrino_simple.rb +80 -0
  139. data/test/frameworks/apps/sinatra_simple.rb +55 -0
  140. data/test/frameworks/grape_test.rb +286 -0
  141. data/test/frameworks/padrino_test.rb +222 -0
  142. data/test/frameworks/rails3x_test.rb +554 -0
  143. data/test/frameworks/rails4x_test.rb +570 -0
  144. data/test/frameworks/rails5x_api_test.rb +210 -0
  145. data/test/frameworks/rails5x_test.rb +376 -0
  146. data/test/frameworks/rails_shared_tests.rb +172 -0
  147. data/test/frameworks/sinatra_test.rb +140 -0
  148. data/test/instrumentation/bunny_client_test.rb +276 -0
  149. data/test/instrumentation/bunny_consumer_test.rb +204 -0
  150. data/test/instrumentation/curb_test.rb +398 -0
  151. data/test/instrumentation/dalli_test.rb +177 -0
  152. data/test/instrumentation/em_http_request_test.rb +89 -0
  153. data/test/instrumentation/excon_test.rb +231 -0
  154. data/test/instrumentation/faraday_test.rb +228 -0
  155. data/test/instrumentation/http_test.rb +143 -0
  156. data/test/instrumentation/httpclient_test.rb +320 -0
  157. data/test/instrumentation/memcache_test.rb +260 -0
  158. data/test/instrumentation/memcached_test.rb +229 -0
  159. data/test/instrumentation/mongo_v1_test.rb +479 -0
  160. data/test/instrumentation/mongo_v2_index_test.rb +124 -0
  161. data/test/instrumentation/mongo_v2_test.rb +584 -0
  162. data/test/instrumentation/mongo_v2_view_test.rb +435 -0
  163. data/test/instrumentation/moped_test.rb +517 -0
  164. data/test/instrumentation/rack_test.rb +165 -0
  165. data/test/instrumentation/redis_hashes_test.rb +268 -0
  166. data/test/instrumentation/redis_keys_test.rb +321 -0
  167. data/test/instrumentation/redis_lists_test.rb +310 -0
  168. data/test/instrumentation/redis_misc_test.rb +163 -0
  169. data/test/instrumentation/redis_sets_test.rb +296 -0
  170. data/test/instrumentation/redis_sortedsets_test.rb +328 -0
  171. data/test/instrumentation/redis_strings_test.rb +349 -0
  172. data/test/instrumentation/resque_test.rb +185 -0
  173. data/test/instrumentation/rest-client_test.rb +288 -0
  174. data/test/instrumentation/sequel_mysql2_test.rb +353 -0
  175. data/test/instrumentation/sequel_mysql_test.rb +334 -0
  176. data/test/instrumentation/sequel_pg_test.rb +336 -0
  177. data/test/instrumentation/sidekiq-client_test.rb +159 -0
  178. data/test/instrumentation/sidekiq-worker_test.rb +180 -0
  179. data/test/instrumentation/twitter-cassandra_test.rb +424 -0
  180. data/test/instrumentation/typhoeus_test.rb +284 -0
  181. data/test/jobs/delayed_job/db_worker_job.rb +29 -0
  182. data/test/jobs/delayed_job/error_worker_job.rb +10 -0
  183. data/test/jobs/delayed_job/remote_call_worker_job.rb +20 -0
  184. data/test/jobs/resque/db_worker_job.rb +29 -0
  185. data/test/jobs/resque/error_worker_job.rb +10 -0
  186. data/test/jobs/resque/remote_call_worker_job.rb +20 -0
  187. data/test/jobs/sidekiq/db_worker_job.rb +29 -0
  188. data/test/jobs/sidekiq/error_worker_job.rb +10 -0
  189. data/test/jobs/sidekiq/remote_call_worker_job.rb +20 -0
  190. data/test/minitest_helper.rb +276 -0
  191. data/test/mocked/curb_mocked_test.rb +311 -0
  192. data/test/mocked/excon_mocked_test.rb +166 -0
  193. data/test/mocked/faraday_mocked_test.rb +93 -0
  194. data/test/mocked/http_mocked_test.rb +129 -0
  195. data/test/mocked/httpclient_mocked_test.rb +245 -0
  196. data/test/mocked/rest_client_mocked_test.rb +103 -0
  197. data/test/mocked/typhoeus_mocked_test.rb +192 -0
  198. data/test/models/widget.rb +36 -0
  199. data/test/profiling/legacy_method_profiling_test.rb +201 -0
  200. data/test/profiling/method_profiling_test.rb +631 -0
  201. data/test/queues/delayed_job-client_test.rb +95 -0
  202. data/test/queues/delayed_job-worker_test.rb +91 -0
  203. data/test/reporter/reporter_test.rb +14 -0
  204. data/test/servers/delayed_job.rb +107 -0
  205. data/test/servers/rackapp_8101.rb +29 -0
  206. data/test/servers/rails3x_8140.rb +96 -0
  207. data/test/servers/rails4x_8140.rb +96 -0
  208. data/test/servers/rails5x_8140.rb +95 -0
  209. data/test/servers/rails5x_api_8150.rb +78 -0
  210. data/test/servers/sidekiq.rb +29 -0
  211. data/test/servers/sidekiq.yml +7 -0
  212. data/test/servers/sidekiq_initializer.rb +25 -0
  213. data/test/settings +0 -0
  214. data/test/support/auto_tracing_test.rb +50 -0
  215. data/test/support/backcompat_test.rb +276 -0
  216. data/test/support/config_test.rb +149 -0
  217. data/test/support/dnt_test.rb +98 -0
  218. data/test/support/init_report_test.rb +25 -0
  219. data/test/support/liboboe_settings_test.rb +110 -0
  220. data/test/support/logging_test.rb +130 -0
  221. data/test/support/noop_test.rb +88 -0
  222. data/test/support/sql_sanitize_test.rb +55 -0
  223. data/test/support/tracing_mode_test.rb +33 -0
  224. data/test/support/tvalias_test.rb +15 -0
  225. data/test/support/xtrace_test.rb +41 -0
  226. metadata +475 -0
@@ -0,0 +1,517 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'minitest_helper'
5
+
6
+ unless ENV['APPOPTICS_MONGO_SERVER']
7
+ ENV['APPOPTICS_MONGO_SERVER'] = "127.0.0.1:27017"
8
+ end
9
+
10
+ if RUBY_VERSION >= '1.9.3'
11
+ # Moped is tested against MRI 2.3.1 and 2.4.1
12
+
13
+ describe "Moped" do
14
+ before do
15
+ clear_all_traces
16
+ @session = Moped::Session.new([ ENV['APPOPTICS_MONGO_SERVER'] ])
17
+ @session.use :moped_test
18
+ @users = @session[:users]
19
+ @users.drop
20
+ @users.insert({ :name => "Syd", :city => "Boston" })
21
+
22
+ # These are standard entry/exit KVs that are passed up with all moped operations
23
+ @entry_kvs = {
24
+ 'Layer' => 'mongo',
25
+ 'Label' => 'entry',
26
+ 'Flavor' => 'mongodb',
27
+ 'Database' => 'moped_test',
28
+ 'RemoteHost' => ENV['APPOPTICS_MONGO_SERVER'] }
29
+
30
+ @exit_kvs = { 'Layer' => 'mongo', 'Label' => 'exit' }
31
+ @collect_backtraces = AppOpticsAPM::Config[:moped][:collect_backtraces]
32
+ end
33
+
34
+ after do
35
+ AppOpticsAPM::Config[:moped][:collect_backtraces] = @collect_backtraces
36
+ end
37
+
38
+ it 'Stock Moped should be loaded, defined and ready' do
39
+ defined?(::Moped).wont_match nil
40
+ defined?(::Moped::Database).wont_match nil
41
+ defined?(::Moped::Indexes).wont_match nil
42
+ defined?(::Moped::Query).wont_match nil
43
+ defined?(::Moped::Collection).wont_match nil
44
+ end
45
+
46
+ it 'Moped should have appoptics_apm methods defined' do
47
+ #::Moped::Database
48
+ AppOpticsAPM::Inst::Moped::DB_OPS.each do |m|
49
+ ::Moped::Database.method_defined?("#{m}_with_appoptics").must_equal true
50
+ end
51
+ ::Moped::Database.method_defined?(:extract_trace_details).must_equal true
52
+ ::Moped::Database.method_defined?(:command_with_appoptics).must_equal true
53
+ ::Moped::Database.method_defined?(:drop_with_appoptics).must_equal true
54
+
55
+ #::Moped::Indexes
56
+ AppOpticsAPM::Inst::Moped::INDEX_OPS.each do |m|
57
+ ::Moped::Indexes.method_defined?("#{m}_with_appoptics").must_equal true
58
+ end
59
+ ::Moped::Indexes.method_defined?(:extract_trace_details).must_equal true
60
+ ::Moped::Indexes.method_defined?(:create_with_appoptics).must_equal true
61
+ ::Moped::Indexes.method_defined?(:drop_with_appoptics).must_equal true
62
+
63
+ #::Moped::Query
64
+ AppOpticsAPM::Inst::Moped::QUERY_OPS.each do |m|
65
+ ::Moped::Query.method_defined?("#{m}_with_appoptics").must_equal true
66
+ end
67
+ ::Moped::Query.method_defined?(:extract_trace_details).must_equal true
68
+
69
+ #::Moped::Collection
70
+ AppOpticsAPM::Inst::Moped::COLLECTION_OPS.each do |m|
71
+ ::Moped::Collection.method_defined?("#{m}_with_appoptics").must_equal true
72
+ end
73
+ ::Moped::Collection.method_defined?(:extract_trace_details).must_equal true
74
+ end
75
+
76
+ it 'should trace command' do
77
+ # TODO: This randomly fails for a yet unknown reason. Does it?
78
+ # skip
79
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
80
+ command = {}
81
+ command[:mapreduce] = "users"
82
+ command[:map] = "function() { emit(this.name, 1); }"
83
+ command[:reduce] = "function(k, vals) { var sum = 0; for(var i in vals) sum += vals[i]; return sum; }"
84
+ command[:out] = "inline: 1"
85
+ @session.command(command)
86
+ end
87
+
88
+ traces = get_all_traces
89
+
90
+ traces.count.must_equal 4
91
+ validate_outer_layers(traces, 'moped_test')
92
+
93
+ validate_event_keys(traces[1], @entry_kvs)
94
+ traces[1]['QueryOp'].must_equal "map_reduce"
95
+ traces[1]['Map_Function'].must_equal "function() { emit(this.name, 1); }"
96
+ traces[1]['Reduce_Function'].must_equal "function(k, vals) { var sum = 0;" +
97
+ " for(var i in vals) sum += vals[i]; return sum; }"
98
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
99
+ validate_event_keys(traces[2], @exit_kvs)
100
+ end
101
+
102
+ it 'should trace drop_collection' do
103
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
104
+ @users.drop
105
+ @session.drop
106
+ end
107
+
108
+ traces = get_all_traces
109
+
110
+ traces.count.must_equal 6
111
+ validate_outer_layers(traces, 'moped_test')
112
+
113
+ validate_event_keys(traces[1], @entry_kvs)
114
+ traces[1]['QueryOp'].must_equal "drop_collection"
115
+ traces[1]['Collection'].must_equal "users"
116
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
117
+ validate_event_keys(traces[2], @exit_kvs)
118
+
119
+ validate_event_keys(traces[3], @entry_kvs)
120
+ traces[3]['QueryOp'].must_equal "drop_database"
121
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
122
+ validate_event_keys(traces[4], @exit_kvs)
123
+ end
124
+
125
+ it 'should trace create_index, indexes and drop_indexes' do
126
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
127
+ @users.indexes.create({:name => 1}, {:unique => true})
128
+ @users.indexes.drop
129
+ end
130
+
131
+ traces = get_all_traces
132
+
133
+ traces.count.must_equal 10
134
+ validate_outer_layers(traces, 'moped_test')
135
+
136
+ validate_event_keys(traces[1], @entry_kvs)
137
+ traces[1]['QueryOp'].must_equal "indexes"
138
+ traces[1]['Collection'].must_equal "users"
139
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
140
+ validate_event_keys(traces[2], @exit_kvs)
141
+
142
+ validate_event_keys(traces[3], @entry_kvs)
143
+ traces[3]['QueryOp'].must_equal "create_index"
144
+ traces[3]['Key'].must_equal "{\"name\":1}"
145
+ traces[3]['Options'].must_equal "{\"unique\":true}"
146
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
147
+ validate_event_keys(traces[4], @exit_kvs)
148
+
149
+ validate_event_keys(traces[5], @entry_kvs)
150
+ traces[5]['QueryOp'].must_equal "indexes"
151
+ traces[5]['Collection'].must_equal "users"
152
+ traces[5].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
153
+ validate_event_keys(traces[6], @exit_kvs)
154
+
155
+ validate_event_keys(traces[7], @entry_kvs)
156
+ traces[7]['QueryOp'].must_equal "drop_indexes"
157
+ traces[7]['Key'].must_equal "all"
158
+ traces[7].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
159
+ validate_event_keys(traces[8], @exit_kvs)
160
+ end
161
+
162
+ it 'should trace find and count' do
163
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
164
+ @users.find.count
165
+ end
166
+
167
+ traces = get_all_traces
168
+
169
+ traces.count.must_equal 6
170
+ validate_outer_layers(traces, 'moped_test')
171
+
172
+ validate_event_keys(traces[1], @entry_kvs)
173
+ traces[1]['QueryOp'].must_equal "find"
174
+ traces[1]['Collection'].must_equal "users"
175
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
176
+ validate_event_keys(traces[2], @exit_kvs)
177
+
178
+ validate_event_keys(traces[3], @entry_kvs)
179
+ traces[3]['QueryOp'].must_equal "count"
180
+ traces[3]['Query'].must_equal "all"
181
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
182
+ validate_event_keys(traces[4], @exit_kvs)
183
+ end
184
+
185
+ it 'should trace find and sort' do
186
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
187
+ @users.find(:name => "Mary").sort(:city => 1, :created_at => -1)
188
+ end
189
+
190
+ traces = get_all_traces
191
+
192
+ traces.count.must_equal 6
193
+ validate_outer_layers(traces, 'moped_test')
194
+
195
+ validate_event_keys(traces[1], @entry_kvs)
196
+ traces[1]['QueryOp'].must_equal "find"
197
+ traces[1]['Query'].must_equal "{\"name\":\"Mary\"}"
198
+ traces[1]['Collection'].must_equal "users"
199
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
200
+ validate_event_keys(traces[2], @exit_kvs)
201
+
202
+ validate_event_keys(traces[3], @entry_kvs)
203
+ traces[3]['QueryOp'].must_equal "sort"
204
+ traces[3]['Query'].must_equal "{\"name\":\"Mary\"}"
205
+ traces[3]['Order'].must_equal "{:city=>1, :created_at=>-1}"
206
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
207
+ validate_event_keys(traces[4], @exit_kvs)
208
+ end
209
+
210
+ it 'should trace find with limit' do
211
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
212
+ @users.find(:name => "Mary").limit(1)
213
+ end
214
+
215
+ traces = get_all_traces
216
+
217
+ traces.count.must_equal 6
218
+ validate_outer_layers(traces, 'moped_test')
219
+
220
+ validate_event_keys(traces[1], @entry_kvs)
221
+ traces[1]['QueryOp'].must_equal "find"
222
+ traces[1]['Query'].must_equal "{\"name\":\"Mary\"}"
223
+ traces[1]['Collection'].must_equal "users"
224
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
225
+ validate_event_keys(traces[2], @exit_kvs)
226
+
227
+ validate_event_keys(traces[3], @entry_kvs)
228
+ traces[3]['QueryOp'].must_equal "limit"
229
+ traces[3]['Query'].must_equal "{\"name\":\"Mary\"}"
230
+ traces[3]['Limit'].must_equal "1"
231
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
232
+ validate_event_keys(traces[4], @exit_kvs)
233
+ end
234
+
235
+ it 'should trace find with distinct' do
236
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
237
+ @users.find(:name => "Mary").distinct(:city)
238
+ end
239
+
240
+ traces = get_all_traces
241
+
242
+ traces.count.must_equal 6
243
+ validate_outer_layers(traces, 'moped_test')
244
+
245
+ validate_event_keys(traces[1], @entry_kvs)
246
+ traces[1]['QueryOp'].must_equal "find"
247
+ traces[1]['Query'].must_equal "{\"name\":\"Mary\"}"
248
+ traces[1]['Collection'].must_equal "users"
249
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
250
+ validate_event_keys(traces[2], @exit_kvs)
251
+
252
+ validate_event_keys(traces[3], @entry_kvs)
253
+ traces[3]['QueryOp'].must_equal "distinct"
254
+ traces[3]['Query'].must_equal "{\"name\":\"Mary\"}"
255
+ traces[3]['Key'].must_equal "city"
256
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
257
+ validate_event_keys(traces[4], @exit_kvs)
258
+ end
259
+
260
+ it 'should trace find and update' do
261
+ 2.times { @users.insert(:name => "Mary") }
262
+ mary_count = @users.find(:name => "Mary").count
263
+ mary_count.wont_equal 0
264
+
265
+ tool_count = @users.find(:name => "Tool").count
266
+ tool_count.must_equal 0
267
+
268
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
269
+ old_attrs = { :name => "Mary" }
270
+ new_attrs = { :name => "Tool" }
271
+ @users.find(old_attrs).update({ '$set' => new_attrs }, { :multi => true })
272
+ end
273
+
274
+ new_tool_count = @users.find(:name => "Tool").count
275
+ new_tool_count.must_equal mary_count
276
+
277
+ new_mary_count = @users.find(:name => "Mary").count
278
+ new_mary_count.must_equal 0
279
+
280
+ traces = get_all_traces
281
+
282
+ traces.count.must_equal 6
283
+ validate_outer_layers(traces, 'moped_test')
284
+
285
+ validate_event_keys(traces[1], @entry_kvs)
286
+ traces[1]['QueryOp'].must_equal "find"
287
+ traces[1]['Query'].must_equal "{\"name\":\"Mary\"}"
288
+ traces[1]['Collection'].must_equal "users"
289
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
290
+ validate_event_keys(traces[2], @exit_kvs)
291
+
292
+ validate_event_keys(traces[3], @entry_kvs)
293
+ traces[3]['QueryOp'].must_equal "update"
294
+ traces[3]['Update_Document'].must_equal "{\"$set\":{\"name\":\"Tool\"}}"
295
+ traces[3]['Flags'].must_equal "{:multi=>true}"
296
+ traces[3]['Collection'].must_equal "users"
297
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
298
+ validate_event_keys(traces[4], @exit_kvs)
299
+ end
300
+
301
+ it 'should trace find and update_all' do
302
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
303
+ @users.find(:name => "Mary").update_all({:name => "Tool"})
304
+ end
305
+
306
+ traces = get_all_traces
307
+
308
+ traces.count.must_equal 6
309
+ validate_outer_layers(traces, 'moped_test')
310
+
311
+ validate_event_keys(traces[1], @entry_kvs)
312
+ traces[1]['QueryOp'].must_equal "find"
313
+ traces[1]['Query'].must_equal "{\"name\":\"Mary\"}"
314
+ traces[1]['Collection'].must_equal "users"
315
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
316
+ validate_event_keys(traces[2], @exit_kvs)
317
+
318
+ validate_event_keys(traces[3], @entry_kvs)
319
+ traces[3]['QueryOp'].must_equal "update_all"
320
+ traces[3]['Update_Document'].must_equal "{\"name\":\"Tool\"}"
321
+ traces[3]['Collection'].must_equal "users"
322
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
323
+ validate_event_keys(traces[4], @exit_kvs)
324
+ end
325
+
326
+ it 'should trace find and upsert' do
327
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
328
+ @users.find(:name => "Tool").upsert({:name => "Mary"})
329
+ end
330
+
331
+ traces = get_all_traces
332
+
333
+ traces.count.must_equal 6
334
+ validate_outer_layers(traces, 'moped_test')
335
+
336
+ validate_event_keys(traces[1], @entry_kvs)
337
+ traces[1]['QueryOp'].must_equal "find"
338
+ traces[1]['Query'].must_equal "{\"name\":\"Tool\"}"
339
+ traces[1]['Collection'].must_equal "users"
340
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
341
+ validate_event_keys(traces[2], @exit_kvs)
342
+
343
+ validate_event_keys(traces[3], @entry_kvs)
344
+ traces[3]['QueryOp'].must_equal "upsert"
345
+ traces[3]['Query'].must_equal "{\"name\":\"Tool\"}"
346
+ traces[3]['Update_Document'].must_equal "{\"name\":\"Mary\"}"
347
+ traces[3]['Collection'].must_equal "users"
348
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
349
+ validate_event_keys(traces[4], @exit_kvs)
350
+ end
351
+
352
+ it 'should trace find and explain' do
353
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
354
+ @users.find(:name => "Mary").explain
355
+ end
356
+
357
+ traces = get_all_traces
358
+
359
+ traces.count.must_equal 6
360
+ validate_outer_layers(traces, 'moped_test')
361
+
362
+ validate_event_keys(traces[1], @entry_kvs)
363
+ traces[1]['QueryOp'].must_equal "find"
364
+ traces[1]['Query'].must_equal "{\"name\":\"Mary\"}"
365
+ traces[1]['Collection'].must_equal "users"
366
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
367
+ validate_event_keys(traces[2], @exit_kvs)
368
+
369
+ validate_event_keys(traces[3], @entry_kvs)
370
+ traces[3]['QueryOp'].must_equal "explain"
371
+ traces[3]['Query'].must_equal "{\"name\":\"Mary\"}"
372
+ traces[3]['Collection'].must_equal "users"
373
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
374
+ validate_event_keys(traces[4], @exit_kvs)
375
+ end
376
+
377
+ it 'should trace 3 types of find and modify calls' do
378
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
379
+ @users.find(:likes => 1).modify({ "$set" => { :name => "Tool" }}, :upsert => true)
380
+ @users.find.modify({ "$inc" => { :likes => 1 }}, :new => true)
381
+ @users.find.modify({:query => {}}, :remove => true)
382
+ end
383
+
384
+ traces = get_all_traces
385
+
386
+ traces.count.must_equal 14
387
+ validate_outer_layers(traces, 'moped_test')
388
+
389
+ validate_event_keys(traces[1], @entry_kvs)
390
+ traces[1]['QueryOp'].must_equal "find"
391
+ traces[1]['Query'].must_equal "{\"likes\":1}"
392
+ traces[1]['Collection'].must_equal "users"
393
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
394
+ validate_event_keys(traces[2], @exit_kvs)
395
+
396
+ validate_event_keys(traces[3], @entry_kvs)
397
+ traces[3]['QueryOp'].must_equal "modify"
398
+ traces[3]['Update_Document'].must_equal "{\"likes\":1}"
399
+ traces[3]['Collection'].must_equal "users"
400
+ traces[3]['Options'].must_equal "{\"upsert\":true}"
401
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
402
+ validate_event_keys(traces[4], @exit_kvs)
403
+
404
+ validate_event_keys(traces[7], @entry_kvs)
405
+ traces[7]['QueryOp'].must_equal "modify"
406
+ traces[7]['Update_Document'].must_equal "all"
407
+ traces[7]['Collection'].must_equal "users"
408
+ traces[7]['Options'].must_equal "{\"new\":true}"
409
+ traces[7]['Change'].must_equal "{\"$inc\":{\"likes\":1}}"
410
+ traces[7].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
411
+ validate_event_keys(traces[8], @exit_kvs)
412
+
413
+ validate_event_keys(traces[11], @entry_kvs)
414
+ traces[11]['Collection'].must_equal "users"
415
+ traces[11]['QueryOp'].must_equal "modify"
416
+ traces[11]['Update_Document'].must_equal "all"
417
+ traces[11]['Change'].must_equal "{\"query\":{}}"
418
+ traces[11]['Options'].must_equal "{\"remove\":true}"
419
+ traces[11].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
420
+ validate_event_keys(traces[12], @exit_kvs)
421
+ end
422
+
423
+ it 'should trace remove' do
424
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
425
+ @users.find(:name => "Tool").remove
426
+ end
427
+
428
+ traces = get_all_traces
429
+
430
+ traces.count.must_equal 6
431
+ validate_outer_layers(traces, 'moped_test')
432
+
433
+ validate_event_keys(traces[1], @entry_kvs)
434
+ traces[1]['QueryOp'].must_equal "find"
435
+ traces[1]['Query'].must_equal "{\"name\":\"Tool\"}"
436
+ traces[1]['Collection'].must_equal "users"
437
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
438
+ validate_event_keys(traces[2], @exit_kvs)
439
+
440
+ validate_event_keys(traces[3], @entry_kvs)
441
+ traces[3]['QueryOp'].must_equal "remove"
442
+ traces[3]['Query'].must_equal "{\"name\":\"Tool\"}"
443
+ traces[3]['Collection'].must_equal "users"
444
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
445
+ validate_event_keys(traces[4], @exit_kvs)
446
+ end
447
+
448
+ it 'should trace remove_all' do
449
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
450
+ @users.find(:name => "Mary").remove_all
451
+ end
452
+
453
+ traces = get_all_traces
454
+
455
+ traces.count.must_equal 6
456
+ validate_outer_layers(traces, 'moped_test')
457
+
458
+ validate_event_keys(traces[1], @entry_kvs)
459
+ traces[1]['QueryOp'].must_equal "find"
460
+ traces[1]['Query'].must_equal "{\"name\":\"Mary\"}"
461
+ traces[1]['Collection'].must_equal "users"
462
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
463
+ validate_event_keys(traces[2], @exit_kvs)
464
+
465
+ validate_event_keys(traces[3], @entry_kvs)
466
+ traces[3]['QueryOp'].must_equal "remove_all"
467
+ traces[3]['Query'].must_equal "{\"name\":\"Mary\"}"
468
+ traces[3]['Collection'].must_equal "users"
469
+ traces[3].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
470
+ validate_event_keys(traces[4], @exit_kvs)
471
+ end
472
+
473
+ it 'should trace aggregate' do
474
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
475
+ @users.aggregate(
476
+ {'$match' => {:name => "Mary"}},
477
+ {'$group' => {"_id" => "$name"}}
478
+ )
479
+ end
480
+
481
+ traces = get_all_traces
482
+
483
+ traces.count.must_equal 4
484
+ validate_outer_layers(traces, 'moped_test')
485
+
486
+ validate_event_keys(traces[1], @entry_kvs)
487
+ traces[1]['QueryOp'].must_equal "aggregate"
488
+ traces[1]['Query'].must_equal "[{\"$match\"=>{:name=>\"Mary\"}}, {\"$group\"=>{\"_id\"=>\"$name\"}}]"
489
+ traces[1]['Collection'].must_equal "users"
490
+ traces[1].has_key?('Backtrace').must_equal AppOpticsAPM::Config[:moped][:collect_backtraces]
491
+ validate_event_keys(traces[2], @exit_kvs)
492
+ end
493
+
494
+ it "should obey :collect_backtraces setting when true" do
495
+ AppOpticsAPM::Config[:moped][:collect_backtraces] = true
496
+
497
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
498
+ @users.find(:name => "Mary").limit(1)
499
+ end
500
+
501
+ traces = get_all_traces
502
+ layer_has_key(traces, 'mongo', 'Backtrace')
503
+ end
504
+
505
+ it "should obey :collect_backtraces setting when false" do
506
+ AppOpticsAPM::Config[:moped][:collect_backtraces] = false
507
+
508
+ AppOpticsAPM::API.start_trace('moped_test', '', {}) do
509
+ @users.find(:name => "Mary").limit(1)
510
+ end
511
+
512
+ traces = get_all_traces
513
+ layer_doesnt_have_key(traces, 'mongo', 'Backtrace')
514
+ end
515
+ end
516
+
517
+ end
@@ -0,0 +1,165 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'minitest_helper'
5
+ require 'rack/test'
6
+ require 'rack/lobster'
7
+ require 'appoptics_apm/inst/rack'
8
+ require 'mocha/mini_test'
9
+
10
+ class RackTestApp < Minitest::Test
11
+ include Rack::Test::Methods
12
+
13
+ def app
14
+ @app = Rack::Builder.new {
15
+ use Rack::CommonLogger
16
+ use Rack::ShowExceptions
17
+ use AppOpticsAPM::Rack
18
+ map "/lobster" do
19
+ use Rack::Lint
20
+ run Rack::Lobster.new
21
+ end
22
+ }
23
+ end
24
+
25
+ def teardown
26
+ AppOpticsAPM::Config[:tracing_mode] = :always
27
+ end
28
+
29
+ def test_get_the_lobster
30
+ skip("FIXME: broken on travis only") if ENV['TRAVIS'] == "true"
31
+
32
+ clear_all_traces
33
+
34
+ get "/lobster"
35
+
36
+ traces = get_all_traces
37
+ traces.count.must_equal 3
38
+
39
+ validate_outer_layers(traces, 'rack')
40
+
41
+ kvs = {}
42
+ kvs["Label"] = "entry"
43
+ kvs["URL"] = "/lobster"
44
+ validate_event_keys(traces[0], kvs)
45
+
46
+ kvs.clear
47
+ kvs["Layer"] = "rack"
48
+ kvs["Label"] = "info"
49
+ kvs["HTTP-Host"] = "example.org"
50
+ kvs["Port"] = 80
51
+ kvs["Proto"] = "http"
52
+ kvs["Method"] = "GET"
53
+ kvs["ClientIP"] = "127.0.0.1"
54
+ validate_event_keys(traces[1], kvs)
55
+
56
+ assert traces[0].has_key?('SampleRate')
57
+ assert traces[0].has_key?('SampleSource')
58
+ assert traces[1].has_key?('ProcessID')
59
+ assert traces[1].has_key?('ThreadID')
60
+
61
+ assert traces[2]["Label"] == 'exit'
62
+ assert traces[2]["Status"] == 200
63
+
64
+ assert last_response.ok?
65
+
66
+ assert last_response['X-Trace']
67
+ end
68
+
69
+ def test_must_return_xtrace_header
70
+ clear_all_traces
71
+ get "/lobster"
72
+ xtrace = last_response['X-Trace']
73
+ assert xtrace
74
+ assert AppOpticsAPM::XTrace.valid?(xtrace)
75
+ end
76
+
77
+ def test_log_args_when_false
78
+ clear_all_traces
79
+
80
+ @log_args = AppOpticsAPM::Config[:rack][:log_args]
81
+ AppOpticsAPM::Config[:rack][:log_args] = false
82
+
83
+ get "/lobster?blah=1"
84
+
85
+ traces = get_all_traces
86
+
87
+ xtrace = last_response['X-Trace']
88
+ assert xtrace
89
+ assert AppOpticsAPM::XTrace.valid?(xtrace)
90
+
91
+ traces[0]['URL'].must_equal "/lobster"
92
+
93
+ AppOpticsAPM::Config[:rack][:log_args] = @log_args
94
+ end
95
+
96
+ def test_log_args_when_true
97
+ clear_all_traces
98
+
99
+ @log_args = AppOpticsAPM::Config[:rack][:log_args]
100
+ AppOpticsAPM::Config[:rack][:log_args] = true
101
+
102
+ get "/lobster?blah=1"
103
+
104
+ traces = get_all_traces
105
+
106
+ xtrace = last_response['X-Trace']
107
+ assert xtrace
108
+ assert AppOpticsAPM::XTrace.valid?(xtrace)
109
+
110
+ traces[0]['URL'].must_equal "/lobster?blah=1"
111
+
112
+ AppOpticsAPM::Config[:rack][:log_args] = @log_args
113
+ end
114
+
115
+ def test_has_header_when_not_tracing
116
+ clear_all_traces
117
+
118
+ AppOpticsAPM::Config[:tracing_mode] = :never
119
+
120
+ get "/lobster?blah=1"
121
+
122
+ traces = get_all_traces
123
+ assert_equal(0, traces.size)
124
+
125
+ assert last_response['X-Trace'], "X-Trace header is missing"
126
+ assert not_sampled?(last_response['X-Trace']), "X-Trace sampling flag is not '00'"
127
+ end
128
+
129
+ def test_sends_path_in_http_span_when_no_controller
130
+ test_action, test_url, test_status, test_method, test_error = nil, nil, nil, nil, nil
131
+
132
+ AppOpticsAPM::Span.expects(:createHttpSpan).with do |action, url, _duration, status, method, error|
133
+ test_action = action
134
+ test_url = url
135
+ test_status = status
136
+ test_method = method
137
+ test_error = error
138
+ end.once
139
+
140
+ get "/no/controller/here"
141
+
142
+ assert_equal nil, test_action
143
+ assert_equal "http://example.org/no/controller/here", test_url
144
+ assert_equal 404, test_status
145
+ assert_equal "GET", test_method
146
+ assert_equal 0, test_error
147
+ end
148
+
149
+ def test_does_not_send_http_span_for_static_assets
150
+ AppOpticsAPM::Span.expects(:createHttpSpan).never
151
+
152
+ get "/assets/static_asset.png"
153
+ end
154
+
155
+ # the status returned by @app.call(env) is usually an integer, but there are cases where it is a string
156
+ # encountered by this app: https://github.com/librato/api which proxies requests "through to a java service by rack"
157
+ def test_status_can_be_a_string
158
+ Rack::URLMap.any_instance.stubs(:call).returns(["200", {"Content-Length"=>"592"}, "the body"])
159
+
160
+ result = get '/lobster'
161
+
162
+ assert_equal 200, result.status
163
+ end
164
+ end
165
+