appoptics_apm-zearn 4.13.1

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 (145) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +5 -0
  3. data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
  4. data/.github/workflows/build_and_release_gem.yml +103 -0
  5. data/.github/workflows/build_for_packagecloud.yml +70 -0
  6. data/.github/workflows/docker-images.yml +47 -0
  7. data/.github/workflows/run_cpluplus_tests.yml +73 -0
  8. data/.github/workflows/run_tests.yml +168 -0
  9. data/.github/workflows/scripts/test_install.rb +23 -0
  10. data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
  11. data/.github/workflows/test_on_4_linux.yml +159 -0
  12. data/.gitignore +36 -0
  13. data/.rubocop.yml +29 -0
  14. data/.travis.yml +130 -0
  15. data/.yardopts +6 -0
  16. data/CHANGELOG.md +769 -0
  17. data/CONFIG.md +33 -0
  18. data/Gemfile +14 -0
  19. data/LICENSE +202 -0
  20. data/README.md +393 -0
  21. data/appoptics_apm.gemspec +70 -0
  22. data/bin/appoptics_apm_config +15 -0
  23. data/examples/prepend.rb +13 -0
  24. data/examples/sdk_examples.rb +158 -0
  25. data/ext/oboe_metal/README.md +69 -0
  26. data/ext/oboe_metal/extconf.rb +151 -0
  27. data/ext/oboe_metal/lib/.keep +0 -0
  28. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
  29. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
  30. data/ext/oboe_metal/noop/noop.c +8 -0
  31. data/ext/oboe_metal/src/README.md +6 -0
  32. data/ext/oboe_metal/src/VERSION +2 -0
  33. data/ext/oboe_metal/src/bson/bson.h +220 -0
  34. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  35. data/ext/oboe_metal/src/frames.cc +246 -0
  36. data/ext/oboe_metal/src/frames.h +40 -0
  37. data/ext/oboe_metal/src/init_appoptics_apm.cc +21 -0
  38. data/ext/oboe_metal/src/logging.cc +95 -0
  39. data/ext/oboe_metal/src/logging.h +35 -0
  40. data/ext/oboe_metal/src/oboe.h +1156 -0
  41. data/ext/oboe_metal/src/oboe_api.cpp +652 -0
  42. data/ext/oboe_metal/src/oboe_api.hpp +431 -0
  43. data/ext/oboe_metal/src/oboe_debug.h +59 -0
  44. data/ext/oboe_metal/src/oboe_swig_wrap.cc +7329 -0
  45. data/ext/oboe_metal/src/profiling.cc +435 -0
  46. data/ext/oboe_metal/src/profiling.h +78 -0
  47. data/ext/oboe_metal/test/CMakeLists.txt +53 -0
  48. data/ext/oboe_metal/test/FindGMock.cmake +43 -0
  49. data/ext/oboe_metal/test/README.md +56 -0
  50. data/ext/oboe_metal/test/frames_test.cc +164 -0
  51. data/ext/oboe_metal/test/profiling_test.cc +93 -0
  52. data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
  53. data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
  54. data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
  55. data/ext/oboe_metal/test/test.h +11 -0
  56. data/ext/oboe_metal/test/test_main.cc +32 -0
  57. data/init.rb +4 -0
  58. data/lib/appoptics_apm/api/layerinit.rb +41 -0
  59. data/lib/appoptics_apm/api/logging.rb +381 -0
  60. data/lib/appoptics_apm/api/memcache.rb +37 -0
  61. data/lib/appoptics_apm/api/metrics.rb +63 -0
  62. data/lib/appoptics_apm/api/tracing.rb +57 -0
  63. data/lib/appoptics_apm/api/util.rb +120 -0
  64. data/lib/appoptics_apm/api.rb +21 -0
  65. data/lib/appoptics_apm/base.rb +231 -0
  66. data/lib/appoptics_apm/config.rb +299 -0
  67. data/lib/appoptics_apm/frameworks/grape.rb +98 -0
  68. data/lib/appoptics_apm/frameworks/padrino.rb +78 -0
  69. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +104 -0
  70. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
  71. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  72. data/lib/appoptics_apm/frameworks/rails/inst/action_controller6.rb +50 -0
  73. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  74. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +88 -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 +29 -0
  78. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +31 -0
  79. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +119 -0
  80. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +114 -0
  81. data/lib/appoptics_apm/frameworks/rails/inst/logger_formatters.rb +27 -0
  82. data/lib/appoptics_apm/frameworks/rails.rb +100 -0
  83. data/lib/appoptics_apm/frameworks/sinatra.rb +96 -0
  84. data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
  85. data/lib/appoptics_apm/inst/bunny-consumer.rb +89 -0
  86. data/lib/appoptics_apm/inst/curb.rb +332 -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 +101 -0
  90. data/lib/appoptics_apm/inst/excon.rb +125 -0
  91. data/lib/appoptics_apm/inst/faraday.rb +106 -0
  92. data/lib/appoptics_apm/inst/graphql.rb +240 -0
  93. data/lib/appoptics_apm/inst/grpc_client.rb +159 -0
  94. data/lib/appoptics_apm/inst/grpc_server.rb +120 -0
  95. data/lib/appoptics_apm/inst/http.rb +81 -0
  96. data/lib/appoptics_apm/inst/httpclient.rb +174 -0
  97. data/lib/appoptics_apm/inst/logger_formatter.rb +50 -0
  98. data/lib/appoptics_apm/inst/logging_log_event.rb +28 -0
  99. data/lib/appoptics_apm/inst/lumberjack_formatter.rb +13 -0
  100. data/lib/appoptics_apm/inst/memcached.rb +86 -0
  101. data/lib/appoptics_apm/inst/mongo.rb +246 -0
  102. data/lib/appoptics_apm/inst/mongo2.rb +225 -0
  103. data/lib/appoptics_apm/inst/moped.rb +466 -0
  104. data/lib/appoptics_apm/inst/rack.rb +182 -0
  105. data/lib/appoptics_apm/inst/rack_cache.rb +35 -0
  106. data/lib/appoptics_apm/inst/redis.rb +274 -0
  107. data/lib/appoptics_apm/inst/resque.rb +151 -0
  108. data/lib/appoptics_apm/inst/rest-client.rb +48 -0
  109. data/lib/appoptics_apm/inst/sequel.rb +178 -0
  110. data/lib/appoptics_apm/inst/sidekiq-client.rb +55 -0
  111. data/lib/appoptics_apm/inst/sidekiq-worker.rb +66 -0
  112. data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
  113. data/lib/appoptics_apm/inst/typhoeus.rb +108 -0
  114. data/lib/appoptics_apm/instrumentation.rb +22 -0
  115. data/lib/appoptics_apm/loading.rb +65 -0
  116. data/lib/appoptics_apm/logger.rb +14 -0
  117. data/lib/appoptics_apm/noop/README.md +9 -0
  118. data/lib/appoptics_apm/noop/context.rb +27 -0
  119. data/lib/appoptics_apm/noop/metadata.rb +25 -0
  120. data/lib/appoptics_apm/noop/profiling.rb +21 -0
  121. data/lib/appoptics_apm/oboe_init_options.rb +211 -0
  122. data/lib/appoptics_apm/ruby.rb +35 -0
  123. data/lib/appoptics_apm/sdk/current_trace.rb +77 -0
  124. data/lib/appoptics_apm/sdk/custom_metrics.rb +94 -0
  125. data/lib/appoptics_apm/sdk/logging.rb +37 -0
  126. data/lib/appoptics_apm/sdk/tracing.rb +434 -0
  127. data/lib/appoptics_apm/support/profiling.rb +18 -0
  128. data/lib/appoptics_apm/support/transaction_metrics.rb +67 -0
  129. data/lib/appoptics_apm/support/transaction_settings.rb +219 -0
  130. data/lib/appoptics_apm/support/x_trace_options.rb +110 -0
  131. data/lib/appoptics_apm/support_report.rb +119 -0
  132. data/lib/appoptics_apm/test.rb +95 -0
  133. data/lib/appoptics_apm/thread_local.rb +26 -0
  134. data/lib/appoptics_apm/util.rb +326 -0
  135. data/lib/appoptics_apm/version.rb +16 -0
  136. data/lib/appoptics_apm/xtrace.rb +115 -0
  137. data/lib/appoptics_apm.rb +77 -0
  138. data/lib/joboe_metal.rb +212 -0
  139. data/lib/oboe.rb +7 -0
  140. data/lib/oboe_metal.rb +172 -0
  141. data/lib/rails/generators/appoptics_apm/install_generator.rb +47 -0
  142. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +425 -0
  143. data/log/.keep +0 -0
  144. data/yardoc_frontpage.md +26 -0
  145. metadata +231 -0
