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,231 @@
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
# Constants from liboboe
|
5
|
+
APPOPTICS_TRACE_DISABLED = 0
|
6
|
+
APPOPTICS_TRACE_ENABLED = 1
|
7
|
+
|
8
|
+
# OBOE_SAMPLE_RATE_SOURCE_FILE = 1
|
9
|
+
# OBOE_SAMPLE_RATE_SOURCE_DEFAULT = 2
|
10
|
+
# OBOE_SAMPLE_RATE_SOURCE_OBOE = 3
|
11
|
+
# OBOE_SAMPLE_RATE_SOURCE_LAST_OBOE = 4
|
12
|
+
# OBOE_SAMPLE_RATE_SOURCE_DEFAULT_MISCONFIGURED = 5
|
13
|
+
# OBOE_SAMPLE_RATE_SOURCE_OBOE_DEFAULT = 6
|
14
|
+
|
15
|
+
# Masks for bitwise ops
|
16
|
+
# ZERO_MASK = 0b0000000000000000000000000000
|
17
|
+
|
18
|
+
SAMPLE_RATE_MASK = 0b0000111111111111111111111111
|
19
|
+
SAMPLE_SOURCE_MASK = 0b1111000000000000000000000000
|
20
|
+
|
21
|
+
# ZERO_SAMPLE_RATE_MASK = 0b1111000000000000000000000000
|
22
|
+
# ZERO_SAMPLE_SOURCE_MASK = 0b0000111111111111111111111111
|
23
|
+
|
24
|
+
# APPOPTICS_STR_BLANK = ''.freeze
|
25
|
+
APPOPTICS_STR_LAYER = 'Layer'.freeze
|
26
|
+
APPOPTICS_STR_LABEL = 'Label'.freeze
|
27
|
+
|
28
|
+
##
|
29
|
+
# This module is the base module for the various implementations of AppOpticsAPM reporting.
|
30
|
+
# Current variations as of 2014-09-10 are a c-extension, JRuby (using AppOpticsAPM Java
|
31
|
+
# instrumentation) and a Heroku c-extension (with embedded tracelyzer)
|
32
|
+
module AppOpticsAPMBase
|
33
|
+
extend AppOpticsAPM::ThreadLocal
|
34
|
+
|
35
|
+
attr_accessor :reporter
|
36
|
+
attr_accessor :loaded
|
37
|
+
thread_local :sample_source
|
38
|
+
thread_local :sample_rate
|
39
|
+
thread_local :layer
|
40
|
+
thread_local :layer_op
|
41
|
+
|
42
|
+
# transaction_name is used for custom transaction naming
|
43
|
+
# It needs to be globally accessible, but is only set by the request processors of the different frameworks
|
44
|
+
# and read by rack
|
45
|
+
thread_local :transaction_name
|
46
|
+
|
47
|
+
# Semaphore used during the test suite to test
|
48
|
+
# global config options.
|
49
|
+
thread_local :config_lock
|
50
|
+
|
51
|
+
# The following accessors indicate the incoming tracing state received
|
52
|
+
# by the rack layer. These are primarily used to identify state
|
53
|
+
# between the Ruby and JAppOpticsAPM instrumentation under JRuby.
|
54
|
+
#
|
55
|
+
# This is because that even though there may be an incoming
|
56
|
+
# X-Trace request header, tracing may have already been started
|
57
|
+
# by Joboe. Such a scenario occurs when the application is being
|
58
|
+
# hosted by a Java container (such as Tomcat or Glassfish) and
|
59
|
+
# AppOpticsAPM has already initiated tracing. In this case, we shouldn't
|
60
|
+
# pickup the X-Trace context in the X-Trace header and we shouldn't
|
61
|
+
# set the outgoing response X-Trace header or clear context.
|
62
|
+
# Yeah I know. Yuck.
|
63
|
+
|
64
|
+
# Occurs only on Jruby. Indicates that Joboe (the java instrumentation)
|
65
|
+
# has already started tracing before it hit the JRuby instrumentation.
|
66
|
+
# It is used in Rack#call if there is a context when entering rack
|
67
|
+
thread_local :has_incoming_context
|
68
|
+
|
69
|
+
# Indicates the existence of a valid X-Trace request header
|
70
|
+
thread_local :has_xtrace_header
|
71
|
+
|
72
|
+
# This indicates that this trace was continued from
|
73
|
+
# an incoming X-Trace request header or in the case
|
74
|
+
# of JRuby, a trace already started by JAppOpticsAPM.
|
75
|
+
thread_local :is_continued_trace
|
76
|
+
|
77
|
+
##
|
78
|
+
# extended
|
79
|
+
#
|
80
|
+
# Invoked when this module is extended.
|
81
|
+
# e.g. extend AppOpticsAPMBase
|
82
|
+
#
|
83
|
+
def self.extended(cls)
|
84
|
+
cls.loaded = true
|
85
|
+
|
86
|
+
# This gives us pretty accessors with questions marks at the end
|
87
|
+
# e.g. is_continued_trace --> is_continued_trace?
|
88
|
+
AppOpticsAPM.methods.select { |m| m =~ /^is_|^has_/ }.each do |c|
|
89
|
+
unless c =~ /\?$|=$/
|
90
|
+
# AppOpticsAPM.logger.debug "aliasing #{c}? to #{c}"
|
91
|
+
alias_method "#{c}?", c
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# pickup_context
|
98
|
+
#
|
99
|
+
# for JRUBY
|
100
|
+
# Determines whether we should pickup context
|
101
|
+
# from an incoming X-Trace request header. The answer
|
102
|
+
# is generally yes but there are cases in JRuby under
|
103
|
+
# Tomcat (or Glassfish etc.) where tracing may have
|
104
|
+
# been already started by the Java instrumentation (Joboe)
|
105
|
+
# in which case we don't want to do this.
|
106
|
+
#
|
107
|
+
def pickup_context?(xtrace)
|
108
|
+
return false unless AppOpticsAPM::XTrace.valid?(xtrace)
|
109
|
+
|
110
|
+
if defined?(JRUBY_VERSION) && AppOpticsAPM.tracing?
|
111
|
+
return false
|
112
|
+
else
|
113
|
+
return true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# tracing_layer?
|
119
|
+
#
|
120
|
+
# Queries the thread local variable about the current
|
121
|
+
# layer being traced. This is used in cases of recursive
|
122
|
+
# operation tracing or one instrumented operation calling another.
|
123
|
+
#
|
124
|
+
def tracing_layer?(layer)
|
125
|
+
AppOpticsAPM.layer == layer.to_sym
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# tracing_layer_op?
|
130
|
+
#
|
131
|
+
# Queries the thread local variable about the current
|
132
|
+
# operation being traced. This is used in cases of recursive
|
133
|
+
# operation tracing or one instrumented operation calling another.
|
134
|
+
#
|
135
|
+
# In such cases, we only want to trace the outermost operation.
|
136
|
+
#
|
137
|
+
def tracing_layer_op?(operation)
|
138
|
+
unless AppOpticsAPM.layer_op.nil? || AppOpticsAPM.layer_op.is_a?(Array)
|
139
|
+
AppOpticsAPM.logger.error('[appopticsapm/logging] INTERNAL: layer_op should be nil or an array, please report to technicalsupport@solarwinds.com')
|
140
|
+
return false
|
141
|
+
end
|
142
|
+
|
143
|
+
return false if AppOpticsAPM.layer_op.nil? || AppOpticsAPM.layer_op.empty? || !operation.respond_to?(:to_sym)
|
144
|
+
AppOpticsAPM.layer_op.last == operation.to_sym
|
145
|
+
end
|
146
|
+
|
147
|
+
# TODO ME review use of these boolean statements
|
148
|
+
# ____ they should now be handled by TransactionSettings,
|
149
|
+
# ____ because there can be exceptions to :enabled and :disabled
|
150
|
+
|
151
|
+
##
|
152
|
+
# Returns true if the tracing_mode is set to :enabled.
|
153
|
+
# False otherwise
|
154
|
+
#
|
155
|
+
def tracing_enabled?
|
156
|
+
AppOpticsAPM::Config[:tracing_mode] &&
|
157
|
+
[:enabled, :always].include?(AppOpticsAPM::Config[:tracing_mode].to_sym)
|
158
|
+
end
|
159
|
+
|
160
|
+
##
|
161
|
+
# Returns true if the tracing_mode is set to :disabled.
|
162
|
+
# False otherwise
|
163
|
+
#
|
164
|
+
def tracing_disabled?
|
165
|
+
AppOpticsAPM::Config[:tracing_mode] &&
|
166
|
+
[:disabled, :never].include?(AppOpticsAPM::Config[:tracing_mode].to_sym)
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Returns true if we are currently tracing a request
|
171
|
+
# False otherwise
|
172
|
+
#
|
173
|
+
def tracing?
|
174
|
+
return false if !AppOpticsAPM.loaded # || AppOpticsAPM.tracing_disabled?
|
175
|
+
AppOpticsAPM::Context.isSampled
|
176
|
+
end
|
177
|
+
|
178
|
+
def heroku?
|
179
|
+
ENV.key?('APPOPTICS_URL')
|
180
|
+
end
|
181
|
+
|
182
|
+
##
|
183
|
+
# Determines if we are running under a forking webserver
|
184
|
+
#
|
185
|
+
def forking_webserver?
|
186
|
+
if (defined?(::Unicorn) && ($PROGRAM_NAME =~ /unicorn/i)) ||
|
187
|
+
(defined?(::Puma) && ($PROGRAM_NAME =~ /puma/i))
|
188
|
+
true
|
189
|
+
else
|
190
|
+
false
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# Indicates whether a supported framework is in use
|
196
|
+
# or not
|
197
|
+
#
|
198
|
+
def framework?
|
199
|
+
defined?(::Rails) || defined?(::Sinatra) || defined?(::Padrino) || defined?(::Grape)
|
200
|
+
end
|
201
|
+
|
202
|
+
##
|
203
|
+
# These methods should be implemented by the descendants
|
204
|
+
# (Oboe_metal, JOboe_metal (JRuby), Heroku_metal)
|
205
|
+
#
|
206
|
+
def sample?(_opts = {})
|
207
|
+
fail 'sample? should be implemented by metal layer.'
|
208
|
+
end
|
209
|
+
|
210
|
+
def log(_layer, _label, _options = {})
|
211
|
+
fail 'log should be implemented by metal layer.'
|
212
|
+
end
|
213
|
+
|
214
|
+
def set_tracing_mode(_mode)
|
215
|
+
fail 'set_tracing_mode should be implemented by metal layer.'
|
216
|
+
end
|
217
|
+
|
218
|
+
def set_sample_rate(_rate)
|
219
|
+
fail 'set_sample_rate should be implemented by metal layer.'
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
module AppOpticsAPM
|
224
|
+
extend AppOpticsAPMBase
|
225
|
+
end
|
226
|
+
|
227
|
+
# Setup an alias so we don't bug users
|
228
|
+
# about single letter capitalization
|
229
|
+
AppopticsAPM = AppOpticsAPM
|
230
|
+
AppOpticsApm = AppOpticsAPM
|
231
|
+
AppopticsApm = AppOpticsAPM
|
@@ -0,0 +1,299 @@
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
require_relative 'support/transaction_settings'
|
5
|
+
|
6
|
+
module AppOpticsAPM
|
7
|
+
##
|
8
|
+
# This module exposes a nested configuration hash that can be used to
|
9
|
+
# configure and/or modify the functionality of the appoptics_apm gem.
|
10
|
+
#
|
11
|
+
# Use AppOpticsAPM::Config.show to view the entire nested hash.
|
12
|
+
#
|
13
|
+
module Config
|
14
|
+
@@config = {}
|
15
|
+
|
16
|
+
@@instrumentation = [:action_controller, :action_controller_api, :action_view,
|
17
|
+
:active_record, :bunnyclient, :bunnyconsumer, :cassandra, :curb,
|
18
|
+
:dalli, :delayed_jobclient, :delayed_jobworker,
|
19
|
+
:excon, :faraday, :graphql, :grpc_client, :grpc_server, :grape,
|
20
|
+
:httpclient, :nethttp, :memcached, :mongo, :moped, :padrino, :rack, :redis,
|
21
|
+
:resqueclient, :resqueworker, :rest_client,
|
22
|
+
:sequel, :sidekiqclient, :sidekiqworker, :sinatra, :typhoeus]
|
23
|
+
|
24
|
+
# ignore configs for instrumentations we don't have anymore
|
25
|
+
# can't remove because the config may still be present in configs created
|
26
|
+
# with previous gem versions
|
27
|
+
@@ignore = [:em_http_request]
|
28
|
+
|
29
|
+
# Subgrouping of instrumentation
|
30
|
+
@@http_clients = [:curb, :excon,
|
31
|
+
# :em_http_request,
|
32
|
+
:faraday, :httpclient, :nethttp, :rest_client, :typhoeus]
|
33
|
+
|
34
|
+
##
|
35
|
+
# load_config_file
|
36
|
+
#
|
37
|
+
# There are 3 possible locations for the config file:
|
38
|
+
# Rails default, ENV['APPOPTICS_APM_CONFIG_RUBY'], or the gem's default
|
39
|
+
#
|
40
|
+
# Hierarchie:
|
41
|
+
# 1 - Rails default: config/initializers/appoptics_apm.rb
|
42
|
+
# (also loaded by Rails, but we can't reliably determine if Rails is running)
|
43
|
+
# 2 - ENV['APPOPTICS_APM_CONFIG_RUBY']
|
44
|
+
# 3 - Gem default: <startup_dir>/appoptics_apm_config.rb
|
45
|
+
#
|
46
|
+
def self.load_config_file
|
47
|
+
config_files = []
|
48
|
+
|
49
|
+
# Check for the rails config file
|
50
|
+
config_file = File.join(Dir.pwd, 'config/initializers/appoptics_apm.rb')
|
51
|
+
config_files << config_file if File.exist?(config_file)
|
52
|
+
|
53
|
+
# Check for file set by env variable
|
54
|
+
if ENV.key?('APPOPTICS_APM_CONFIG_RUBY')
|
55
|
+
if File.exist?(ENV['APPOPTICS_APM_CONFIG_RUBY']) && !File.directory?(ENV['APPOPTICS_APM_CONFIG_RUBY'])
|
56
|
+
config_files << ENV['APPOPTICS_APM_CONFIG_RUBY']
|
57
|
+
elsif File.exist?(File.join(ENV['APPOPTICS_APM_CONFIG_RUBY'], 'appoptics_apm_config.rb'))
|
58
|
+
config_files << File.join(ENV['APPOPTICS_APM_CONFIG_RUBY'], 'appoptics_apm_config.rb')
|
59
|
+
else
|
60
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/config] Could not find the configuration file set by the APPOPTICS_APM_CONFIG_RUBY environment variable: #{ENV['APPOPTICS_APM_CONFIG_RUBY']}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Check for default config file
|
65
|
+
config_file = File.join(Dir.pwd, 'appoptics_apm_config.rb')
|
66
|
+
config_files << config_file if File.exist?(config_file)
|
67
|
+
|
68
|
+
unless config_files.empty? # we use the defaults from the template if there are no config files
|
69
|
+
if config_files.size > 1
|
70
|
+
AppOpticsAPM.logger.warn [
|
71
|
+
'[appoptics_apm/config] Multiple configuration files configured, using the first one listed: ',
|
72
|
+
config_files.join(', ')
|
73
|
+
].join(' ')
|
74
|
+
end
|
75
|
+
load(config_files[0])
|
76
|
+
end
|
77
|
+
|
78
|
+
# sets AppOpticsAPM::Config[:debug_level], AppOpticsAPM.logger.level
|
79
|
+
set_log_level
|
80
|
+
|
81
|
+
# the verbose setting is only relevant for ruby, ENV['APPOPTICS_GEM_VERBOSE'] overrides
|
82
|
+
if ENV.key?('APPOPTICS_GEM_VERBOSE')
|
83
|
+
AppOpticsAPM::Config[:verbose] = ENV['APPOPTICS_GEM_VERBOSE'].downcase == 'true'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.set_log_level
|
88
|
+
unless (-1..6).include?(AppOpticsAPM::Config[:debug_level])
|
89
|
+
AppOpticsAPM::Config[:debug_level] = 3
|
90
|
+
end
|
91
|
+
|
92
|
+
# let's find and use the equivalent debug level for ruby
|
93
|
+
debug_level = (ENV['APPOPTICS_DEBUG_LEVEL'] || AppOpticsAPM::Config[:debug_level] || 3).to_i
|
94
|
+
if debug_level < 0
|
95
|
+
# there should be no logging if APPOPTICS_DEBUG_LEVEL == -1
|
96
|
+
# In Ruby level 5 is UNKNOWN and it can log, but level 6 is quiet
|
97
|
+
AppOpticsAPM.logger.level = 6
|
98
|
+
else
|
99
|
+
AppOpticsAPM.logger.level = [4 - debug_level, 0].max
|
100
|
+
end
|
101
|
+
AppOpticsAPM::Config[:debug_level] = debug_level
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# print_config
|
106
|
+
#
|
107
|
+
# print configurations one per line
|
108
|
+
# to create an output similar to the content of the config file
|
109
|
+
#
|
110
|
+
def self.print_config
|
111
|
+
AppOpticsAPM.logger.warn "# General configurations"
|
112
|
+
non_instrumentation = @@config.keys - @@instrumentation
|
113
|
+
non_instrumentation.each do |config|
|
114
|
+
AppOpticsAPM.logger.warn "AppOpticsAPM::Config[:#{config}] = #{@@config[config]}"
|
115
|
+
end
|
116
|
+
|
117
|
+
AppOpticsAPM.logger.warn "\n# Instrumentation specific configurations"
|
118
|
+
AppOpticsAPM.logger.warn "# Enabled/Disabled Instrumentation"
|
119
|
+
@@instrumentation.each do |config|
|
120
|
+
AppOpticsAPM.logger.warn "AppOpticsAPM::Config[:#{config}][:enabled] = #{@@config[config][:enabled]}"
|
121
|
+
end
|
122
|
+
|
123
|
+
AppOpticsAPM.logger.warn "\n# Enabled/Disabled Backtrace Collection"
|
124
|
+
@@instrumentation.each do |config|
|
125
|
+
AppOpticsAPM.logger.warn "AppOpticsAPM::Config[:#{config}][:collect_backtraces] = #{@@config[config][:collect_backtraces]}"
|
126
|
+
end
|
127
|
+
|
128
|
+
AppOpticsAPM.logger.warn "\n# Logging of outgoing HTTP query args"
|
129
|
+
@@instrumentation.each do |config|
|
130
|
+
AppOpticsAPM.logger.warn "AppOpticsAPM::Config[:#{config}][:log_args] = #{@@config[config][:log_args] || false}"
|
131
|
+
end
|
132
|
+
|
133
|
+
AppOpticsAPM.logger.warn "\n# Bunny Controller and Action"
|
134
|
+
AppOpticsAPM.logger.warn "AppOpticsAPM::Config[:bunnyconsumer][:controller] = #{@@config[:bunnyconsumer][:controller].inspect}"
|
135
|
+
AppOpticsAPM.logger.warn "AppOpticsAPM::Config[:bunnyconsumer][:action] = #{@@config[:bunnyconsumer][:action].inspect}"
|
136
|
+
nil
|
137
|
+
end
|
138
|
+
|
139
|
+
##
|
140
|
+
# initialize
|
141
|
+
#
|
142
|
+
# Initializer method to set everything up with a default configuration.
|
143
|
+
# The defaults are read from the template configuration file.
|
144
|
+
#
|
145
|
+
# rubocop:disable Metrics/AbcSize
|
146
|
+
def self.initialize(_data = {})
|
147
|
+
(@@instrumentation+@@ignore).each { |k| @@config[k] = {} }
|
148
|
+
@@config[:transaction_name] = {}
|
149
|
+
|
150
|
+
# Always load the template, it has all the keys and defaults defined,
|
151
|
+
# no guarantee of completeness in the user's config file
|
152
|
+
load(File.join(File.dirname(File.dirname(__FILE__)),
|
153
|
+
'rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb'))
|
154
|
+
end
|
155
|
+
# rubocop:enable Metrics/AbcSize
|
156
|
+
|
157
|
+
def self.update!(data)
|
158
|
+
data.each do |key, value|
|
159
|
+
self[key] = value
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.merge!(data)
|
164
|
+
update!(data)
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.[](key)
|
168
|
+
if key == :resque
|
169
|
+
AppOpticsAPM.logger.warn '[appoptics_apm/warn] :resque config is deprecated. It is now split into :resqueclient and :resqueworker.'
|
170
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/warn] Called from #{Kernel.caller[0]}"
|
171
|
+
end
|
172
|
+
|
173
|
+
@@config[key.to_sym]
|
174
|
+
end
|
175
|
+
|
176
|
+
##
|
177
|
+
# []=
|
178
|
+
#
|
179
|
+
# Config variable assignment method. Here we validate and store the
|
180
|
+
# assigned value(s) and trigger any secondary action needed.
|
181
|
+
#
|
182
|
+
# rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
183
|
+
def self.[]=(key, value)
|
184
|
+
key = key.to_sym
|
185
|
+
@@config[key] = value
|
186
|
+
|
187
|
+
if key == :sampling_rate
|
188
|
+
AppOpticsAPM.logger.warn '[appoptics_apm/config] sampling_rate is not a supported setting for AppOpticsAPM::Config. ' \
|
189
|
+
'Please use :sample_rate.'
|
190
|
+
|
191
|
+
elsif key == :sample_rate
|
192
|
+
unless value.is_a?(Integer) || value.is_a?(Float)
|
193
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/config] :sample_rate must be a number between 0 and 1000000 (1m) " \
|
194
|
+
"(provided: #{value}), corrected to 0"
|
195
|
+
value = 0
|
196
|
+
end
|
197
|
+
|
198
|
+
# Validate :sample_rate value
|
199
|
+
unless value.between?(0, 1e6)
|
200
|
+
value_1 = value
|
201
|
+
value = value_1 < 0 ? 0 : 1_000_000
|
202
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/config] :sample_rate must be between 0 and 1000000 (1m) " \
|
203
|
+
"(provided: #{value_1}), corrected to #{value}"
|
204
|
+
end
|
205
|
+
|
206
|
+
# Assure value is an integer
|
207
|
+
@@config[key.to_sym] = value.to_i
|
208
|
+
AppOpticsAPM.set_sample_rate(value) if AppOpticsAPM.loaded
|
209
|
+
|
210
|
+
elsif key == :action_blacklist
|
211
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/config] :action_blacklist has been deprecated and no longer functions."
|
212
|
+
|
213
|
+
elsif key == :dnt_regexp
|
214
|
+
if value.nil? || value == ''
|
215
|
+
@@config[:dnt_compiled] = nil
|
216
|
+
else
|
217
|
+
@@config[:dnt_compiled] =
|
218
|
+
Regexp.new(AppOpticsAPM::Config[:dnt_regexp], AppOpticsAPM::Config[:dnt_opts] || nil)
|
219
|
+
end
|
220
|
+
|
221
|
+
elsif key == :dnt_opts
|
222
|
+
if AppOpticsAPM::Config[:dnt_regexp] && AppOpticsAPM::Config[:dnt_regexp] != ''
|
223
|
+
@@config[:dnt_compiled] =
|
224
|
+
Regexp.new(AppOpticsAPM::Config[:dnt_regexp], AppOpticsAPM::Config[:dnt_opts] || nil)
|
225
|
+
end
|
226
|
+
|
227
|
+
elsif key == :profiling_interval
|
228
|
+
if value.is_a?(Integer) && value > 0
|
229
|
+
value = [100, value].min
|
230
|
+
else
|
231
|
+
value = 10
|
232
|
+
end
|
233
|
+
@@config[:profiling_interval] = value
|
234
|
+
# CProfiler may not be loaded yet, the profiler will send the value
|
235
|
+
# after it is loaded
|
236
|
+
AppOpticsAPM::CProfiler.set_interval(value) if defined? AppOpticsAPM::CProfiler
|
237
|
+
|
238
|
+
elsif key == :transaction_settings
|
239
|
+
if value.is_a?(Hash)
|
240
|
+
AppOpticsAPM::TransactionSettings.compile_url_settings(value[:url])
|
241
|
+
else
|
242
|
+
AppOpticsAPM::TransactionSettings.reset_url_regexps
|
243
|
+
end
|
244
|
+
|
245
|
+
elsif key == :resque
|
246
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/config] :resque config is deprecated. It is now split into :resqueclient and :resqueworker."
|
247
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/config] Called from #{Kernel.caller[0]}"
|
248
|
+
|
249
|
+
elsif key == :include_url_query_params # DEPRECATED
|
250
|
+
# Obey the global flag and update all of the per instrumentation
|
251
|
+
# <tt>:log_args</tt> values.
|
252
|
+
@@config[:rack][:log_args] = value
|
253
|
+
|
254
|
+
elsif key == :include_remote_url_params # DEPRECATED
|
255
|
+
# Obey the global flag and update all of the per instrumentation
|
256
|
+
# <tt>:log_args</tt> values.
|
257
|
+
@@http_clients.each do |i|
|
258
|
+
@@config[i][:log_args] = value
|
259
|
+
end
|
260
|
+
|
261
|
+
elsif key == :tracing_mode
|
262
|
+
# CAN'T DO `set_tracing_mode` ANYMORE, ALL TRACING COMMUNICATION TO OBOE
|
263
|
+
# IS NOW HANDLED BY TransactionSettings
|
264
|
+
# AppOpticsAPM.set_tracing_mode(value.to_sym) if AppOpticsAPM.loaded
|
265
|
+
|
266
|
+
# Make sure that the mode is stored as a symbol
|
267
|
+
@@config[key.to_sym] = value.to_sym
|
268
|
+
|
269
|
+
elsif key == :trigger_tracing_mode
|
270
|
+
# Make sure that the mode is stored as a symbol
|
271
|
+
@@config[key.to_sym] = value.to_sym
|
272
|
+
end
|
273
|
+
end
|
274
|
+
# rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
275
|
+
|
276
|
+
def self.method_missing(sym, *args)
|
277
|
+
class_var_name = "@@#{sym}"
|
278
|
+
|
279
|
+
if sym.to_s =~ /(.+)=$/
|
280
|
+
self[$1] = args.first
|
281
|
+
else
|
282
|
+
# Try part of the @@config hash first
|
283
|
+
if @@config.key?(sym)
|
284
|
+
self[sym]
|
285
|
+
|
286
|
+
# Then try as a class variable
|
287
|
+
elsif self.class_variable_defined?(class_var_name.to_sym)
|
288
|
+
self.class_eval(class_var_name)
|
289
|
+
|
290
|
+
# Congrats - You've won a brand new nil...
|
291
|
+
else
|
292
|
+
nil
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
AppOpticsAPM::Config.initialize
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
class GrapeError < StandardError; end
|
5
|
+
|
6
|
+
module AppOpticsAPM
|
7
|
+
module Grape
|
8
|
+
module API
|
9
|
+
def self.extended(klass)
|
10
|
+
AppOpticsAPM::Util.class_method_alias(klass, :inherited, ::Grape::API)
|
11
|
+
end
|
12
|
+
|
13
|
+
def inherited_with_appoptics(subclass)
|
14
|
+
inherited_without_appoptics(subclass)
|
15
|
+
|
16
|
+
subclass.use AppOpticsAPM::Rack
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Endpoint
|
21
|
+
def self.included(klass)
|
22
|
+
AppOpticsAPM::Util.method_alias(klass, :run, ::Grape::Endpoint)
|
23
|
+
end
|
24
|
+
|
25
|
+
def run_with_appoptics(*args)
|
26
|
+
# Report Controller/Action and Transaction as best possible
|
27
|
+
report_kvs = {}
|
28
|
+
|
29
|
+
report_kvs[:Controller] = options[:for].to_s
|
30
|
+
report_kvs[:Action] =
|
31
|
+
if route&.pattern
|
32
|
+
route.options ? "#{route.options[:method]}#{route.pattern.origin}" : route.pattern.origin
|
33
|
+
else
|
34
|
+
args.empty? ? env['PATH_INFO'] : args[0]['PATH_INFO']
|
35
|
+
end
|
36
|
+
report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:grape][:collect_backtraces]
|
37
|
+
|
38
|
+
env['appoptics_apm.controller'] = report_kvs[:Controller]
|
39
|
+
env['appoptics_apm.action'] = report_kvs[:Action]
|
40
|
+
|
41
|
+
AppOpticsAPM::API.log_entry('grape', report_kvs)
|
42
|
+
|
43
|
+
run_without_appoptics(*args)
|
44
|
+
ensure
|
45
|
+
AppOpticsAPM::API.log_exit('grape')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module Middleware
|
50
|
+
module Error
|
51
|
+
def self.included(klass)
|
52
|
+
AppOpticsAPM::Util.method_alias(klass, :error_response, ::Grape::Middleware::Error)
|
53
|
+
end
|
54
|
+
|
55
|
+
def error_response_with_appoptics(error = {})
|
56
|
+
response = error_response_without_appoptics(error)
|
57
|
+
status, headers, _body = response.finish
|
58
|
+
|
59
|
+
xtrace = AppOpticsAPM::Context.toString
|
60
|
+
|
61
|
+
if AppOpticsAPM.tracing?
|
62
|
+
|
63
|
+
# Since Grape uses throw/catch and not Exceptions, we have to create an exception here
|
64
|
+
exception = GrapeError.new(error[:message] ? error[:message] : "No message given.")
|
65
|
+
exception.set_backtrace(AppOpticsAPM::API.backtrace)
|
66
|
+
|
67
|
+
AppOpticsAPM::API.log_exception('rack', exception)
|
68
|
+
|
69
|
+
# Since calls to error() are handled similar to abort in Grape. We
|
70
|
+
# manually log the rack exit here since the original code won't
|
71
|
+
# be returned to
|
72
|
+
xtrace = AppOpticsAPM::API.log_end('rack', :Status => status)
|
73
|
+
end
|
74
|
+
|
75
|
+
if headers && AppOpticsAPM::XTrace.valid?(xtrace)
|
76
|
+
unless defined?(JRUBY_VERSION) && AppOpticsAPM.is_continued_trace?
|
77
|
+
headers['X-Trace'] = xtrace if headers.is_a?(Hash)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
response
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if AppOpticsAPM::Config[:grape][:enabled] && defined?(Grape)
|
89
|
+
require 'appoptics_apm/inst/rack'
|
90
|
+
|
91
|
+
AppOpticsAPM.logger.info "[appoptics_apm/loading] Instrumenting Grape" if AppOpticsAPM::Config[:verbose]
|
92
|
+
|
93
|
+
AppOpticsAPM::Inst.load_instrumentation
|
94
|
+
|
95
|
+
AppOpticsAPM::Util.send_extend(Grape::API, AppOpticsAPM::Grape::API)
|
96
|
+
AppOpticsAPM::Util.send_include(Grape::Endpoint, AppOpticsAPM::Grape::Endpoint)
|
97
|
+
AppOpticsAPM::Util.send_include(Grape::Middleware::Error, AppOpticsAPM::Grape::Middleware::Error)
|
98
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
module AppOpticsAPM
|
5
|
+
module PadrinoInst
|
6
|
+
module Routing
|
7
|
+
def self.included(klass)
|
8
|
+
AppOpticsAPM::Util.method_alias(klass, :dispatch!, ::Padrino::Routing)
|
9
|
+
end
|
10
|
+
|
11
|
+
def dispatch_with_appoptics
|
12
|
+
|
13
|
+
AppOpticsAPM::API.log_entry('padrino', {})
|
14
|
+
report_kvs = {}
|
15
|
+
|
16
|
+
result = dispatch_without_appoptics
|
17
|
+
|
18
|
+
# Report Controller/Action and Transaction as best possible
|
19
|
+
controller = (request.controller && !request.controller.empty?) ? request.controller : nil
|
20
|
+
report_kvs[:Controller] = controller || self.class
|
21
|
+
report_kvs[:Action] = request.route_obj ? request.route_obj.path : request.action
|
22
|
+
env['appoptics_apm.controller'] = report_kvs[:Controller]
|
23
|
+
env['appoptics_apm.action'] = report_kvs[:Action]
|
24
|
+
|
25
|
+
result
|
26
|
+
rescue => e
|
27
|
+
AppOpticsAPM::API.log_exception('padrino', e)
|
28
|
+
raise e
|
29
|
+
ensure
|
30
|
+
report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:padrino][:collect_backtraces]
|
31
|
+
AppOpticsAPM::API.log_exit('padrino', report_kvs)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module Rendering
|
36
|
+
def self.included(klass)
|
37
|
+
AppOpticsAPM::Util.method_alias(klass, :render, ::Padrino::Rendering)
|
38
|
+
end
|
39
|
+
|
40
|
+
# TODO add test coverage, currently there are no tests for this
|
41
|
+
# ____ I'm not sure this gets ever called, Padrino uses Sinatra's render method
|
42
|
+
def render_with_appoptics(engine, data = nil, options = {}, locals = {}, &block)
|
43
|
+
if AppOpticsAPM.tracing?
|
44
|
+
report_kvs = {}
|
45
|
+
|
46
|
+
report_kvs[:engine] = engine
|
47
|
+
report_kvs[:template] = data
|
48
|
+
|
49
|
+
AppOpticsAPM::SDK.trace(:padrino_render, report_kvs, :padrino_render) do
|
50
|
+
report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:padrino][:collect_backtraces]
|
51
|
+
render_without_appoptics(engine, data, options, locals, &block)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
render_without_appoptics(engine, data, options, locals, &block)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
if defined?(Padrino) && AppOpticsAPM::Config[:padrino][:enabled]
|
62
|
+
# This instrumentation is a superset of the Sinatra instrumentation similar
|
63
|
+
# to how Padrino is a superset of Sinatra itself.
|
64
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting Padrino' if AppOpticsAPM::Config[:verbose]
|
65
|
+
|
66
|
+
Padrino.after_load do
|
67
|
+
AppOpticsAPM.logger = Padrino.logger if Padrino.respond_to?(:logger)
|
68
|
+
AppOpticsAPM::Inst.load_instrumentation
|
69
|
+
|
70
|
+
AppOpticsAPM::Util.send_include(Padrino::Routing::InstanceMethods, AppOpticsAPM::PadrinoInst::Routing)
|
71
|
+
if defined?(Padrino::Rendering)
|
72
|
+
AppOpticsAPM::Util.send_include(Padrino::Rendering::InstanceMethods, AppOpticsAPM::PadrinoInst::Rendering)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Report __Init after fork when in Heroku
|
76
|
+
AppOpticsAPM::API.report_init unless AppOpticsAPM.heroku?
|
77
|
+
end
|
78
|
+
end
|