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,242 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'json'
5
+
6
+ module AppOpticsAPM
7
+ module Inst
8
+ module Mongo
9
+ FLAVOR = 'mongodb'
10
+
11
+ # Operations for Mongo::DB
12
+ DB_OPS = [:create_collection, :drop_collection]
13
+
14
+ # Operations for Mongo::Cursor
15
+ CURSOR_OPS = [:count]
16
+
17
+ # Operations for Mongo::Collection
18
+ COLL_WRITE_OPS = [:find_and_modify, :insert, :map_reduce, :remove, :rename, :update]
19
+ COLL_QUERY_OPS = [:distinct, :find, :group]
20
+ COLL_INDEX_OPS = [:create_index, :drop_index, :drop_indexes, :ensure_index, :index_information]
21
+ end
22
+ end
23
+ end
24
+
25
+ if defined?(::Mongo) && (Gem.loaded_specs['mongo'].version.to_s < '2.0.0') && AppOpticsAPM::Config[:mongo][:enabled]
26
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting mongo' if AppOpticsAPM::Config[:verbose]
27
+
28
+ if defined?(::Mongo::DB)
29
+ module ::Mongo
30
+ class DB
31
+ include AppOpticsAPM::Inst::Mongo
32
+
33
+ # Instrument DB operations
34
+ AppOpticsAPM::Inst::Mongo::DB_OPS.reject { |m| !method_defined?(m) }.each do |m|
35
+ define_method("#{m}_with_appoptics") do |*args|
36
+ report_kvs = {}
37
+
38
+ begin
39
+ report_kvs[:Flavor] = AppOpticsAPM::Inst::Mongo::FLAVOR
40
+
41
+ report_kvs[:Database] = @name
42
+
43
+ # Mongo >= 1.10 uses @client instead of @connection
44
+ # Avoid the nil
45
+ if @connection
46
+ report_kvs[:RemoteHost] = @connection.host
47
+ report_kvs[:RemotePort] = @connection.port
48
+ elsif @client
49
+ report_kvs[:RemoteHost] = @client.host
50
+ report_kvs[:RemotePort] = @client.port
51
+ end
52
+
53
+ report_kvs[:QueryOp] = m
54
+
55
+ report_kvs[:New_Collection_Name] = args[0] if m == :create_collection
56
+ report_kvs[:Collection] = args[0] if m == :drop_collection
57
+
58
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:mongo][:collect_backtraces]
59
+ rescue => e
60
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
61
+ end
62
+
63
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
64
+ send("#{m}_without_appoptics", *args)
65
+ end
66
+ end
67
+
68
+ class_eval "alias #{m}_without_appoptics #{m}"
69
+ class_eval "alias #{m} #{m}_with_appoptics"
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ if defined?(::Mongo::Cursor)
76
+ module ::Mongo
77
+ class Cursor
78
+ include AppOpticsAPM::Inst::Mongo
79
+
80
+ # Instrument DB cursor operations
81
+ AppOpticsAPM::Inst::Mongo::CURSOR_OPS.reject { |m| !method_defined?(m) }.each do |m|
82
+ define_method("#{m}_with_appoptics") do |*args|
83
+ report_kvs = {}
84
+
85
+ begin
86
+ report_kvs[:Flavor] = AppOpticsAPM::Inst::Mongo::FLAVOR
87
+
88
+ report_kvs[:Database] = @db.name
89
+ report_kvs[:RemoteHost] = @connection.host
90
+ report_kvs[:RemotePort] = @connection.port
91
+
92
+ report_kvs[:QueryOp] = m
93
+ if m == :count
94
+ unless @selector.empty?
95
+ report_kvs[:Query] = @selector.to_json
96
+ else
97
+ report_kvs[:Query] = :all
98
+ end
99
+ report_kvs[:Limit] = @limit if @limit != 0
100
+ end
101
+ rescue => e
102
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
103
+ end
104
+
105
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
106
+ send("#{m}_without_appoptics", *args)
107
+ end
108
+ end
109
+
110
+ class_eval "alias #{m}_without_appoptics #{m}"
111
+ class_eval "alias #{m} #{m}_with_appoptics"
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ if defined?(::Mongo::Collection)
118
+ module ::Mongo
119
+ class Collection
120
+ include AppOpticsAPM::Inst::Mongo
121
+
122
+ def appoptics_collect(m, args)
123
+ kvs = {}
124
+ kvs[:Flavor] = AppOpticsAPM::Inst::Mongo::FLAVOR
125
+
126
+ kvs[:Database] = @db.name
127
+ kvs[:RemoteHost] = @db.connection.host
128
+ kvs[:RemotePort] = @db.connection.port
129
+ kvs[:Collection] = @name
130
+
131
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:mongo][:collect_backtraces]
132
+
133
+ kvs[:QueryOp] = m
134
+ kvs[:Query] = args[0].to_json if args && !args.empty? && args[0].class == Hash
135
+ rescue StandardError => e
136
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] Exception in appoptics_collect KV collection: #{e.inspect}"
137
+ ensure
138
+ return kvs
139
+ end
140
+
141
+ # Instrument Collection write operations
142
+ AppOpticsAPM::Inst::Mongo::COLL_WRITE_OPS.reject { |m| !method_defined?(m) }.each do |m|
143
+ define_method("#{m}_with_appoptics") do |*args|
144
+ report_kvs = appoptics_collect(m, args)
145
+ args_length = args.length
146
+
147
+ begin
148
+ if m == :find_and_modify && args[0] && args[0].key?(:update)
149
+ report_kvs[:Update_Document] = args[0][:update].inspect
150
+ end
151
+
152
+ if m == :map_reduce
153
+ report_kvs[:Map_Function] = args[0]
154
+ report_kvs[:Reduce_Function] = args[1]
155
+ report_kvs[:Limit] = args[2][:limit] if args[2] && args[2].key?(:limit)
156
+ end
157
+
158
+ report_kvs[:New_Collection_Name] = args[0] if m == :rename
159
+
160
+ if m == :update
161
+ if args_length >= 3
162
+ report_kvs[:Update_Document] = args[1].to_json
163
+ report_kvs[:Multi] = args[2][:multi] if args[2] && args[2].key?(:multi)
164
+ end
165
+ end
166
+ rescue => e
167
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
168
+ end
169
+
170
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
171
+ send("#{m}_without_appoptics", *args)
172
+ end
173
+ end
174
+
175
+ class_eval "alias #{m}_without_appoptics #{m}"
176
+ class_eval "alias #{m} #{m}_with_appoptics"
177
+ end
178
+
179
+ # Instrument Collection query operations
180
+ AppOpticsAPM::Inst::Mongo::COLL_QUERY_OPS.reject { |m| !method_defined?(m) }.each do |m|
181
+ define_method("#{m}_with_appoptics") do |*args, &blk|
182
+ begin
183
+ report_kvs = appoptics_collect(m, args)
184
+ args_length = args.length
185
+
186
+ if m == :distinct && args_length >= 2
187
+ report_kvs[:Key] = args[0]
188
+ report_kvs[:Query] = args[1].to_json if args[1] && args[1].class == Hash
189
+ end
190
+
191
+ if m == :find && args_length > 0
192
+ report_kvs[:Limit] = args[0][:limit] if !args[0].nil? && args[0].key?(:limit)
193
+ end
194
+
195
+ if m == :group
196
+ unless args.empty?
197
+ if args[0].is_a?(Hash)
198
+ report_kvs[:Group_Key] = args[0][:key].to_json if args[0].key?(:key)
199
+ report_kvs[:Group_Condition] = args[0][:cond].to_json if args[0].key?(:cond)
200
+ report_kvs[:Group_Initial] = args[0][:initial].to_json if args[0].key?(:initial)
201
+ report_kvs[:Group_Reduce] = args[0][:reduce] if args[0].key?(:reduce)
202
+ end
203
+ end
204
+ end
205
+ rescue => e
206
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
207
+ end
208
+
209
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
210
+ send("#{m}_without_appoptics", *args, &blk)
211
+ end
212
+ end
213
+
214
+ class_eval "alias #{m}_without_appoptics #{m}"
215
+ class_eval "alias #{m} #{m}_with_appoptics"
216
+ end
217
+
218
+ # Instrument Collection index operations
219
+ AppOpticsAPM::Inst::Mongo::COLL_INDEX_OPS.reject { |m| !method_defined?(m) }.each do |m|
220
+ define_method("#{m}_with_appoptics") do |*args|
221
+ report_kvs = appoptics_collect(m, args)
222
+
223
+ begin
224
+ if [:create_index, :ensure_index, :drop_index].include?(m) && !args.empty?
225
+ report_kvs[:Index] = args[0].to_json
226
+ end
227
+ rescue => e
228
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
229
+ end
230
+
231
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
232
+ send("#{m}_without_appoptics", *args)
233
+ end
234
+ end
235
+
236
+ class_eval "alias #{m}_without_appoptics #{m}"
237
+ class_eval "alias #{m} #{m}_with_appoptics"
238
+ end
239
+ end
240
+ end
241
+ end
242
+ end
@@ -0,0 +1,225 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'json'
5
+
6
+ if RUBY_VERSION >= '1.9' && AppOpticsAPM::Config[:mongo][:enabled]
7
+ if defined?(::Mongo) && (Gem.loaded_specs['mongo'].version.to_s >= '2.0.0')
8
+ ::AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting mongo' if AppOpticsAPM::Config[:verbose]
9
+
10
+ # Collection Related Operations
11
+ COLL_OTHER_OPS = [:create, :drop, :insert_one, :insert_many, :bulk_write, :map_reduce].freeze
12
+
13
+ # Mongo 2.2 only ops
14
+ if Mongo::VERSION >= '2.1'
15
+ COLL_QUERY_OPS = [:find, :find_one_and_delete, :find_one_and_update, :find_one_and_replace, :update_one, :update_many, :delete_one, :delete_many, :replace_one].freeze
16
+ else
17
+ COLL_QUERY_OPS = [:find, :update_many, :delete_one].freeze
18
+ end
19
+
20
+ COLL_OPS = COLL_QUERY_OPS + COLL_OTHER_OPS
21
+
22
+ module Mongo
23
+ class Collection
24
+ ##
25
+ # collect_kvs
26
+ #
27
+ # Used to collect up information to report and build a hash
28
+ # with the Keys/Values to report.
29
+ #
30
+ def collect_kvs(op, args)
31
+ kvs = { :Flavor => :mongodb, :Database => @database.name }
32
+
33
+ kvs[:QueryOp] = op
34
+
35
+ if op == :create
36
+ kvs[:New_Collection_Name] = @name
37
+ else
38
+ kvs[:Collection] = @name
39
+ end
40
+
41
+ if op == :map_reduce
42
+ kvs[:Map_Function] = args[0]
43
+ kvs[:Reduce_Function] = args[1]
44
+ kvs[:Limit] = args[2][:limit] if args[2].is_a?(Hash) && args[2].key?(:limit)
45
+ end
46
+
47
+ if AppOpticsAPM::Config[:mongo][:log_args]
48
+ if COLL_QUERY_OPS.include?(op)
49
+ kvs[:Query] = args.first.to_json
50
+ end
51
+ end
52
+
53
+ kvs[:RemoteHost] = @database.client.cluster.addresses.first.to_s
54
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:mongo][:collect_backtraces]
55
+ rescue => e
56
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
57
+ ensure
58
+ return kvs
59
+ end
60
+
61
+ ##
62
+ # Here we dynamically define wrapper methods for the operations
63
+ # we want to instrument in mongo
64
+ #
65
+ COLL_OPS.reject { |m| !method_defined?(m) }.each do |m|
66
+ define_method("#{m}_with_appoptics") do |*args|
67
+ begin
68
+ if !AppOpticsAPM.tracing? || AppOpticsAPM.tracing_layer?(:mongo)
69
+ mongo_skipped = true
70
+ return send("#{m}_without_appoptics", *args)
71
+ end
72
+
73
+ kvs = collect_kvs(m, args)
74
+ AppOpticsAPM::API.log_entry(:mongo, kvs)
75
+
76
+ send("#{m}_without_appoptics", *args)
77
+ rescue => e
78
+ AppOpticsAPM::API.log_exception(:mongo, e)
79
+ raise e
80
+ ensure
81
+ AppOpticsAPM::API.log_exit(:mongo) unless mongo_skipped
82
+ end
83
+ end
84
+ ::AppOpticsAPM::Util.method_alias(Mongo::Collection, m)
85
+ end
86
+ end
87
+ end
88
+
89
+ ##
90
+ # Mongo Collection View Instrumentation
91
+ #
92
+
93
+ # Collection View Related Operations
94
+ VIEW_QUERY_OPS = [:delete_one, :delete_many, :count, :distinct, :find_one_and_delete, :find_one_and_update,
95
+ :replace_one, :update_one, :update_many].freeze
96
+ VIEW_OTHER_OPS = [:aggregate, :map_reduce ].freeze
97
+ VIEW_OPS = VIEW_QUERY_OPS + VIEW_OTHER_OPS
98
+
99
+ module Mongo
100
+ class Collection
101
+ class View
102
+ ##
103
+ # collect_kvs
104
+ #
105
+ # Used to collect up information to report and build a hash
106
+ # with the Keys/Values to report.
107
+ #
108
+ def collect_kvs(op, args)
109
+ kvs = { :Flavor => :mongodb, :Database => @collection.database.name }
110
+
111
+ kvs[:QueryOp] = op
112
+ kvs[:Collection] = @collection.name
113
+
114
+ if op == :map_reduce
115
+ kvs[:Map_Function] = args[0]
116
+ kvs[:Reduce_Function] = args[1]
117
+ kvs[:Limit] = args[2][:limit] if args[2].is_a?(Hash) && args[2].key?(:limit)
118
+ end
119
+
120
+ if AppOpticsAPM::Config[:mongo][:log_args]
121
+ if VIEW_QUERY_OPS.include?(op)
122
+ if defined?(filter)
123
+ kvs[:Query] = filter.to_json
124
+ elsif defined?(selector)
125
+ kvs[:Query] = selector.to_json
126
+ end
127
+ end
128
+ end
129
+
130
+ kvs[:RemoteHost] = @collection.database.client.cluster.addresses.first.to_s
131
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:mongo][:collect_backtraces]
132
+ rescue => e
133
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
134
+ ensure
135
+ return kvs
136
+ end
137
+
138
+ ##
139
+ # Here we dynamically define wrapper methods for the operations
140
+ # we want to instrument in mongo
141
+ #
142
+ VIEW_OPS.reject { |m| !method_defined?(m) }.each do |m|
143
+ define_method("#{m}_with_appoptics") do |*args|
144
+ begin
145
+ if !AppOpticsAPM.tracing? || AppOpticsAPM.tracing_layer?(:mongo)
146
+ mongo_skipped = true
147
+ return send("#{m}_without_appoptics", *args)
148
+ end
149
+
150
+ kvs = collect_kvs(m, args)
151
+ AppOpticsAPM::API.log_entry(:mongo, kvs)
152
+
153
+ send("#{m}_without_appoptics", *args)
154
+ rescue => e
155
+ AppOpticsAPM::API.log_exception(:mongo, e)
156
+ raise e
157
+ ensure
158
+ AppOpticsAPM::API.log_exit(:mongo) unless mongo_skipped
159
+ end
160
+ end
161
+ ::AppOpticsAPM::Util.method_alias(Mongo::Collection::View, m)
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ ##
168
+ # Mongo Collection Index View Instrumentation
169
+ #
170
+
171
+ # Collection Index View Related Operations
172
+ INDEX_OPS = [:create_one, :create_many, :drop_one, :drop_all].freeze
173
+
174
+ module Mongo
175
+ module Index
176
+ class View
177
+ ##
178
+ # collect_kvs
179
+ #
180
+ # Used to collect up information to report and build a hash
181
+ # with the Keys/Values to report.
182
+ #
183
+ def collect_index_kvs(op, args)
184
+ kvs = { :Flavor => :mongodb, :Database => @collection.database.name }
185
+
186
+ kvs[:QueryOp] = op
187
+ kvs[:Collection] = @collection.name
188
+ kvs[:RemoteHost] = @collection.database.client.cluster.addresses.first.to_s
189
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:mongo][:collect_backtraces]
190
+ rescue => e
191
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
192
+ ensure
193
+ return kvs
194
+ end
195
+
196
+ ##
197
+ # Here we dynamically define wrapper methods for the operations
198
+ # we want to instrument in mongo
199
+ #
200
+ INDEX_OPS.reject { |m| !method_defined?(m) }.each do |m|
201
+ define_method("#{m}_with_appoptics") do |*args|
202
+ begin
203
+ if !AppOpticsAPM.tracing? || AppOpticsAPM.tracing_layer?(:mongo)
204
+ mongo_skipped = true
205
+ return send("#{m}_without_appoptics", *args)
206
+ end
207
+
208
+ kvs = collect_index_kvs(m, args)
209
+ AppOpticsAPM::API.log_entry(:mongo, kvs)
210
+
211
+ send("#{m}_without_appoptics", *args)
212
+ rescue => e
213
+ AppOpticsAPM::API.log_exception(:mongo, e)
214
+ raise e
215
+ ensure
216
+ AppOpticsAPM::API.log_exit(:mongo) unless mongo_skipped
217
+ end
218
+ end
219
+ ::AppOpticsAPM::Util.method_alias(Mongo::Index::View, m)
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
225
+ end