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.
- checksums.yaml +7 -0
- data/.dockerignore +5 -0
- data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
- data/.github/workflows/build_and_release_gem.yml +103 -0
- data/.github/workflows/build_for_packagecloud.yml +70 -0
- data/.github/workflows/docker-images.yml +47 -0
- data/.github/workflows/run_cpluplus_tests.yml +73 -0
- data/.github/workflows/run_tests.yml +168 -0
- data/.github/workflows/scripts/test_install.rb +23 -0
- data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
- data/.github/workflows/test_on_4_linux.yml +159 -0
- data/.gitignore +36 -0
- data/.rubocop.yml +29 -0
- data/.travis.yml +130 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +769 -0
- data/CONFIG.md +33 -0
- data/Gemfile +14 -0
- data/LICENSE +202 -0
- data/README.md +393 -0
- data/appoptics_apm.gemspec +70 -0
- data/bin/appoptics_apm_config +15 -0
- data/examples/prepend.rb +13 -0
- data/examples/sdk_examples.rb +158 -0
- data/ext/oboe_metal/README.md +69 -0
- data/ext/oboe_metal/extconf.rb +151 -0
- data/ext/oboe_metal/lib/.keep +0 -0
- data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
- data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
- data/ext/oboe_metal/noop/noop.c +8 -0
- data/ext/oboe_metal/src/README.md +6 -0
- data/ext/oboe_metal/src/VERSION +2 -0
- data/ext/oboe_metal/src/bson/bson.h +220 -0
- data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
- data/ext/oboe_metal/src/frames.cc +246 -0
- data/ext/oboe_metal/src/frames.h +40 -0
- data/ext/oboe_metal/src/init_appoptics_apm.cc +21 -0
- data/ext/oboe_metal/src/logging.cc +95 -0
- data/ext/oboe_metal/src/logging.h +35 -0
- data/ext/oboe_metal/src/oboe.h +1156 -0
- data/ext/oboe_metal/src/oboe_api.cpp +652 -0
- data/ext/oboe_metal/src/oboe_api.hpp +431 -0
- data/ext/oboe_metal/src/oboe_debug.h +59 -0
- data/ext/oboe_metal/src/oboe_swig_wrap.cc +7329 -0
- data/ext/oboe_metal/src/profiling.cc +435 -0
- data/ext/oboe_metal/src/profiling.h +78 -0
- data/ext/oboe_metal/test/CMakeLists.txt +53 -0
- data/ext/oboe_metal/test/FindGMock.cmake +43 -0
- data/ext/oboe_metal/test/README.md +56 -0
- data/ext/oboe_metal/test/frames_test.cc +164 -0
- data/ext/oboe_metal/test/profiling_test.cc +93 -0
- data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
- data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
- data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
- data/ext/oboe_metal/test/test.h +11 -0
- data/ext/oboe_metal/test/test_main.cc +32 -0
- data/init.rb +4 -0
- data/lib/appoptics_apm/api/layerinit.rb +41 -0
- data/lib/appoptics_apm/api/logging.rb +381 -0
- data/lib/appoptics_apm/api/memcache.rb +37 -0
- data/lib/appoptics_apm/api/metrics.rb +63 -0
- data/lib/appoptics_apm/api/tracing.rb +57 -0
- data/lib/appoptics_apm/api/util.rb +120 -0
- data/lib/appoptics_apm/api.rb +21 -0
- data/lib/appoptics_apm/base.rb +231 -0
- data/lib/appoptics_apm/config.rb +299 -0
- data/lib/appoptics_apm/frameworks/grape.rb +98 -0
- data/lib/appoptics_apm/frameworks/padrino.rb +78 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +104 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller6.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +88 -0
- data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +31 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +119 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +114 -0
- data/lib/appoptics_apm/frameworks/rails/inst/logger_formatters.rb +27 -0
- data/lib/appoptics_apm/frameworks/rails.rb +100 -0
- data/lib/appoptics_apm/frameworks/sinatra.rb +96 -0
- data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
- data/lib/appoptics_apm/inst/bunny-consumer.rb +89 -0
- data/lib/appoptics_apm/inst/curb.rb +332 -0
- data/lib/appoptics_apm/inst/dalli.rb +85 -0
- data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
- data/lib/appoptics_apm/inst/em-http-request.rb +101 -0
- data/lib/appoptics_apm/inst/excon.rb +125 -0
- data/lib/appoptics_apm/inst/faraday.rb +106 -0
- data/lib/appoptics_apm/inst/graphql.rb +240 -0
- data/lib/appoptics_apm/inst/grpc_client.rb +159 -0
- data/lib/appoptics_apm/inst/grpc_server.rb +120 -0
- data/lib/appoptics_apm/inst/http.rb +81 -0
- data/lib/appoptics_apm/inst/httpclient.rb +174 -0
- data/lib/appoptics_apm/inst/logger_formatter.rb +50 -0
- data/lib/appoptics_apm/inst/logging_log_event.rb +28 -0
- data/lib/appoptics_apm/inst/lumberjack_formatter.rb +13 -0
- data/lib/appoptics_apm/inst/memcached.rb +86 -0
- data/lib/appoptics_apm/inst/mongo.rb +246 -0
- data/lib/appoptics_apm/inst/mongo2.rb +225 -0
- data/lib/appoptics_apm/inst/moped.rb +466 -0
- data/lib/appoptics_apm/inst/rack.rb +182 -0
- data/lib/appoptics_apm/inst/rack_cache.rb +35 -0
- data/lib/appoptics_apm/inst/redis.rb +274 -0
- data/lib/appoptics_apm/inst/resque.rb +151 -0
- data/lib/appoptics_apm/inst/rest-client.rb +48 -0
- data/lib/appoptics_apm/inst/sequel.rb +178 -0
- data/lib/appoptics_apm/inst/sidekiq-client.rb +55 -0
- data/lib/appoptics_apm/inst/sidekiq-worker.rb +66 -0
- data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
- data/lib/appoptics_apm/inst/typhoeus.rb +108 -0
- data/lib/appoptics_apm/instrumentation.rb +22 -0
- data/lib/appoptics_apm/loading.rb +65 -0
- data/lib/appoptics_apm/logger.rb +14 -0
- data/lib/appoptics_apm/noop/README.md +9 -0
- data/lib/appoptics_apm/noop/context.rb +27 -0
- data/lib/appoptics_apm/noop/metadata.rb +25 -0
- data/lib/appoptics_apm/noop/profiling.rb +21 -0
- data/lib/appoptics_apm/oboe_init_options.rb +211 -0
- data/lib/appoptics_apm/ruby.rb +35 -0
- data/lib/appoptics_apm/sdk/current_trace.rb +77 -0
- data/lib/appoptics_apm/sdk/custom_metrics.rb +94 -0
- data/lib/appoptics_apm/sdk/logging.rb +37 -0
- data/lib/appoptics_apm/sdk/tracing.rb +434 -0
- data/lib/appoptics_apm/support/profiling.rb +18 -0
- data/lib/appoptics_apm/support/transaction_metrics.rb +67 -0
- data/lib/appoptics_apm/support/transaction_settings.rb +219 -0
- data/lib/appoptics_apm/support/x_trace_options.rb +110 -0
- data/lib/appoptics_apm/support_report.rb +119 -0
- data/lib/appoptics_apm/test.rb +95 -0
- data/lib/appoptics_apm/thread_local.rb +26 -0
- data/lib/appoptics_apm/util.rb +326 -0
- data/lib/appoptics_apm/version.rb +16 -0
- data/lib/appoptics_apm/xtrace.rb +115 -0
- data/lib/appoptics_apm.rb +77 -0
- data/lib/joboe_metal.rb +212 -0
- data/lib/oboe.rb +7 -0
- data/lib/oboe_metal.rb +172 -0
- data/lib/rails/generators/appoptics_apm/install_generator.rb +47 -0
- data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +425 -0
- data/log/.keep +0 -0
- data/yardoc_frontpage.md +26 -0
- metadata +231 -0
@@ -0,0 +1,274 @@
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
module AppOpticsAPM
|
5
|
+
module Inst
|
6
|
+
module Redis
|
7
|
+
module Client
|
8
|
+
# The operations listed in this constant skip collecting KVKey
|
9
|
+
NO_KEY_OPS = [:auth, :keys, :randomkey, :scan, :sdiff, :sdiffstore, :sinter,
|
10
|
+
:sinterstore, :smove, :sunion, :sunionstore, :zinterstore,
|
11
|
+
:zunionstore, :publish, :select, :eval, :evalsha, :script].freeze
|
12
|
+
|
13
|
+
# Instead of a giant switch statement, we use a hash constant to map out what
|
14
|
+
# KVs need to be collected for each of the many many Redis operations
|
15
|
+
# Hash formatting by undiagnosed OCD
|
16
|
+
KV_COLLECT_MAP = {
|
17
|
+
:brpoplpush => { :destination => 2 }, :rpoplpush => { :destination => 2 },
|
18
|
+
:sdiffstore => { :destination => 1 }, :sinterstore => { :destination => 1 },
|
19
|
+
:sunionstore => { :destination => 1 }, :zinterstore => { :destination => 1 },
|
20
|
+
:zunionstore => { :destination => 1 }, :publish => { :channel => 1 },
|
21
|
+
:incrby => { :increment => 2 }, :incrbyfloat => { :increment => 2 },
|
22
|
+
:pexpire => { :milliseconds => 2 }, :pexpireat => { :milliseconds => 2 },
|
23
|
+
:expireat => { :timestamp => 2 }, :decrby => { :decrement => 2 },
|
24
|
+
:psetex => { :ttl => 2 }, :restore => { :ttl => 2 },
|
25
|
+
:setex => { :ttl => 2 }, :setnx => { :ttl => 2 },
|
26
|
+
:move => { :db => 2 }, :select => { :db => 1 },
|
27
|
+
:lindex => { :index => 2 }, :getset => { :value => 2 },
|
28
|
+
:keys => { :pattern => 1 }, :expire => { :seconds => 2 },
|
29
|
+
:rename => { :newkey => 2 }, :renamenx => { :newkey => 2 },
|
30
|
+
:getbit => { :offset => 2 }, :setbit => { :offset => 2 },
|
31
|
+
:setrange => { :offset => 2 }, :evalsha => { :sha => 1 },
|
32
|
+
:getrange => { :start => 2, :end => 3 },
|
33
|
+
:zrange => { :start => 2, :end => 3 },
|
34
|
+
:bitcount => { :start => 2, :stop => 3 },
|
35
|
+
:lrange => { :start => 2, :stop => 3 },
|
36
|
+
:zrevrange => { :start => 2, :stop => 3 },
|
37
|
+
:hincrby => { :field => 2, :increment => 3 },
|
38
|
+
:smove => { :source => 1, :destination => 2 },
|
39
|
+
:bitop => { :operation => 1, :destkey => 2 },
|
40
|
+
:hincrbyfloat => { :field => 2, :increment => 3 },
|
41
|
+
:zremrangebyrank => { :start => 2, :stop => 3 }
|
42
|
+
}.freeze
|
43
|
+
|
44
|
+
# The following operations don't require any special handling. For these,
|
45
|
+
# we only collect KVKey and KVOp
|
46
|
+
#
|
47
|
+
# :append, :blpop, :brpop, :decr, :del, :dump, :exists,
|
48
|
+
# :hgetall, :hkeys, :hlen, :hvals, :hmset, :incr, :linsert,
|
49
|
+
# :llen, :lpop, :lpush, :lpushx, :lrem, :lset, :ltrim,
|
50
|
+
# :persist, :pttl, :hscan, :rpop, :rpush, :rpushx, :sadd,
|
51
|
+
# :scard, :sismember, :smembers, :strlen, :sort, :spop,
|
52
|
+
# :srandmember, :srem, :sscan, :ttl, :type, :zadd, :zcard,
|
53
|
+
# :zcount, :zincrby, :zrangebyscore, :zrank, :zrem,
|
54
|
+
# :zremrangebyscore, :zrevrank, :zrevrangebyscore, :zscore
|
55
|
+
#
|
56
|
+
# For the operations in NO_KEY_OPS (above) we only collect
|
57
|
+
# KVOp (no KVKey)
|
58
|
+
|
59
|
+
def self.included(klass)
|
60
|
+
# We wrap two of the Redis methods to instrument
|
61
|
+
# operations
|
62
|
+
AppOpticsAPM::Util.method_alias(klass, :call, ::Redis::Client)
|
63
|
+
AppOpticsAPM::Util.method_alias(klass, :call_pipeline, ::Redis::Client)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Given any Redis operation command array, this method
|
67
|
+
# extracts the Key/Values to report to the AppOptics
|
68
|
+
# dashboard.
|
69
|
+
#
|
70
|
+
# @param command [Array] the Redis operation array
|
71
|
+
# @param r [Return] the return value from the operation
|
72
|
+
# @return [Hash] the Key/Values to report
|
73
|
+
def extract_trace_details(command, r)
|
74
|
+
kvs = {}
|
75
|
+
op = command.first
|
76
|
+
|
77
|
+
kvs[:KVOp] = command[0]
|
78
|
+
kvs[:RemoteHost] = @options[:host]
|
79
|
+
unless NO_KEY_OPS.include?(op) || op == :del && command[1..-1].flatten.count > 1
|
80
|
+
if command[1].is_a?(Array)
|
81
|
+
kvs[:KVKey] = command[1].first
|
82
|
+
else
|
83
|
+
kvs[:KVKey] = command[1]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
if KV_COLLECT_MAP[op]
|
88
|
+
# Extract KVs from command for this op
|
89
|
+
KV_COLLECT_MAP[op].each { |k, v| kvs[k] = command[v] }
|
90
|
+
else
|
91
|
+
# This case statement handle special cases not handled
|
92
|
+
# by KV_COLLECT_MAP
|
93
|
+
case op
|
94
|
+
when :set
|
95
|
+
if command.count > 3
|
96
|
+
if command[3].is_a?(Hash)
|
97
|
+
options = command[3]
|
98
|
+
kvs[:ex] = options[:ex] if options.key?(:ex)
|
99
|
+
kvs[:px] = options[:px] if options.key?(:px)
|
100
|
+
kvs[:nx] = options[:nx] if options.key?(:nx)
|
101
|
+
kvs[:xx] = options[:xx] if options.key?(:xx)
|
102
|
+
else
|
103
|
+
options = command[3..-1]
|
104
|
+
until (opts = options.shift(2)).empty?
|
105
|
+
case opts[0]
|
106
|
+
when 'EX' then; kvs[:ex] = opts[1]
|
107
|
+
when 'PX' then; kvs[:px] = opts[1]
|
108
|
+
when 'NX' then; kvs[:nx] = opts[1]
|
109
|
+
when 'XX' then; kvs[:xx] = opts[1]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
when :get
|
116
|
+
kvs[:KVHit] = r.nil? ? 0 : 1
|
117
|
+
|
118
|
+
when :hdel, :hexists, :hget, :hset, :hsetnx
|
119
|
+
kvs[:field] = command[2] unless command[2].is_a?(Array)
|
120
|
+
if op == :hget
|
121
|
+
kvs[:KVHit] = r.nil? ? 0 : 1
|
122
|
+
end
|
123
|
+
|
124
|
+
when :eval
|
125
|
+
if command[1].length > 1024
|
126
|
+
kvs[:Script] = command[1][0..1023] + '(...snip...)'
|
127
|
+
else
|
128
|
+
kvs[:Script] = command[1]
|
129
|
+
end
|
130
|
+
|
131
|
+
when :script
|
132
|
+
kvs[:subcommand] = command[1]
|
133
|
+
kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:redis][:collect_backtraces]
|
134
|
+
if command[1] == 'load'
|
135
|
+
if command[1].length > 1024
|
136
|
+
kvs[:Script] = command[2][0..1023] + '(...snip...)'
|
137
|
+
else
|
138
|
+
kvs[:Script] = command[2]
|
139
|
+
end
|
140
|
+
elsif command[1] == :exists
|
141
|
+
if command[2].is_a?(Array)
|
142
|
+
kvs[:KVKey] = command[2].inspect
|
143
|
+
else
|
144
|
+
kvs[:KVKey] = command[2]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
when :mget
|
149
|
+
if command[1].is_a?(Array)
|
150
|
+
kvs[:KVKeyCount] = command[1].count
|
151
|
+
else
|
152
|
+
kvs[:KVKeyCount] = command.count - 1
|
153
|
+
end
|
154
|
+
values = r.select { |i| i }
|
155
|
+
kvs[:KVHitCount] = values.count
|
156
|
+
|
157
|
+
when :hmget
|
158
|
+
kvs[:KVKeyCount] = command.count - 2
|
159
|
+
values = r.select { |i| i }
|
160
|
+
kvs[:KVHitCount] = values.count
|
161
|
+
|
162
|
+
when :mset, :msetnx
|
163
|
+
if command[1].is_a?(Array)
|
164
|
+
kvs[:KVKeyCount] = command[1].count / 2
|
165
|
+
else
|
166
|
+
kvs[:KVKeyCount] = (command.count - 1) / 2
|
167
|
+
end
|
168
|
+
end # case op
|
169
|
+
end # if KV_COLLECT_MAP[op]
|
170
|
+
rescue StandardError => e
|
171
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/redis] Error collecting redis KVs: #{e.message}"
|
172
|
+
AppOpticsAPM.logger.debug e.backtrace.join('\n')
|
173
|
+
ensure
|
174
|
+
return kvs
|
175
|
+
end
|
176
|
+
|
177
|
+
# Extracts the Key/Values to report from a pipelined
|
178
|
+
# call to the AppOptics dashboard.
|
179
|
+
#
|
180
|
+
# @param pipeline [Redis::Pipeline] the Redis pipeline instance
|
181
|
+
# @return [Hash] the Key/Values to report
|
182
|
+
def extract_pipeline_details(pipeline)
|
183
|
+
kvs = {}
|
184
|
+
|
185
|
+
kvs[:RemoteHost] = @options[:host]
|
186
|
+
kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:redis][:collect_backtraces]
|
187
|
+
|
188
|
+
command_count = pipeline.commands.count
|
189
|
+
kvs[:KVOpCount] = command_count
|
190
|
+
|
191
|
+
kvs[:KVOp] = if pipeline.commands.first == :multi
|
192
|
+
:multi
|
193
|
+
else
|
194
|
+
:pipeline
|
195
|
+
end
|
196
|
+
|
197
|
+
# Report pipelined operations if the number
|
198
|
+
# of ops is reasonable
|
199
|
+
if command_count < 12
|
200
|
+
ops = []
|
201
|
+
pipeline.commands.each do |c|
|
202
|
+
ops << c.first
|
203
|
+
end
|
204
|
+
kvs[:KVOps] = ops.join(', ')
|
205
|
+
end
|
206
|
+
rescue StandardError => e
|
207
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug] Error extracting pipelined commands: #{e.message}"
|
208
|
+
AppOpticsAPM.logger.debug e.backtrace
|
209
|
+
ensure
|
210
|
+
return kvs
|
211
|
+
end
|
212
|
+
|
213
|
+
#
|
214
|
+
# The wrapper method for Redis::Client.call. Here
|
215
|
+
# (when tracing) we capture KVs to report and pass
|
216
|
+
# the call along
|
217
|
+
#
|
218
|
+
def call_with_appoptics(command, &block)
|
219
|
+
if AppOpticsAPM.tracing?
|
220
|
+
AppOpticsAPM::API.log_entry(:redis, {})
|
221
|
+
|
222
|
+
begin
|
223
|
+
r = call_without_appoptics(command, &block)
|
224
|
+
report_kvs = extract_trace_details(command, r)
|
225
|
+
r
|
226
|
+
rescue StandardError => e
|
227
|
+
AppOpticsAPM::API.log_exception(:redis, e)
|
228
|
+
raise
|
229
|
+
ensure
|
230
|
+
AppOpticsAPM::API.log_exit(:redis, report_kvs)
|
231
|
+
end
|
232
|
+
|
233
|
+
else
|
234
|
+
call_without_appoptics(command, &block)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
#
|
239
|
+
# The wrapper method for Redis::Client.call_pipeline. Here
|
240
|
+
# (when tracing) we capture KVs to report and pass the call along
|
241
|
+
#
|
242
|
+
def call_pipeline_with_appoptics(pipeline)
|
243
|
+
if AppOpticsAPM.tracing?
|
244
|
+
# Fall back to the raw tracing API so we can pass KVs
|
245
|
+
# back on exit (a limitation of the AppOpticsAPM::API.trace
|
246
|
+
# block method) This removes the need for an info
|
247
|
+
# event to send additonal KVs
|
248
|
+
AppOpticsAPM::API.log_entry(:redis, {})
|
249
|
+
|
250
|
+
report_kvs = extract_pipeline_details(pipeline)
|
251
|
+
|
252
|
+
begin
|
253
|
+
call_pipeline_without_appoptics(pipeline)
|
254
|
+
rescue StandardError => e
|
255
|
+
AppOpticsAPM::API.log_exception(:redis, e)
|
256
|
+
raise
|
257
|
+
ensure
|
258
|
+
AppOpticsAPM::API.log_exit(:redis, report_kvs)
|
259
|
+
end
|
260
|
+
else
|
261
|
+
call_pipeline_without_appoptics(pipeline)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
if AppOpticsAPM::Config[:redis][:enabled]
|
270
|
+
if defined?(Redis) && Gem::Version.new(Redis::VERSION) >= Gem::Version.new('3.0.0')
|
271
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting redis' if AppOpticsAPM::Config[:verbose]
|
272
|
+
AppOpticsAPM::Util.send_include(Redis::Client, AppOpticsAPM::Inst::Redis::Client)
|
273
|
+
end
|
274
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
require 'socket'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module AppOpticsAPM
|
8
|
+
module Inst
|
9
|
+
module ResqueClient
|
10
|
+
def self.included(klass)
|
11
|
+
klass.send :extend, ::Resque
|
12
|
+
AppOpticsAPM::Util.method_alias(klass, :enqueue, ::Resque)
|
13
|
+
AppOpticsAPM::Util.method_alias(klass, :enqueue_to, ::Resque)
|
14
|
+
AppOpticsAPM::Util.method_alias(klass, :dequeue, ::Resque)
|
15
|
+
end
|
16
|
+
|
17
|
+
def extract_trace_details(op, klass, args)
|
18
|
+
report_kvs = {}
|
19
|
+
|
20
|
+
begin
|
21
|
+
report_kvs[:Spec] = :pushq
|
22
|
+
report_kvs[:Flavor] = :resque
|
23
|
+
report_kvs[:JobName] = klass.to_s
|
24
|
+
|
25
|
+
if AppOpticsAPM::Config[:resqueclient][:log_args]
|
26
|
+
kv_args = args.to_json
|
27
|
+
|
28
|
+
# Limit the argument json string to 1024 bytes
|
29
|
+
if kv_args.length > 1024
|
30
|
+
report_kvs[:Args] = kv_args[0..1023] + '...[snipped]'
|
31
|
+
else
|
32
|
+
report_kvs[:Args] = kv_args
|
33
|
+
end
|
34
|
+
end
|
35
|
+
report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:resqueclient][:collect_backtraces]
|
36
|
+
report_kvs[:Queue] = klass.instance_variable_get(:@queue)
|
37
|
+
rescue => e
|
38
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
|
39
|
+
end
|
40
|
+
|
41
|
+
report_kvs
|
42
|
+
end
|
43
|
+
|
44
|
+
def enqueue_with_appoptics(klass, *args)
|
45
|
+
if AppOpticsAPM.tracing?
|
46
|
+
report_kvs = extract_trace_details(:enqueue, klass, args)
|
47
|
+
|
48
|
+
AppOpticsAPM::API.trace(:'resque-client', report_kvs, :enqueue) do
|
49
|
+
enqueue_without_appoptics(klass, *args)
|
50
|
+
end
|
51
|
+
else
|
52
|
+
enqueue_without_appoptics(klass, *args)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def enqueue_to_with_appoptics(queue, klass, *args)
|
57
|
+
if AppOpticsAPM.tracing? && !AppOpticsAPM.tracing_layer_op?(:enqueue)
|
58
|
+
report_kvs = extract_trace_details(:enqueue_to, klass, args)
|
59
|
+
report_kvs[:Queue] = queue.to_s if queue
|
60
|
+
|
61
|
+
AppOpticsAPM::API.trace(:'resque-client', report_kvs) do
|
62
|
+
enqueue_to_without_appoptics(queue, klass, *args)
|
63
|
+
end
|
64
|
+
else
|
65
|
+
enqueue_to_without_appoptics(queue, klass, *args)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def dequeue_with_appoptics(klass, *args)
|
70
|
+
if AppOpticsAPM.tracing?
|
71
|
+
report_kvs = extract_trace_details(:dequeue, klass, args)
|
72
|
+
|
73
|
+
AppOpticsAPM::API.trace(:'resque-client', report_kvs) do
|
74
|
+
dequeue_without_appoptics(klass, *args)
|
75
|
+
end
|
76
|
+
else
|
77
|
+
dequeue_without_appoptics(klass, *args)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module ResqueWorker
|
83
|
+
def self.included(klass)
|
84
|
+
AppOpticsAPM::Util.method_alias(klass, :perform, ::Resque::Worker)
|
85
|
+
end
|
86
|
+
|
87
|
+
def perform_with_appoptics(job)
|
88
|
+
report_kvs = {}
|
89
|
+
|
90
|
+
begin
|
91
|
+
report_kvs[:Spec] = :job
|
92
|
+
report_kvs[:Flavor] = :resque
|
93
|
+
report_kvs[:JobName] = job.payload['class'].to_s
|
94
|
+
report_kvs[:Queue] = job.queue
|
95
|
+
|
96
|
+
# Set these keys for the ability to separate out
|
97
|
+
# background tasks into a separate app on the server-side UI
|
98
|
+
|
99
|
+
report_kvs[:'HTTP-Host'] = Socket.gethostname
|
100
|
+
report_kvs[:Controller] = "Resque_#{job.queue}"
|
101
|
+
report_kvs[:Action] = job.payload['class'].to_s
|
102
|
+
report_kvs[:URL] = "/resque/#{job.queue}/#{job.payload['class']}"
|
103
|
+
|
104
|
+
if AppOpticsAPM::Config[:resqueworker][:log_args]
|
105
|
+
kv_args = job.payload['args'].to_json
|
106
|
+
|
107
|
+
# Limit the argument json string to 1024 bytes
|
108
|
+
if kv_args.length > 1024
|
109
|
+
report_kvs[:Args] = kv_args[0..1023] + '...[snipped]'
|
110
|
+
else
|
111
|
+
report_kvs[:Args] = kv_args
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:resqueworker][:collect_backtraces]
|
116
|
+
rescue => e
|
117
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
|
118
|
+
end
|
119
|
+
|
120
|
+
AppOpticsAPM::SDK.start_trace(:'resque-worker', nil, report_kvs) do
|
121
|
+
perform_without_appoptics(job)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
module ResqueJob
|
127
|
+
def self.included(klass)
|
128
|
+
AppOpticsAPM::Util.method_alias(klass, :fail, ::Resque::Job)
|
129
|
+
end
|
130
|
+
|
131
|
+
def fail_with_appoptics(exception)
|
132
|
+
if AppOpticsAPM.tracing?
|
133
|
+
AppOpticsAPM::API.log_exception(:resque, exception)
|
134
|
+
end
|
135
|
+
fail_without_appoptics(exception)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
if defined?(Resque)
|
142
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting resque' if AppOpticsAPM::Config[:verbose]
|
143
|
+
|
144
|
+
AppOpticsAPM::Util.send_include(Resque, AppOpticsAPM::Inst::ResqueClient) if AppOpticsAPM::Config[:resqueclient][:enabled]
|
145
|
+
AppOpticsAPM::Util.send_include(Resque::Worker, AppOpticsAPM::Inst::ResqueWorker) if AppOpticsAPM::Config[:resqueworker][:enabled]
|
146
|
+
if AppOpticsAPM::Config[:resqueclient][:enabled] || AppOpticsAPM::Config[:resqueworker][:enabled]
|
147
|
+
AppOpticsAPM::Util.send_include(Resque::Job, AppOpticsAPM::Inst::ResqueJob)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
module AppOpticsAPM
|
5
|
+
module Inst
|
6
|
+
module RestClientRequest
|
7
|
+
def self.included(klass)
|
8
|
+
AppOpticsAPM::Util.method_alias(klass, :execute, ::RestClient::Request)
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# execute_with_appoptics
|
13
|
+
#
|
14
|
+
# The wrapper method for RestClient::Request.execute
|
15
|
+
#
|
16
|
+
def execute_with_appoptics(&block)
|
17
|
+
blacklisted = AppOpticsAPM::API.blacklisted?(url)
|
18
|
+
|
19
|
+
unless AppOpticsAPM.tracing?
|
20
|
+
xtrace = AppOpticsAPM::Context.toString
|
21
|
+
@processed_headers['X-Trace'] = AppOpticsAPM::Context.toString if AppOpticsAPM::XTrace.valid?(xtrace) && !blacklisted
|
22
|
+
return execute_without_appoptics(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
kvs = {}
|
27
|
+
kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:rest_client][:collect_backtraces]
|
28
|
+
AppOpticsAPM::API.log_entry('rest-client', kvs)
|
29
|
+
|
30
|
+
@processed_headers['X-Trace'] = AppOpticsAPM::Context.toString unless blacklisted
|
31
|
+
|
32
|
+
# The core rest-client call
|
33
|
+
execute_without_appoptics(&block)
|
34
|
+
rescue => e
|
35
|
+
AppOpticsAPM::API.log_exception('rest-client', e)
|
36
|
+
raise e
|
37
|
+
ensure
|
38
|
+
AppOpticsAPM::API.log_exit('rest-client')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
if defined?(RestClient) && AppOpticsAPM::Config[:rest_client][:enabled]
|
46
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting rest-client' if AppOpticsAPM::Config[:verbose]
|
47
|
+
AppOpticsAPM::Util.send_include(RestClient::Request, AppOpticsAPM::Inst::RestClientRequest)
|
48
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
module AppOpticsAPM
|
5
|
+
module Inst
|
6
|
+
##
|
7
|
+
# AppOpticsAPM::Inst::Sequel
|
8
|
+
#
|
9
|
+
# The common (shared) methods used by the AppOpticsAPM Sequel instrumentation
|
10
|
+
# across multiple modules/classes.
|
11
|
+
#
|
12
|
+
module Sequel
|
13
|
+
##
|
14
|
+
# extract_trace_details
|
15
|
+
#
|
16
|
+
# Given SQL and the options hash, this method extracts the interesting
|
17
|
+
# bits for reporting to the AppOptics dashboard.
|
18
|
+
#
|
19
|
+
def extract_trace_details(sql, opts)
|
20
|
+
kvs = {}
|
21
|
+
|
22
|
+
if !sql.is_a?(String)
|
23
|
+
kvs[:IsPreparedStatement] = true
|
24
|
+
end
|
25
|
+
|
26
|
+
if ::Sequel::VERSION > '4.36.0' && !sql.is_a?(String)
|
27
|
+
# In 4.37.0, sql was converted to a prepared statement object
|
28
|
+
sql = sql.prepared_sql unless sql.is_a?(Symbol)
|
29
|
+
end
|
30
|
+
|
31
|
+
if AppOpticsAPM::Config[:sanitize_sql]
|
32
|
+
# Sanitize SQL and don't report binds
|
33
|
+
if sql.is_a?(Symbol)
|
34
|
+
kvs[:Query] = sql
|
35
|
+
else
|
36
|
+
kvs[:Query] = AppOpticsAPM::Util.sanitize_sql(sql)
|
37
|
+
end
|
38
|
+
else
|
39
|
+
# Report raw SQL and any binds if they exist
|
40
|
+
kvs[:Query] = sql.to_s
|
41
|
+
kvs[:QueryArgs] = opts[:arguments] if opts.is_a?(Hash) && opts.key?(:arguments)
|
42
|
+
end
|
43
|
+
|
44
|
+
kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:sequel][:collect_backtraces]
|
45
|
+
|
46
|
+
if ::Sequel::VERSION < '3.41.0' && !(self.class.to_s =~ /Dataset$/)
|
47
|
+
db_opts = @opts
|
48
|
+
elsif @pool
|
49
|
+
db_opts = @pool.db.opts
|
50
|
+
else
|
51
|
+
db_opts = @db.opts
|
52
|
+
end
|
53
|
+
|
54
|
+
kvs[:Database] = db_opts[:database]
|
55
|
+
kvs[:RemoteHost] = db_opts[:host]
|
56
|
+
kvs[:RemotePort] = db_opts[:port] if db_opts.key?(:port)
|
57
|
+
kvs[:Flavor] = db_opts[:adapter]
|
58
|
+
rescue => e
|
59
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug Error capturing Sequel KVs: #{e.message}" if AppOpticsAPM::Config[:verbose]
|
60
|
+
ensure
|
61
|
+
return kvs
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# exec_with_appoptics
|
66
|
+
#
|
67
|
+
# This method wraps and routes the call to the specified
|
68
|
+
# original method call
|
69
|
+
#
|
70
|
+
def exec_with_appoptics(method, sql, opts = ::Sequel::OPTS, &block)
|
71
|
+
if AppOpticsAPM.tracing?
|
72
|
+
kvs = extract_trace_details(sql, opts)
|
73
|
+
AppOpticsAPM::API.log_entry(:sequel, kvs)
|
74
|
+
end
|
75
|
+
|
76
|
+
send(method, sql, opts, &block)
|
77
|
+
rescue => e
|
78
|
+
AppOpticsAPM::API.log_exception(:sequel, e)
|
79
|
+
raise e
|
80
|
+
ensure
|
81
|
+
AppOpticsAPM::API.log_exit(:sequel)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
module SequelDatabase
|
86
|
+
include AppOpticsAPM::Inst::Sequel
|
87
|
+
|
88
|
+
def self.included(klass)
|
89
|
+
AppOpticsAPM::Util.method_alias(klass, :run, ::Sequel::Database)
|
90
|
+
AppOpticsAPM::Util.method_alias(klass, :execute_ddl, ::Sequel::Database)
|
91
|
+
AppOpticsAPM::Util.method_alias(klass, :execute_dui, ::Sequel::Database)
|
92
|
+
AppOpticsAPM::Util.method_alias(klass, :execute_insert, ::Sequel::Database)
|
93
|
+
end
|
94
|
+
|
95
|
+
def run_with_appoptics(sql, opts = ::Sequel::OPTS)
|
96
|
+
if AppOpticsAPM.tracing?
|
97
|
+
kvs = extract_trace_details(sql, opts)
|
98
|
+
AppOpticsAPM::API.log_entry(:sequel, kvs)
|
99
|
+
end
|
100
|
+
|
101
|
+
run_without_appoptics(sql, opts)
|
102
|
+
rescue => e
|
103
|
+
AppOpticsAPM::API.log_exception(:sequel, e)
|
104
|
+
raise e
|
105
|
+
ensure
|
106
|
+
AppOpticsAPM::API.log_exit(:sequel)
|
107
|
+
end
|
108
|
+
|
109
|
+
def execute_ddl_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
|
110
|
+
# If we're already tracing a sequel operation, then this call likely came
|
111
|
+
# from Sequel::Dataset. In this case, just pass it on.
|
112
|
+
return execute_ddl_without_appoptics(sql, opts, &block) if AppOpticsAPM.tracing_layer?(:sequel)
|
113
|
+
|
114
|
+
exec_with_appoptics(:execute_ddl_without_appoptics, sql, opts, &block)
|
115
|
+
end
|
116
|
+
|
117
|
+
def execute_dui_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
|
118
|
+
# If we're already tracing a sequel operation, then this call likely came
|
119
|
+
# from Sequel::Dataset. In this case, just pass it on.
|
120
|
+
return execute_dui_without_appoptics(sql, opts, &block) if AppOpticsAPM.tracing_layer?(:sequel)
|
121
|
+
|
122
|
+
exec_with_appoptics(:execute_dui_without_appoptics, sql, opts, &block)
|
123
|
+
end
|
124
|
+
|
125
|
+
def execute_insert_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
|
126
|
+
# If we're already tracing a sequel operation, then this call likely came
|
127
|
+
# from Sequel::Dataset. In this case, just pass it on.
|
128
|
+
return execute_insert_without_appoptics(sql, opts, &block) if AppOpticsAPM.tracing_layer?(:sequel)
|
129
|
+
|
130
|
+
exec_with_appoptics(:execute_insert_without_appoptics, sql, opts, &block)
|
131
|
+
end
|
132
|
+
end # module SequelDatabase
|
133
|
+
|
134
|
+
module SequelDataset
|
135
|
+
include AppOpticsAPM::Inst::Sequel
|
136
|
+
|
137
|
+
def self.included(klass)
|
138
|
+
AppOpticsAPM::Util.method_alias(klass, :execute, ::Sequel::Dataset)
|
139
|
+
AppOpticsAPM::Util.method_alias(klass, :execute_ddl, ::Sequel::Dataset)
|
140
|
+
AppOpticsAPM::Util.method_alias(klass, :execute_dui, ::Sequel::Dataset)
|
141
|
+
AppOpticsAPM::Util.method_alias(klass, :execute_insert, ::Sequel::Dataset)
|
142
|
+
end
|
143
|
+
|
144
|
+
def execute_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
|
145
|
+
exec_with_appoptics(:execute_without_appoptics, sql, opts, &block)
|
146
|
+
end
|
147
|
+
|
148
|
+
def execute_ddl_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
|
149
|
+
exec_with_appoptics(:execute_ddl_without_appoptics, sql, opts, &block)
|
150
|
+
end
|
151
|
+
|
152
|
+
def execute_dui_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
|
153
|
+
exec_with_appoptics(:execute_dui_without_appoptics, sql, opts, &block)
|
154
|
+
end
|
155
|
+
|
156
|
+
def execute_insert_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
|
157
|
+
exec_with_appoptics(:execute_insert_without_appoptics, sql, opts, &block)
|
158
|
+
end
|
159
|
+
|
160
|
+
end # module SequelDataset
|
161
|
+
end # module Inst
|
162
|
+
end # module AppOpticsAPM
|
163
|
+
|
164
|
+
if AppOpticsAPM::Config[:sequel][:enabled]
|
165
|
+
if defined?(::Sequel) && ::Sequel::VERSION < '4.0.0'
|
166
|
+
# For versions before 4.0.0, Sequel::OPTS wasn't defined.
|
167
|
+
# Define it as an empty hash for backwards compatibility.
|
168
|
+
module ::Sequel
|
169
|
+
OPTS = {}
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
if defined?(::Sequel)
|
174
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting sequel' if AppOpticsAPM::Config[:verbose]
|
175
|
+
AppOpticsAPM::Util.send_include(::Sequel::Database, AppOpticsAPM::Inst::SequelDatabase)
|
176
|
+
AppOpticsAPM::Util.send_include(::Sequel::Dataset, AppOpticsAPM::Inst::SequelDataset)
|
177
|
+
end
|
178
|
+
end
|