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