appoptics_apm_mnfst 4.5.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.
- checksums.yaml +7 -0
- data/.dockerignore +5 -0
- data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
- data/.gitignore +29 -0
- data/.rubocop.yml +8 -0
- data/.travis.yml +121 -0
- data/.yardopts +4 -0
- data/CHANGELOG.md +769 -0
- data/CONFIG.md +33 -0
- data/Gemfile +29 -0
- data/LICENSE +193 -0
- data/README.md +393 -0
- data/Rakefile +230 -0
- data/appoptics_apm.gemspec +61 -0
- data/bin/appoptics_apm_config +15 -0
- data/build_gem.sh +15 -0
- data/build_gem_upload_to_packagecloud.sh +20 -0
- data/examples/SDK/01_basic_tracing.rb +67 -0
- data/examples/carrying_context.rb +220 -0
- data/ext/oboe_metal/extconf.rb +114 -0
- data/ext/oboe_metal/lib/.keep +0 -0
- data/ext/oboe_metal/noop/noop.c +7 -0
- data/ext/oboe_metal/src/VERSION +1 -0
- data/init.rb +4 -0
- data/lib/appoptics_apm.rb +76 -0
- data/lib/appoptics_apm/api.rb +20 -0
- data/lib/appoptics_apm/api/layerinit.rb +41 -0
- data/lib/appoptics_apm/api/logging.rb +375 -0
- data/lib/appoptics_apm/api/memcache.rb +37 -0
- data/lib/appoptics_apm/api/metrics.rb +55 -0
- data/lib/appoptics_apm/api/profiling.rb +203 -0
- data/lib/appoptics_apm/api/tracing.rb +53 -0
- data/lib/appoptics_apm/api/util.rb +122 -0
- data/lib/appoptics_apm/base.rb +230 -0
- data/lib/appoptics_apm/config.rb +254 -0
- data/lib/appoptics_apm/frameworks/grape.rb +97 -0
- data/lib/appoptics_apm/frameworks/padrino.rb +108 -0
- data/lib/appoptics_apm/frameworks/rails.rb +94 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +104 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +55 -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_controller_api.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +58 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +50 -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 +108 -0
- data/lib/appoptics_apm/frameworks/sinatra.rb +125 -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 +330 -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 +94 -0
- data/lib/appoptics_apm/inst/grpc_client.rb +162 -0
- data/lib/appoptics_apm/inst/grpc_server.rb +120 -0
- data/lib/appoptics_apm/inst/http.rb +73 -0
- data/lib/appoptics_apm/inst/httpclient.rb +174 -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 +199 -0
- data/lib/appoptics_apm/inst/redis.rb +275 -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 +65 -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/legacy_method_profiling.rb +90 -0
- data/lib/appoptics_apm/loading.rb +65 -0
- data/lib/appoptics_apm/logger.rb +42 -0
- data/lib/appoptics_apm/method_profiling.rb +33 -0
- data/lib/appoptics_apm/noop/README.md +9 -0
- data/lib/appoptics_apm/noop/context.rb +26 -0
- data/lib/appoptics_apm/noop/metadata.rb +22 -0
- data/lib/appoptics_apm/ruby.rb +35 -0
- data/lib/appoptics_apm/sdk/custom_metrics.rb +92 -0
- data/lib/appoptics_apm/sdk/tracing.rb +315 -0
- data/lib/appoptics_apm/support.rb +119 -0
- data/lib/appoptics_apm/test.rb +94 -0
- data/lib/appoptics_apm/thread_local.rb +26 -0
- data/lib/appoptics_apm/util.rb +319 -0
- data/lib/appoptics_apm/version.rb +15 -0
- data/lib/appoptics_apm/xtrace.rb +103 -0
- data/lib/joboe_metal.rb +212 -0
- data/lib/oboe.rb +7 -0
- data/lib/oboe/README +2 -0
- data/lib/oboe/backward_compatibility.rb +80 -0
- data/lib/oboe/inst/rack.rb +11 -0
- data/lib/oboe_metal.rb +198 -0
- data/lib/rails/generators/appoptics_apm/install_generator.rb +45 -0
- data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +265 -0
- data/yardoc_frontpage.md +26 -0
- metadata +266 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
#++
|
|
5
|
+
|
|
6
|
+
# TODO remove Memcache from API and into some Util module to be included in Modules that need
|
|
7
|
+
# ____ these methods
|
|
8
|
+
module AppOpticsAPM
|
|
9
|
+
module API
|
|
10
|
+
##
|
|
11
|
+
# Utility methods for the Memcache instrumentation
|
|
12
|
+
# currently used by dalli and memcached
|
|
13
|
+
module Memcache #:nodoc:
|
|
14
|
+
MEMCACHE_OPS = %w(add append cas decr decrement delete fetch get incr increment prepend replace set)
|
|
15
|
+
|
|
16
|
+
def memcache_hit?(result)
|
|
17
|
+
result.nil? ? 0 : 1
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def remote_host(key)
|
|
21
|
+
return unless defined?(Lib.memcached_server_by_key) &&
|
|
22
|
+
defined?(@struct) && defined?(is_unix_socket?)
|
|
23
|
+
|
|
24
|
+
server_as_array = Lib.memcached_server_by_key(@struct, key.to_s)
|
|
25
|
+
|
|
26
|
+
return unless server_as_array.is_a?(Array)
|
|
27
|
+
|
|
28
|
+
server = server_as_array.first
|
|
29
|
+
if is_unix_socket?(server)
|
|
30
|
+
'localhost'
|
|
31
|
+
elsif defined?(server.hostname)
|
|
32
|
+
server.hostname
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module AppOpticsAPM
|
|
2
|
+
module API
|
|
3
|
+
module Metrics
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# Internal: method to send duration for a transaction
|
|
7
|
+
# it checks if it can send metrics with the current transaction name
|
|
8
|
+
# or a default transaction name and sets the transaction name accordingly
|
|
9
|
+
#
|
|
10
|
+
# === Arguments:
|
|
11
|
+
#
|
|
12
|
+
# * +span+ the name of the current span (used to construct a transaction name if none is defined)
|
|
13
|
+
# * +kvs+ A hash containing key/value pairs, only the value of :TransactionName will be relevant
|
|
14
|
+
#
|
|
15
|
+
# === Returns:
|
|
16
|
+
# The result of the block.
|
|
17
|
+
#
|
|
18
|
+
# === Assigns:
|
|
19
|
+
# The transaction_name to kvs[:TransactionName]
|
|
20
|
+
|
|
21
|
+
def send_metrics(span, kvs)
|
|
22
|
+
start = Time.now
|
|
23
|
+
yield
|
|
24
|
+
ensure
|
|
25
|
+
duration = (1000 * 1000 * (Time.now - start)).to_i
|
|
26
|
+
transaction_name = determine_transaction_name(span, kvs)
|
|
27
|
+
kvs[:TransactionName] = AppOpticsAPM::Span.createSpan(transaction_name, nil, duration)
|
|
28
|
+
AppOpticsAPM.transaction_name = nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# Determine the transaction name to be set on the trace.
|
|
35
|
+
#
|
|
36
|
+
# === Argument:
|
|
37
|
+
# * +span+ the name of the current span (used to construct a transaction name if none is defined)
|
|
38
|
+
# * +kvs+ (hash, optional) the hash that may have values for 'Controller' and 'Action'
|
|
39
|
+
#
|
|
40
|
+
# === Returns:
|
|
41
|
+
# (string) the determined transaction name
|
|
42
|
+
#
|
|
43
|
+
def determine_transaction_name(span, kvs = {})
|
|
44
|
+
if AppOpticsAPM.transaction_name
|
|
45
|
+
AppOpticsAPM.transaction_name
|
|
46
|
+
elsif kvs['Controller'] && kvs['Action']
|
|
47
|
+
[kvs['Controller'], kvs['Action']].join('.')
|
|
48
|
+
else
|
|
49
|
+
"custom-#{span}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
#++
|
|
5
|
+
|
|
6
|
+
module AppOpticsAPM
|
|
7
|
+
module API
|
|
8
|
+
##
|
|
9
|
+
# Module to create profiling traces for blocks of code or methods
|
|
10
|
+
module Profiling
|
|
11
|
+
##
|
|
12
|
+
# Public: Profile a given block of code. Detect any exceptions thrown by
|
|
13
|
+
# the block and report errors.
|
|
14
|
+
#
|
|
15
|
+
# ==== Arguments
|
|
16
|
+
#
|
|
17
|
+
# * +profile_name+ - A name used to identify the block being profiled.
|
|
18
|
+
# * +report_kvs+ - A hash containing key/value pairs that will be reported along
|
|
19
|
+
# with the event of this profile (optional).
|
|
20
|
+
# * +with_backtrace+ - Boolean to indicate whether a backtrace should
|
|
21
|
+
# be collected with this trace event.
|
|
22
|
+
#
|
|
23
|
+
# ==== Example
|
|
24
|
+
#
|
|
25
|
+
# def computation(n)
|
|
26
|
+
# AppOpticsAPM::API.profile('fib', { :n => n }) do
|
|
27
|
+
# fib(n)
|
|
28
|
+
# end
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# Returns the result of the block.
|
|
32
|
+
#
|
|
33
|
+
|
|
34
|
+
def profile(profile_name, report_kvs = {}, with_backtrace = false)
|
|
35
|
+
return yield unless AppOpticsAPM.tracing?
|
|
36
|
+
|
|
37
|
+
begin
|
|
38
|
+
report_kvs[:Language] ||= :ruby
|
|
39
|
+
report_kvs[:ProfileName] ||= profile_name
|
|
40
|
+
report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if with_backtrace
|
|
41
|
+
|
|
42
|
+
AppOpticsAPM::API.log(nil, :profile_entry, report_kvs)
|
|
43
|
+
|
|
44
|
+
begin
|
|
45
|
+
yield
|
|
46
|
+
rescue => e
|
|
47
|
+
log_exception(nil, e)
|
|
48
|
+
raise
|
|
49
|
+
ensure
|
|
50
|
+
exit_kvs = {}
|
|
51
|
+
exit_kvs[:Language] = :ruby
|
|
52
|
+
exit_kvs[:ProfileName] = report_kvs[:ProfileName]
|
|
53
|
+
|
|
54
|
+
AppOpticsAPM::API.log(nil, :profile_exit, exit_kvs)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
##
|
|
60
|
+
# Public: Add profiling to a method on a class or module. That method can be of any (accessible)
|
|
61
|
+
# type (instance, singleton, private, protected etc.).
|
|
62
|
+
#
|
|
63
|
+
# ==== Arguments
|
|
64
|
+
#
|
|
65
|
+
# * +klass+ - the class or module that has the method to profile
|
|
66
|
+
# * +method+ - the method to profile. Can be singleton, instance, private etc...
|
|
67
|
+
# * +opts+ - a hash specifying the one or more of the following options:
|
|
68
|
+
# * +:arguments+ - report the arguments passed to <tt>method</tt> on each profile (default: false)
|
|
69
|
+
# * +:result+ - report the return value of <tt>method</tt> on each profile (default: false)
|
|
70
|
+
# * +:backtrace+ - report the return value of <tt>method</tt> on each profile (default: false)
|
|
71
|
+
# * +:name+ - alternate name for the profile reported in the dashboard (default: method name)
|
|
72
|
+
# * +extra_kvs+ - a hash containing any additional key/value pairs you would like reported with the profile
|
|
73
|
+
#
|
|
74
|
+
# ==== Example
|
|
75
|
+
#
|
|
76
|
+
# opts = {}
|
|
77
|
+
# opts[:backtrace] = true
|
|
78
|
+
# opts[:arguments] = false
|
|
79
|
+
# opts[:name] = :array_sort
|
|
80
|
+
#
|
|
81
|
+
# AppOpticsAPM::API.profile_method(Array, :sort, opts)
|
|
82
|
+
#
|
|
83
|
+
def profile_method(klass, method, opts = {}, extra_kvs = {})
|
|
84
|
+
# If we're on an unsupported platform (ahem Mac), just act
|
|
85
|
+
# like we did something to nicely play the no-op part.
|
|
86
|
+
return true unless AppOpticsAPM.loaded
|
|
87
|
+
|
|
88
|
+
if !klass.is_a?(Module)
|
|
89
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/error] profile_method: Not sure what to do with #{klass}. Send a class or module."
|
|
90
|
+
return false
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
if method.is_a?(String)
|
|
94
|
+
method = method.to_sym
|
|
95
|
+
elsif !method.is_a?(Symbol)
|
|
96
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/error] profile_method: Not sure what to do with #{method}. Send a string or symbol for method."
|
|
97
|
+
return false
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
instance_method = klass.instance_methods.include?(method) || klass.private_instance_methods.include?(method)
|
|
101
|
+
class_method = klass.singleton_methods.include?(method)
|
|
102
|
+
|
|
103
|
+
# Make sure the request klass::method exists
|
|
104
|
+
if !instance_method && !class_method
|
|
105
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/error] profile_method: Can't instrument #{klass}.#{method} as it doesn't seem to exist."
|
|
106
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/error] #{__FILE__}:#{__LINE__}"
|
|
107
|
+
return false
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Strip '!' or '?' from method if present
|
|
111
|
+
safe_method_name = method.to_s.chop if method.to_s =~ /\?$|\!$/
|
|
112
|
+
safe_method_name ||= method
|
|
113
|
+
|
|
114
|
+
without_appoptics = "#{safe_method_name}_without_appoptics"
|
|
115
|
+
with_appoptics = "#{safe_method_name}_with_appoptics"
|
|
116
|
+
|
|
117
|
+
# Check if already profiled
|
|
118
|
+
if klass.instance_methods.include?(with_appoptics.to_sym) ||
|
|
119
|
+
klass.singleton_methods.include?(with_appoptics.to_sym)
|
|
120
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/error] profile_method: #{klass}::#{method} already profiled."
|
|
121
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/error] profile_method: #{__FILE__}:#{__LINE__}"
|
|
122
|
+
return false
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
source_location = []
|
|
126
|
+
if instance_method
|
|
127
|
+
AppOpticsAPM::Util.send_include(klass, AppOpticsAPM::MethodProfiling)
|
|
128
|
+
source_location = klass.instance_method(method).source_location
|
|
129
|
+
elsif class_method
|
|
130
|
+
AppOpticsAPM::Util.send_extend(klass, AppOpticsAPM::MethodProfiling)
|
|
131
|
+
source_location = klass.method(method).source_location
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
report_kvs = collect_profile_kvs(klass, method, opts, extra_kvs, source_location)
|
|
135
|
+
report_kvs[:MethodName] = safe_method_name
|
|
136
|
+
|
|
137
|
+
if instance_method
|
|
138
|
+
klass.class_eval do
|
|
139
|
+
define_method(with_appoptics) do |*args, &block|
|
|
140
|
+
profile_wrapper(without_appoptics, report_kvs, opts, *args, &block)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
alias_method without_appoptics, method.to_s
|
|
144
|
+
alias_method method.to_s, with_appoptics
|
|
145
|
+
end
|
|
146
|
+
elsif class_method
|
|
147
|
+
klass.define_singleton_method(with_appoptics) do |*args, &block|
|
|
148
|
+
profile_wrapper(without_appoptics, report_kvs, opts, *args, &block)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
klass.singleton_class.class_eval do
|
|
152
|
+
alias_method without_appoptics, method.to_s
|
|
153
|
+
alias_method method.to_s, with_appoptics
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
true
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
private
|
|
160
|
+
|
|
161
|
+
##
|
|
162
|
+
# Private: Helper method to aggregate KVs to report
|
|
163
|
+
#
|
|
164
|
+
# klass - the class or module that has the method to profile
|
|
165
|
+
# method - the method to profile. Can be singleton, instance, private etc...
|
|
166
|
+
# opts - a hash specifying the one or more of the following options:
|
|
167
|
+
# * :arguments - report the arguments passed to <tt>method</tt> on each profile (default: false)
|
|
168
|
+
# * :result - report the return value of <tt>method</tt> on each profile (default: false)
|
|
169
|
+
# * :backtrace - report the return value of <tt>method</tt> on each profile (default: false)
|
|
170
|
+
# * :name - alternate name for the profile reported in the dashboard (default: method name)
|
|
171
|
+
# extra_kvs - a hash containing any additional KVs you would like reported with the profile
|
|
172
|
+
# source_location - array returned from klass.method(:name).source_location
|
|
173
|
+
#
|
|
174
|
+
def collect_profile_kvs(klass, method, opts, extra_kvs, source_location)
|
|
175
|
+
report_kvs = {}
|
|
176
|
+
report_kvs[:Language] ||= :ruby
|
|
177
|
+
report_kvs[:ProfileName] ||= opts[:name] ? opts[:name] : method
|
|
178
|
+
|
|
179
|
+
klass.is_a?(Class) ? report_kvs[:Class] = klass.to_s : report_kvs[:Module] = klass.to_s
|
|
180
|
+
|
|
181
|
+
# If this is a Rails Controller, report the KVs
|
|
182
|
+
if defined?(::AbstractController::Base) && klass.ancestors.include?(::AbstractController::Base)
|
|
183
|
+
report_kvs[:Controller] = klass.to_s
|
|
184
|
+
report_kvs[:Action] = method.to_s
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# We won't have access to this info for native methods (those not defined in Ruby).
|
|
188
|
+
if source_location.is_a?(Array) && source_location.length == 2
|
|
189
|
+
report_kvs[:File] = source_location[0]
|
|
190
|
+
report_kvs[:LineNumber] = source_location[1]
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Merge in any extra_kvs requested
|
|
194
|
+
report_kvs.merge!(extra_kvs)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
# need to set the context to public, otherwise the following `extends` will be private in api.rb
|
|
199
|
+
public
|
|
200
|
+
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
#++
|
|
5
|
+
|
|
6
|
+
module AppOpticsAPM
|
|
7
|
+
module API
|
|
8
|
+
##
|
|
9
|
+
# Provides the higher-level tracing interface for the API
|
|
10
|
+
#
|
|
11
|
+
# The tracing methods have been moved to AppOpticsAPM::SDK and AppOpticsAPM::API extends all methods from the SDK
|
|
12
|
+
# except for start_trace.
|
|
13
|
+
# AppOpticsAPM::API.start_trace is kept for backwards compatibility because it returns an array
|
|
14
|
+
# whereas AppOpticsAPM::SDK.start_trace will only return the result of the block.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
module Tracing
|
|
18
|
+
|
|
19
|
+
# Public: Collect metrics and start tracing a given block of code. A
|
|
20
|
+
# trace will be started depending on configuration and probability.
|
|
21
|
+
# Detect any exceptions thrown by the block and report errors.
|
|
22
|
+
#
|
|
23
|
+
# When start_trace returns control to the calling context, the trace will be
|
|
24
|
+
# completed and the tracing context will be cleared.
|
|
25
|
+
#
|
|
26
|
+
# ==== Arguments
|
|
27
|
+
#
|
|
28
|
+
# * +span+ - name for the span to be used as label in the trace view
|
|
29
|
+
# * +xtrace+ - (optional) incoming X-Trace identifier to be continued
|
|
30
|
+
# * +opts+ - (optional) hash containing key/value pairs that will be reported along
|
|
31
|
+
# with the first event of this span
|
|
32
|
+
#
|
|
33
|
+
# ==== Example
|
|
34
|
+
#
|
|
35
|
+
# def handle_request(request, response)
|
|
36
|
+
# # ... code that modifies request and response ...
|
|
37
|
+
# end
|
|
38
|
+
#
|
|
39
|
+
# def handle_request_with_appoptics(request, response)
|
|
40
|
+
# start_trace('custom_span', nil, :TransactionName => 'handle_request') do
|
|
41
|
+
# handle_request(request, response)
|
|
42
|
+
# end
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# Returns an array with the result of the block and the last xtrace used
|
|
46
|
+
def start_trace(span, xtrace = nil, opts = {})
|
|
47
|
+
target = {}
|
|
48
|
+
[start_trace_with_target(span, xtrace, target, opts) { yield }, target['X-Trace']]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
#++
|
|
5
|
+
|
|
6
|
+
require 'pp'
|
|
7
|
+
|
|
8
|
+
module AppOpticsAPM
|
|
9
|
+
module API
|
|
10
|
+
##
|
|
11
|
+
# General utility methods for the gem
|
|
12
|
+
module Util #:nodoc:
|
|
13
|
+
BACKTRACE_CUTOFF = 200
|
|
14
|
+
|
|
15
|
+
# Internal: Check whether the provided key is reserved or not. Reserved
|
|
16
|
+
# keys are either keys that are handled by liboboe calls or the appoptics_apm gem.
|
|
17
|
+
#
|
|
18
|
+
# key - the key to check.
|
|
19
|
+
#
|
|
20
|
+
# Return a boolean indicating whether or not key is reserved.
|
|
21
|
+
def valid_key?(key)
|
|
22
|
+
![:Label, :Layer, :Edge, :Timestamp, :Timestamp_u].include?(key.to_sym)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Internal: Get the current backtrace.
|
|
26
|
+
#
|
|
27
|
+
# ignore - Number of frames to ignore at the top of the backtrace. Use
|
|
28
|
+
# when you know how many layers deep in the key call is being
|
|
29
|
+
# made.
|
|
30
|
+
#
|
|
31
|
+
# Returns a string with each frame of the backtrace separated by '\r\n'.
|
|
32
|
+
#
|
|
33
|
+
def backtrace(ignore = 0)
|
|
34
|
+
bt = Kernel.caller
|
|
35
|
+
bt.slice!(0, ignore)
|
|
36
|
+
trim_backtrace(bt).join("\r\n")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Internal: Trim a backtrace to a manageable size
|
|
40
|
+
#
|
|
41
|
+
# backtrace - the backtrace (an array of stack frames/from Kernel.caller)
|
|
42
|
+
#
|
|
43
|
+
# Returns a trimmed backtrace
|
|
44
|
+
def trim_backtrace(backtrace)
|
|
45
|
+
return backtrace unless backtrace.is_a?(Array) && backtrace.size > BACKTRACE_CUTOFF
|
|
46
|
+
|
|
47
|
+
# Trim backtraces by getting the first 180 and last 20 lines
|
|
48
|
+
backtrace[0, 180] + ['...[snip]...'] + backtrace[backtrace.size - 20, 20]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Internal: Check if a host is blacklisted from tracing
|
|
52
|
+
#
|
|
53
|
+
# addr_port - the addr_port from Net::HTTP although this method
|
|
54
|
+
# can be used from any component in reality
|
|
55
|
+
#
|
|
56
|
+
# Returns a boolean on blacklisted state
|
|
57
|
+
def blacklisted?(addr_port)
|
|
58
|
+
return false unless AppOpticsAPM::Config.blacklist
|
|
59
|
+
|
|
60
|
+
# Ensure that the blacklist is an array
|
|
61
|
+
unless AppOpticsAPM::Config.blacklist.is_a?(Array)
|
|
62
|
+
val = AppOpticsAPM::Config[:blacklist]
|
|
63
|
+
AppOpticsAPM::Config[:blacklist] = [val.to_s]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
AppOpticsAPM::Config.blacklist.each do |h|
|
|
67
|
+
return true if addr_port.to_s.match(h.to_s)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
false
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Internal: Pretty print a list of arguments for reporting
|
|
74
|
+
#
|
|
75
|
+
# args - the list of arguments to work on
|
|
76
|
+
#
|
|
77
|
+
# Returns a pretty string representation of arguments
|
|
78
|
+
def pps(*args)
|
|
79
|
+
old_out = $stdout
|
|
80
|
+
begin
|
|
81
|
+
s = StringIO.new
|
|
82
|
+
$stdout = s
|
|
83
|
+
pp(*args)
|
|
84
|
+
ensure
|
|
85
|
+
$stdout = old_out
|
|
86
|
+
end
|
|
87
|
+
s.string
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Internal: Determine a string to report representing klass
|
|
91
|
+
#
|
|
92
|
+
# args - an instance of a Class, a Class or a Module
|
|
93
|
+
#
|
|
94
|
+
# Returns a string representation of klass
|
|
95
|
+
def get_class_name(klass)
|
|
96
|
+
kv = {}
|
|
97
|
+
|
|
98
|
+
if klass.to_s =~ /::/
|
|
99
|
+
klass.class.to_s.rpartition('::').last
|
|
100
|
+
else
|
|
101
|
+
if klass.is_a?(Class) && klass.is_a?(Module)
|
|
102
|
+
# Class
|
|
103
|
+
kv['Class'] = klass.to_s
|
|
104
|
+
|
|
105
|
+
elsif !klass.is_a?(Class) && !klass.is_a?(Module)
|
|
106
|
+
# Class instance
|
|
107
|
+
kv['Class'] = klass.class.to_s
|
|
108
|
+
|
|
109
|
+
else
|
|
110
|
+
# Module
|
|
111
|
+
kv['Module'] = klass.to_s
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
kv
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def xtrace_v2?(xtr)
|
|
118
|
+
return xtr && xtr.start_with?('2B')
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|