@@ -0,0 +1,466 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'json'
5
+
6
+ module AppOpticsAPM
7
+ module Inst
8
+ ##
9
+ # Moped
10
+ #
11
+ module Moped
12
+ FLAVOR = :mongodb
13
+
14
+ # Moped::Database
15
+ DB_OPS = [:command, :drop].freeze
16
+
17
+ # Moped::Indexes
18
+ INDEX_OPS = [:create, :drop].freeze
19
+
20
+ # Moped::Query
21
+ QUERY_OPS = [:count, :sort, :limit, :distinct, :update, :update_all, :upsert,
22
+ :explain, :modify, :remove, :remove_all].freeze
23
+
24
+ # Moped::Collection
25
+ COLLECTION_OPS = [:drop, :find, :indexes, :insert, :aggregate].freeze
26
+
27
+ ##
28
+ # remote_host
29
+ #
30
+ # This utility method converts the server into a host:port
31
+ # pair for reporting
32
+ #
33
+ def remote_host(server)
34
+ if ::Moped::VERSION < '2.0.0'
35
+ server
36
+ else
37
+ "#{server.address.host}:#{server.address.port}"
38
+ end
39
+ end
40
+ end
41
+
42
+ ##
43
+ # MopedDatabase
44
+ #
45
+ module MopedDatabase
46
+ include AppOpticsAPM::Inst::Moped
47
+
48
+ def self.included(klass)
49
+ AppOpticsAPM::Inst::Moped::DB_OPS.each do |m|
50
+ AppOpticsAPM::Util.method_alias(klass, m)
51
+ end
52
+ end
53
+
54
+ def extract_trace_details(op)
55
+ report_kvs = {}
56
+ report_kvs[:Flavor] = AppOpticsAPM::Inst::Moped::FLAVOR
57
+ # FIXME: We're only grabbing the first of potentially multiple servers here
58
+ report_kvs[:RemoteHost] = remote_host(session.cluster.seeds.first)
59
+ report_kvs[:Database] = name
60
+ report_kvs[:QueryOp] = op.to_s
61
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:moped][:collect_backtraces]
62
+ rescue StandardError => e
63
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
64
+ ensure
65
+ return report_kvs
66
+ end
67
+
68
+ def command_with_appoptics(command)
69
+ if AppOpticsAPM.tracing? && !AppOpticsAPM.layer_op && command.key?(:mapreduce)
70
+ begin
71
+ report_kvs = extract_trace_details(:map_reduce)
72
+ report_kvs[:Map_Function] = command[:map]
73
+ report_kvs[:Reduce_Function] = command[:reduce]
74
+ rescue => e
75
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
76
+ end
77
+
78
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
79
+ command_without_appoptics(command)
80
+ end
81
+ else
82
+ command_without_appoptics(command)
83
+ end
84
+ end
85
+
86
+ def drop_with_appoptics
87
+ return drop_without_appoptics unless AppOpticsAPM.tracing?
88
+
89
+ report_kvs = extract_trace_details(:drop_database)
90
+
91
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
92
+ drop_without_appoptics
93
+ end
94
+ end
95
+ end
96
+
97
+ ##
98
+ # MopedIndexes
99
+ #
100
+ module MopedIndexes
101
+ include AppOpticsAPM::Inst::Moped
102
+
103
+ def self.included(klass)
104
+ AppOpticsAPM::Inst::Moped::INDEX_OPS.each do |m|
105
+ AppOpticsAPM::Util.method_alias(klass, m)
106
+ end
107
+ end
108
+
109
+ def extract_trace_details(op)
110
+ report_kvs = {}
111
+ report_kvs[:Flavor] = AppOpticsAPM::Inst::Moped::FLAVOR
112
+
113
+ # FIXME: We're only grabbing the first of potentially multiple servers here
114
+ first = database.session.cluster.seeds.first
115
+ if ::Moped::VERSION < '2.0.0'
116
+ report_kvs[:RemoteHost] = first
117
+ else
118
+ report_kvs[:RemoteHost] = "#{first.address.host}:#{first.address.port}"
119
+ end
120
+ report_kvs[:Database] = database.name
121
+ report_kvs[:QueryOp] = op.to_s
122
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:moped][:collect_backtraces]
123
+ rescue StandardError => e
124
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
125
+ ensure
126
+ return report_kvs
127
+ end
128
+
129
+ def create_with_appoptics(key, options = {})
130
+ return create_without_appoptics(key, options) unless AppOpticsAPM.tracing?
131
+
132
+ begin
133
+ # We report :create_index here to be consistent
134
+ # with other mongo implementations
135
+ report_kvs = extract_trace_details(:create_index)
136
+ report_kvs[:Key] = key.to_json
137
+ report_kvs[:Options] = options.to_json
138
+ rescue StandardError => e
139
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
140
+ end
141
+
142
+ AppOpticsAPM::API.trace(:mongo, report_kvs, :create_index) do
143
+ create_without_appoptics(key, options = {})
144
+ end
145
+ end
146
+
147
+ def drop_with_appoptics(key = nil)
148
+ return drop_without_appoptics(key) unless AppOpticsAPM.tracing?
149
+
150
+ begin
151
+ # We report :drop_indexes here to be consistent
152
+ # with other mongo implementations
153
+ report_kvs = extract_trace_details(:drop_indexes)
154
+ report_kvs[:Key] = key.nil? ? :all : key.to_json
155
+ rescue StandardError => e
156
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
157
+ end
158
+
159
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
160
+ drop_without_appoptics(key = nil)
161
+ end
162
+ end
163
+ end
164
+
165
+ ##
166
+ # MopedQuery
167
+ #
168
+ module MopedQuery
169
+ include AppOpticsAPM::Inst::Moped
170
+
171
+ def self.included(klass)
172
+ AppOpticsAPM::Inst::Moped::QUERY_OPS.each do |m|
173
+ AppOpticsAPM::Util.method_alias(klass, m)
174
+ end
175
+ end
176
+
177
+ def extract_trace_details(op)
178
+ report_kvs = {}
179
+ report_kvs[:Flavor] = AppOpticsAPM::Inst::Moped::FLAVOR
180
+ # FIXME: We're only grabbing the first of potentially multiple servers here
181
+ first = collection.database.session.cluster.seeds.first
182
+ report_kvs[:RemoteHost] = remote_host(first)
183
+ report_kvs[:Database] = collection.database.name
184
+ report_kvs[:Collection] = collection.name
185
+ report_kvs[:QueryOp] = op.to_s
186
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:moped][:collect_backtraces]
187
+ rescue StandardError => e
188
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
189
+ ensure
190
+ return report_kvs
191
+ end
192
+
193
+ def count_with_appoptics
194
+ return count_without_appoptics unless AppOpticsAPM.tracing?
195
+
196
+ begin
197
+ report_kvs = extract_trace_details(:count)
198
+ report_kvs[:Query] = selector.empty? ? :all : selector.to_json
199
+ rescue StandardError => e
200
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
201
+ end
202
+
203
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
204
+ count_without_appoptics
205
+ end
206
+ end
207
+
208
+ def sort_with_appoptics(sort)
209
+ return sort_without_appoptics(sort) unless AppOpticsAPM.tracing?
210
+
211
+ begin
212
+ report_kvs = extract_trace_details(:sort)
213
+ report_kvs[:Query] = selector.empty? ? :all : selector.to_json
214
+ report_kvs[:Order] = sort.to_s
215
+ rescue StandardError => e
216
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
217
+ end
218
+
219
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
220
+ sort_without_appoptics(sort)
221
+ end
222
+ end
223
+
224
+ def limit_with_appoptics(limit)
225
+ if AppOpticsAPM.tracing? && !AppOpticsAPM.tracing_layer_op?(:explain)
226
+ begin
227
+ report_kvs = extract_trace_details(:limit)
228
+ report_kvs[:Query] = selector.empty? ? :all : selector.to_json
229
+ report_kvs[:Limit] = limit.to_s
230
+ rescue StandardError => e
231
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
232
+ end
233
+
234
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
235
+ limit_without_appoptics(limit)
236
+ end
237
+ else
238
+ limit_without_appoptics(limit)
239
+ end
240
+ end
241
+
242
+ def distinct_with_appoptics(key)
243
+ return distinct_without_appoptics(key) unless AppOpticsAPM.tracing?
244
+
245
+ begin
246
+ report_kvs = extract_trace_details(:distinct)
247
+ report_kvs[:Query] = selector.empty? ? :all : selector.to_json
248
+ report_kvs[:Key] = key.to_s
249
+ rescue StandardError => e
250
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
251
+ end
252
+
253
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
254
+ distinct_without_appoptics(key)
255
+ end
256
+ end
257
+
258
+ def update_with_appoptics(change, flags = nil)
259
+ if AppOpticsAPM.tracing? && !AppOpticsAPM.tracing_layer_op?(:update_all) && !AppOpticsAPM.tracing_layer_op?(:upsert)
260
+ begin
261
+ report_kvs = extract_trace_details(:update)
262
+ report_kvs[:Flags] = flags.to_s if flags
263
+ report_kvs[:Update_Document] = change.to_json
264
+ rescue StandardError => e
265
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
266
+ end
267
+
268
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
269
+ update_without_appoptics(change, flags)
270
+ end
271
+ else
272
+ update_without_appoptics(change, flags)
273
+ end
274
+ end
275
+
276
+ def update_all_with_appoptics(change)
277
+ return update_all_without_appoptics(change) unless AppOpticsAPM.tracing?
278
+
279
+ begin
280
+ report_kvs = extract_trace_details(:update_all)
281
+ report_kvs[:Update_Document] = change.to_json
282
+ rescue StandardError => e
283
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
284
+ end
285
+
286
+ AppOpticsAPM::API.trace(:mongo, report_kvs, :update_all) do
287
+ update_all_without_appoptics(change)
288
+ end
289
+ end
290
+
291
+ def upsert_with_appoptics(change)
292
+ return upsert_without_appoptics(change) unless AppOpticsAPM.tracing?
293
+
294
+ begin
295
+ report_kvs = extract_trace_details(:upsert)
296
+ report_kvs[:Query] = selector.to_json
297
+ report_kvs[:Update_Document] = change.to_json
298
+ rescue StandardError => e
299
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
300
+ end
301
+
302
+ AppOpticsAPM::API.trace(:mongo, report_kvs, :upsert) do
303
+ upsert_without_appoptics(change)
304
+ end
305
+ end
306
+
307
+ def explain_with_appoptics
308
+ return explain_without_appoptics unless AppOpticsAPM.tracing?
309
+
310
+ begin
311
+ report_kvs = extract_trace_details(:explain)
312
+ report_kvs[:Query] = selector.empty? ? :all : selector.to_json
313
+ rescue StandardError => e
314
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
315
+ end
316
+
317
+ AppOpticsAPM::API.trace(:mongo, report_kvs, :explain) do
318
+ explain_without_appoptics
319
+ end
320
+ end
321
+
322
+ def modify_with_appoptics(change, options = {})
323
+ return modify_without_appoptics(change, options) unless AppOpticsAPM.tracing?
324
+
325
+ begin
326
+ report_kvs = extract_trace_details(:modify)
327
+ report_kvs[:Update_Document] = selector.empty? ? :all : selector.to_json
328
+ report_kvs[:Change] = change.to_json
329
+ report_kvs[:Options] = options.to_json
330
+ rescue StandardError => e
331
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
332
+ end
333
+
334
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
335
+ modify_without_appoptics(change, options)
336
+ end
337
+ end
338
+
339
+ def remove_with_appoptics
340
+ return remove_without_appoptics unless AppOpticsAPM.tracing?
341
+
342
+ begin
343
+ report_kvs = extract_trace_details(:remove)
344
+ report_kvs[:Query] = selector.to_json
345
+ rescue StandardError => e
346
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
347
+ end
348
+
349
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
350
+ remove_without_appoptics
351
+ end
352
+ end
353
+
354
+ def remove_all_with_appoptics
355
+ return remove_all_without_appoptics unless AppOpticsAPM.tracing?
356
+
357
+ begin
358
+ report_kvs = extract_trace_details(:remove_all)
359
+ report_kvs[:Query] = selector.to_json
360
+ rescue StandardError => e
361
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
362
+ end
363
+
364
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
365
+ remove_all_without_appoptics
366
+ end
367
+ end
368
+ end
369
+
370
+ ##
371
+ # MopedCollection
372
+ #
373
+ module MopedCollection
374
+ include AppOpticsAPM::Inst::Moped
375
+
376
+ def self.included(klass)
377
+ AppOpticsAPM::Inst::Moped::COLLECTION_OPS.each do |m|
378
+ AppOpticsAPM::Util.method_alias(klass, m)
379
+ end
380
+ end
381
+
382
+ def extract_trace_details(op)
383
+ report_kvs = {}
384
+ report_kvs[:Flavor] = AppOpticsAPM::Inst::Moped::FLAVOR
385
+ # FIXME: We're only grabbing the first of potentially multiple servers here
386
+ report_kvs[:RemoteHost] = remote_host(database.session.cluster.seeds.first)
387
+ report_kvs[:Database] = database.name
388
+ report_kvs[:Collection] = name
389
+ report_kvs[:QueryOp] = op.to_s
390
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:moped][:collect_backtraces]
391
+ rescue StandardError => e
392
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
393
+ ensure
394
+ return report_kvs
395
+ end
396
+
397
+ def drop_with_appoptics
398
+ return drop_without_appoptics unless AppOpticsAPM.tracing?
399
+
400
+ # We report :drop_collection here to be consistent
401
+ # with other mongo implementations
402
+ report_kvs = extract_trace_details(:drop_collection)
403
+
404
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
405
+ drop_without_appoptics
406
+ end
407
+ end
408
+
409
+ def find_with_appoptics(selector = {})
410
+ return find_without_appoptics(selector) unless AppOpticsAPM.tracing?
411
+
412
+ begin
413
+ report_kvs = extract_trace_details(:find)
414
+ report_kvs[:Query] = selector.empty? ? 'all' : selector.to_json
415
+ rescue StandardError => e
416
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
417
+ end
418
+
419
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
420
+ find_without_appoptics(selector)
421
+ end
422
+ end
423
+
424
+ def indexes_with_appoptics
425
+ return indexes_without_appoptics unless AppOpticsAPM.tracing?
426
+
427
+ report_kvs = extract_trace_details(:indexes)
428
+
429
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
430
+ indexes_without_appoptics
431
+ end
432
+ end
433
+
434
+ def insert_with_appoptics(documents, flags = nil)
435
+ if AppOpticsAPM.tracing? && !AppOpticsAPM.tracing_layer_op?(:create_index)
436
+ report_kvs = extract_trace_details(:insert)
437
+
438
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
439
+ insert_without_appoptics(documents, flags)
440
+ end
441
+ else
442
+ insert_without_appoptics(documents, flags)
443
+ end
444
+ end
445
+
446
+ def aggregate_with_appoptics(*pipeline)
447
+ return aggregate_without_appoptics(*pipeline) unless AppOpticsAPM.tracing?
448
+
449
+ report_kvs = extract_trace_details(:aggregate)
450
+ report_kvs[:Query] = pipeline
451
+
452
+ AppOpticsAPM::API.trace(:mongo, report_kvs) do
453
+ aggregate_without_appoptics(pipeline)
454
+ end
455
+ end
456
+ end
457
+ end
458
+ end
459
+
460
+ if defined?(Moped) && AppOpticsAPM::Config[:moped][:enabled]
461
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting moped' if AppOpticsAPM::Config[:verbose]
462
+ AppOpticsAPM::Util.send_include(Moped::Database, AppOpticsAPM::Inst::MopedDatabase)
463
+ AppOpticsAPM::Util.send_include(Moped::Collection, AppOpticsAPM::Inst::MopedCollection)
464
+ AppOpticsAPM::Util.send_include(Moped::Query, AppOpticsAPM::Inst::MopedQuery)
465
+ AppOpticsAPM::Util.send_include(Moped::Indexes, AppOpticsAPM::Inst::MopedIndexes)
466
+ end
@@ -0,0 +1,182 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'uri'
5
+ require 'cgi'
6
+
7
+ if AppOpticsAPM.loaded
8
+ module AppOpticsAPM
9
+ ##
10
+ # AppOpticsAPM::Rack
11
+ #
12
+ # The AppOpticsAPM::Rack middleware used to sample a subset of incoming
13
+ # requests for instrumentation and reporting. Tracing context can
14
+ # be received here (via the X-Trace HTTP header) or initiated here
15
+ # based on configured tracing mode.
16
+ #
17
+ # After the rack layer passes on to the following layers (Rails, Sinatra,
18
+ # Padrino, Grape), then the instrumentation downstream will
19
+ # automatically detect whether this is a sampled request or not
20
+ # and act accordingly.
21
+ #
22
+ class Rack
23
+ attr_reader :app
24
+
25
+ def initialize(app)
26
+ @app = app
27
+ end
28
+
29
+ def call(env)
30
+
31
+ # In the case of nested Ruby apps such as Grape inside of Rails
32
+ # or Grape inside of Grape, each app has it's own instance
33
+ # of rack middleware. We want to avoid tracing rack more than once
34
+ return @app.call(env) if AppOpticsAPM.tracing? && AppOpticsAPM.layer == :rack
35
+
36
+ incoming = AppOpticsAPM::Context.isValid
37
+ AppOpticsAPM.transaction_name = nil
38
+
39
+ url = env['PATH_INFO']
40
+ options = AppOpticsAPM::XTraceOptions.new(env['HTTP_X_TRACE_OPTIONS'], env['HTTP_X_TRACE_OPTIONS_SIGNATURE'])
41
+ xtrace = AppOpticsAPM::XTrace.valid?(env['HTTP_X_TRACE']) ? (env['HTTP_X_TRACE']) : nil
42
+ settings = AppOpticsAPM::TransactionSettings.new(url, xtrace, options)
43
+ profile_spans = AppOpticsAPM::Config['profiling'] == :enabled ? 1 : -1
44
+
45
+ response =
46
+ propagate_xtrace(env, settings, xtrace) do
47
+ sample(env, settings, options, profile_spans) do
48
+ AppOpticsAPM::Profiling.run do
49
+ AppOpticsAPM::TransactionMetrics.metrics(env, settings) do
50
+ @app.call(env)
51
+ end
52
+ end
53
+ end
54
+ end || [500, {}, nil]
55
+ options.add_response_header(response[1], settings)
56
+
57
+ AppOpticsAPM::Context.clear unless incoming
58
+ response
59
+ rescue
60
+ AppOpticsAPM::Context.clear unless incoming
61
+ raise
62
+ # can't use ensure for Context.clearing, because the Grape middleware
63
+ # needs the context in case of an error, it is somewhat convoluted ...
64
+ end
65
+
66
+ def self.noop?
67
+ false
68
+ end
69
+
70
+ private
71
+
72
+ def collect(env)
73
+ req = ::Rack::Request.new(env)
74
+ report_kvs = {}
75
+
76
+ begin
77
+ report_kvs[:'HTTP-Host'] = req.host
78
+ report_kvs[:Port] = req.port
79
+ report_kvs[:Proto] = req.scheme
80
+ report_kvs[:Method] = req.request_method
81
+ report_kvs[:AJAX] = true if req.xhr?
82
+ report_kvs[:ClientIP] = req.ip
83
+
84
+ if AppOpticsAPM::Config[:rack][:log_args]
85
+ report_kvs[:'Query-String'] = ::CGI.unescape(req.query_string) unless req.query_string.empty?
86
+ end
87
+
88
+ report_kvs[:URL] = AppOpticsAPM::Config[:rack][:log_args] ? ::CGI.unescape(req.fullpath) : ::CGI.unescape(req.path)
89
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:rack][:collect_backtraces]
90
+
91
+ # Report any request queue'ing headers. Report as 'Request-Start' or the summed Queue-Time
92
+ report_kvs[:'Request-Start'] = env['HTTP_X_REQUEST_START'] if env.key?('HTTP_X_REQUEST_START')
93
+ report_kvs[:'Request-Start'] = env['HTTP_X_QUEUE_START'] if env.key?('HTTP_X_QUEUE_START')
94
+ report_kvs[:'Queue-Time'] = env['HTTP_X_QUEUE_TIME'] if env.key?('HTTP_X_QUEUE_TIME')
95
+
96
+ report_kvs[:'Forwarded-For'] = env['HTTP_X_FORWARDED_FOR'] if env.key?('HTTP_X_FORWARDED_FOR')
97
+ report_kvs[:'Forwarded-Host'] = env['HTTP_X_FORWARDED_HOST'] if env.key?('HTTP_X_FORWARDED_HOST')
98
+ report_kvs[:'Forwarded-Proto'] = env['HTTP_X_FORWARDED_PROTO'] if env.key?('HTTP_X_FORWARDED_PROTO')
99
+ report_kvs[:'Forwarded-Port'] = env['HTTP_X_FORWARDED_PORT'] if env.key?('HTTP_X_FORWARDED_PORT')
100
+
101
+ report_kvs[:'Ruby.AppOptics.Version'] = AppOpticsAPM::Version::STRING
102
+ report_kvs[:ProcessID] = Process.pid
103
+ report_kvs[:ThreadID] = Thread.current.to_s[/0x\w*/]
104
+ rescue StandardError => e
105
+ # Discard any potential exceptions. Debug log and report whatever we can.
106
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] Rack KV collection error: #{e.inspect}"
107
+ end
108
+ report_kvs
109
+ end
110
+
111
+ def propagate_xtrace(env, settings, xtrace)
112
+ return yield unless settings.do_propagate
113
+
114
+ if xtrace
115
+ xtrace_local = xtrace.dup
116
+ AppOpticsAPM::XTrace.unset_sampled(xtrace_local) unless settings.do_sample
117
+ env['HTTP_X_TRACE'] = xtrace_local
118
+ end
119
+
120
+ status, headers, response = yield
121
+
122
+ headers ||= {}
123
+ headers['X-Trace'] = AppOpticsAPM::Context.toString if AppOpticsAPM::Context.isValid
124
+ headers['X-Trace'] ||= xtrace if xtrace
125
+ headers['X-Trace'] && AppOpticsAPM::XTrace.unset_sampled(headers['X-Trace']) unless settings.do_sample
126
+
127
+ [status, headers, response]
128
+ end
129
+
130
+ def sample(env, settings, options, profile_spans)
131
+ xtrace = env['HTTP_X_TRACE']
132
+ if settings.do_sample
133
+ begin
134
+ report_kvs = collect(env)
135
+ settings.add_kvs(report_kvs)
136
+ options&.add_kvs(report_kvs, settings)
137
+
138
+ AppOpticsAPM::API.log_start(:rack, xtrace, report_kvs, settings)
139
+
140
+ status, headers, response = yield
141
+
142
+ AppOpticsAPM::API.log_exit(:rack, { Status: status,
143
+ TransactionName: AppOpticsAPM.transaction_name,
144
+ ProfileSpans: profile_spans})
145
+
146
+ [status, headers, response]
147
+ rescue Exception => e
148
+ # it is ok to rescue Exception here because we are reraising it (we just need a chance to log_end)
149
+ AppOpticsAPM::API.log_exception(:rack, e)
150
+ AppOpticsAPM::API.log_exit(:rack, { Status: status,
151
+ TransactionName: AppOpticsAPM.transaction_name,
152
+ ProfileSpans: profile_spans
153
+ })
154
+ raise
155
+ end
156
+ else
157
+ AppOpticsAPM::API.create_nontracing_context(xtrace)
158
+ yield
159
+ end
160
+ end
161
+
162
+ end
163
+ end
164
+ else
165
+ module AppOpticsAPM
166
+ class Rack
167
+ attr_reader :app
168
+
169
+ def initialize(app)
170
+ @app = app
171
+ end
172
+
173
+ def call(env)
174
+ @app.call(env)
175
+ end
176
+
177
+ def self.noop?
178
+ true
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,35 @@
1
+ # Copyright (c) 2020 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module RackCacheContext
6
+
7
+ ###
8
+ # This adds a controller.action like transaction name for
9
+ # requests directly served from the cache without involving a controller.
10
+ # The resulting transaction name is `rack-cache.<cache-store>`,
11
+ # e.g. `rack-cache.memcached`
12
+ #
13
+ # It is not a full instrumentation, no span is added.
14
+ #
15
+ def call!(env)
16
+ metastore_type = begin
17
+ if options['rack-cache.metastore']
18
+ options['rack-cache.metastore'].match(/^([^\:]*)\:/)[1]
19
+ end || 'unknown_store'
20
+ rescue
21
+ 'unknown_store'
22
+ end
23
+
24
+ env['appoptics_apm.action'] = metastore_type
25
+ env['appoptics_apm.controller'] = 'rack-cache'
26
+
27
+ super
28
+ end
29
+ end
30
+ end
31
+
32
+ if AppOpticsAPM::Config[:rack_cache][:transaction_name] && defined?(Rack::Cache::Context)
33
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting rack_cache' if AppOpticsAPM::Config[:verbose]
34
+ Rack::Cache::Context.send(:prepend, ::AppOpticsAPM::RackCacheContext)
35
+ end