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,97 @@
|
|
|
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
|
+
status, headers, body = error_response_without_appoptics(error)
|
|
57
|
+
|
|
58
|
+
xtrace = AppOpticsAPM::Context.toString
|
|
59
|
+
|
|
60
|
+
if AppOpticsAPM.tracing?
|
|
61
|
+
|
|
62
|
+
# Since Grape uses throw/catch and not Exceptions, we have to create an exception here
|
|
63
|
+
exception = GrapeError.new(error[:message] ? error[:message] : "No message given.")
|
|
64
|
+
exception.set_backtrace(AppOpticsAPM::API.backtrace)
|
|
65
|
+
|
|
66
|
+
AppOpticsAPM::API.log_exception('rack', exception)
|
|
67
|
+
|
|
68
|
+
# Since calls to error() are handled similar to abort in Grape. We
|
|
69
|
+
# manually log the rack exit here since the original code won't
|
|
70
|
+
# be returned to
|
|
71
|
+
xtrace = AppOpticsAPM::API.log_end('rack', :Status => status)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
if headers && AppOpticsAPM::XTrace.valid?(xtrace)
|
|
75
|
+
unless defined?(JRUBY_VERSION) && AppOpticsAPM.is_continued_trace?
|
|
76
|
+
headers['X-Trace'] = xtrace if headers.is_a?(Hash)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
[status, headers, body]
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
if AppOpticsAPM::Config[:grape][:enabled] && defined?(Grape)
|
|
88
|
+
require 'appoptics_apm/inst/rack'
|
|
89
|
+
|
|
90
|
+
AppOpticsAPM.logger.info "[appoptics_apm/loading] Instrumenting Grape" if AppOpticsAPM::Config[:verbose]
|
|
91
|
+
|
|
92
|
+
AppOpticsAPM::Inst.load_instrumentation
|
|
93
|
+
|
|
94
|
+
AppOpticsAPM::Util.send_extend(Grape::API, AppOpticsAPM::Grape::API)
|
|
95
|
+
AppOpticsAPM::Util.send_include(Grape::Endpoint, AppOpticsAPM::Grape::Endpoint)
|
|
96
|
+
AppOpticsAPM::Util.send_include(Grape::Middleware::Error, AppOpticsAPM::Grape::Middleware::Error)
|
|
97
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
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
|
+
def render_with_appoptics(engine, data = nil, options = {}, locals = {}, &block)
|
|
42
|
+
if AppOpticsAPM.tracing?
|
|
43
|
+
report_kvs = {}
|
|
44
|
+
|
|
45
|
+
if data
|
|
46
|
+
report_kvs[:engine] = engine
|
|
47
|
+
report_kvs[:template] = data
|
|
48
|
+
else
|
|
49
|
+
report_kvs[:template] = engine
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if AppOpticsAPM.tracing_layer_op?(:render)
|
|
53
|
+
# For recursive calls to :render (for sub-partials and layouts),
|
|
54
|
+
# use method profiling.
|
|
55
|
+
begin
|
|
56
|
+
report_kvs[:FunctionName] = :render
|
|
57
|
+
report_kvs[:Class] = :Rendering
|
|
58
|
+
report_kvs[:Module] = :Padrino
|
|
59
|
+
report_kvs[:File] = __FILE__
|
|
60
|
+
report_kvs[:LineNumber] = __LINE__
|
|
61
|
+
rescue StandardError => e
|
|
62
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/padrino] #{e.message}"
|
|
63
|
+
AppOpticsAPM.logger.debug e.backtrace.join(', ')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
AppOpticsAPM::API.profile(report_kvs[:template], report_kvs, false) do
|
|
67
|
+
render_without_appoptics(engine, data, options, locals, &block)
|
|
68
|
+
end
|
|
69
|
+
else
|
|
70
|
+
# Fall back to the raw tracing API so we can pass KVs
|
|
71
|
+
# back on exit (a limitation of the AppOpticsAPM::API.trace
|
|
72
|
+
# block method) This removes the need for an info
|
|
73
|
+
# event to send additonal KVs
|
|
74
|
+
AppOpticsAPM::API.log_entry(:render, {}, :render)
|
|
75
|
+
|
|
76
|
+
begin
|
|
77
|
+
render_without_appoptics(engine, data, options, locals, &block)
|
|
78
|
+
ensure
|
|
79
|
+
report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:padrino][:collect_backtraces]
|
|
80
|
+
AppOpticsAPM::API.log_exit(:render, report_kvs)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
else
|
|
84
|
+
render_without_appoptics(engine, data, options, locals, &block)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
if defined?(Padrino) && AppopticsAPM::Config[:padrino][:enabled]
|
|
92
|
+
# This instrumentation is a superset of the Sinatra instrumentation similar
|
|
93
|
+
# to how Padrino is a superset of Sinatra itself.
|
|
94
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting Padrino' if AppOpticsAPM::Config[:verbose]
|
|
95
|
+
|
|
96
|
+
Padrino.after_load do
|
|
97
|
+
AppOpticsAPM.logger = Padrino.logger if Padrino.respond_to?(:logger)
|
|
98
|
+
AppOpticsAPM::Inst.load_instrumentation
|
|
99
|
+
|
|
100
|
+
AppOpticsAPM::Util.send_include(Padrino::Routing::InstanceMethods, AppOpticsAPM::PadrinoInst::Routing)
|
|
101
|
+
if defined?(Padrino::Rendering)
|
|
102
|
+
AppOpticsAPM::Util.send_include(Padrino::Rendering::InstanceMethods, AppOpticsAPM::PadrinoInst::Rendering)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Report __Init after fork when in Heroku
|
|
106
|
+
AppOpticsAPM::API.report_init unless AppOpticsAPM.heroku?
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
module Rails
|
|
6
|
+
module Helpers
|
|
7
|
+
extend ActiveSupport::Concern if defined?(::Rails) and ::Rails::VERSION::MAJOR > 2
|
|
8
|
+
|
|
9
|
+
# Deprecated
|
|
10
|
+
# no usages
|
|
11
|
+
def appoptics_rum_header
|
|
12
|
+
AppOpticsAPM.logger.warn '[appoptics_apm/warn] Note that appoptics_rum_header is deprecated. It is now a no-op and should be removed from your application code.'
|
|
13
|
+
return ''
|
|
14
|
+
end
|
|
15
|
+
alias_method :oboe_rum_header, :appoptics_rum_header
|
|
16
|
+
|
|
17
|
+
# Deprecated
|
|
18
|
+
def appoptics_rum_footer
|
|
19
|
+
AppOpticsAPM.logger.warn '[appoptics_apm/warn] Note that appoptics_rum_footer is deprecated. It is now a no-op and should be removed from your application code.'
|
|
20
|
+
return ''
|
|
21
|
+
end
|
|
22
|
+
alias_method :oboe_rum_footer, :appoptics_rum_footer
|
|
23
|
+
end # Helpers
|
|
24
|
+
|
|
25
|
+
def self.load_initializer
|
|
26
|
+
# Force load the AppOpticsAPM Rails initializer if there is one
|
|
27
|
+
# Prefer appoptics_apm.rb but give priority to the legacy tracelytics.rb if it exists
|
|
28
|
+
if ::Rails::VERSION::MAJOR > 2
|
|
29
|
+
rails_root = ::Rails.root.to_s
|
|
30
|
+
else
|
|
31
|
+
rails_root = RAILS_ROOT.to_s
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
#
|
|
35
|
+
# We've been through 3 initializer names. Try each one.
|
|
36
|
+
#
|
|
37
|
+
if File.exist?("#{rails_root}/config/initializers/tracelytics.rb")
|
|
38
|
+
tr_initializer = "#{rails_root}/config/initializers/tracelytics.rb"
|
|
39
|
+
elsif File.exist?("#{rails_root}/config/initializers/oboe.rb")
|
|
40
|
+
tr_initializer = "#{rails_root}/config/initializers/oboe.rb"
|
|
41
|
+
else
|
|
42
|
+
tr_initializer = "#{rails_root}/config/initializers/appoptics_apm.rb"
|
|
43
|
+
end
|
|
44
|
+
require tr_initializer if File.exist?(tr_initializer)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.load_instrumentation
|
|
48
|
+
# Load the Rails specific instrumentation
|
|
49
|
+
require 'appoptics_apm/frameworks/rails/inst/action_controller'
|
|
50
|
+
require 'appoptics_apm/frameworks/rails/inst/action_view'
|
|
51
|
+
require 'appoptics_apm/frameworks/rails/inst/action_view_30'
|
|
52
|
+
require 'appoptics_apm/frameworks/rails/inst/active_record'
|
|
53
|
+
|
|
54
|
+
AppOpticsAPM.logger.info "[appoptics_apm/rails] AppOpticsAPM gem #{AppOpticsAPM::Version::STRING} successfully loaded."
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.include_helpers
|
|
58
|
+
# TBD: This would make the helpers available to controllers which is occasionally desired.
|
|
59
|
+
# ActiveSupport.on_load(:action_controller) do
|
|
60
|
+
# include AppOpticsAPM::Rails::Helpers
|
|
61
|
+
# end
|
|
62
|
+
ActiveSupport.on_load(:action_view) do
|
|
63
|
+
include AppOpticsAPM::Rails::Helpers
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end # Rails
|
|
67
|
+
end # AppOpticsAPM
|
|
68
|
+
|
|
69
|
+
if defined?(::Rails)
|
|
70
|
+
require 'appoptics_apm/inst/rack'
|
|
71
|
+
|
|
72
|
+
module AppOpticsAPM
|
|
73
|
+
class Railtie < ::Rails::Railtie
|
|
74
|
+
initializer 'appoptics_apm.helpers' do
|
|
75
|
+
AppOpticsAPM::Rails.include_helpers
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
initializer 'appoptics_apm.rack' do |app|
|
|
79
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting rack' if AppOpticsAPM::Config[:verbose]
|
|
80
|
+
app.config.middleware.insert 0, AppOpticsAPM::Rack
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
config.after_initialize do
|
|
84
|
+
AppOpticsAPM.logger = ::Rails.logger if ::Rails.logger && !ENV.key?('APPOPTICS_GEM_TEST')
|
|
85
|
+
|
|
86
|
+
AppOpticsAPM::Inst.load_instrumentation
|
|
87
|
+
AppOpticsAPM::Rails.load_instrumentation
|
|
88
|
+
|
|
89
|
+
# Report __Init after fork when in Heroku
|
|
90
|
+
AppOpticsAPM::API.report_init unless AppOpticsAPM.heroku?
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
#
|
|
7
|
+
# RailsBase
|
|
8
|
+
#
|
|
9
|
+
# This module contains the instrumentation code common to
|
|
10
|
+
# many Rails versions.
|
|
11
|
+
#
|
|
12
|
+
module RailsBase
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
# has_handler?
|
|
16
|
+
#
|
|
17
|
+
# Determins if <tt>exception</tt> has a registered
|
|
18
|
+
# handler via <tt>rescue_from</tt>
|
|
19
|
+
#
|
|
20
|
+
def has_handler?(exception)
|
|
21
|
+
# Don't log exceptions if they have a rescue handler set
|
|
22
|
+
has_handler = false
|
|
23
|
+
rescue_handlers.detect do |klass_name, _handler|
|
|
24
|
+
# Rescue handlers can be specified as strings or constant names
|
|
25
|
+
klass = self.class.const_get(klass_name) rescue nil
|
|
26
|
+
klass ||= klass_name.constantize rescue nil
|
|
27
|
+
has_handler = exception.is_a?(klass) if klass
|
|
28
|
+
end
|
|
29
|
+
has_handler
|
|
30
|
+
rescue => e
|
|
31
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug] Error searching Rails handlers: #{e.message}"
|
|
32
|
+
return false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
#
|
|
36
|
+
# log_rails_error?
|
|
37
|
+
#
|
|
38
|
+
# Determins whether we should log a raised exception to the
|
|
39
|
+
# AppOptics dashboard. This is determined by whether the exception
|
|
40
|
+
# has a rescue handler setup and the value of
|
|
41
|
+
# AppOpticsAPM::Config[:report_rescued_errors]
|
|
42
|
+
#
|
|
43
|
+
def log_rails_error?(exception)
|
|
44
|
+
# As it's perculating up through the layers... make sure that
|
|
45
|
+
# we only report it once.
|
|
46
|
+
return false if exception.instance_variable_get(:@exn_logged)
|
|
47
|
+
|
|
48
|
+
return false if has_handler?(exception) && !AppOpticsAPM::Config[:report_rescued_errors]
|
|
49
|
+
|
|
50
|
+
true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# This method does the logging if we are tracing
|
|
55
|
+
# it `wraps` around the call to the original method
|
|
56
|
+
#
|
|
57
|
+
# This can't use the SDK trace() method because of the log_rails_error?(e) condition
|
|
58
|
+
def trace(layer)
|
|
59
|
+
return yield unless AppOpticsAPM.tracing?
|
|
60
|
+
begin
|
|
61
|
+
AppOpticsAPM::API.log_entry(layer)
|
|
62
|
+
yield
|
|
63
|
+
rescue Exception => e
|
|
64
|
+
AppOpticsAPM::API.log_exception(layer, e) if log_rails_error?(e)
|
|
65
|
+
raise
|
|
66
|
+
ensure
|
|
67
|
+
AppOpticsAPM::API.log_exit(layer)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
#
|
|
73
|
+
# render_with_appoptics
|
|
74
|
+
#
|
|
75
|
+
# Our render wrapper that calls 'add_logging', which will log if we are tracing
|
|
76
|
+
#
|
|
77
|
+
def render_with_appoptics(*args, &blk)
|
|
78
|
+
trace('actionview') do
|
|
79
|
+
render_without_appoptics(*args, &blk)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# ActionController::Base
|
|
87
|
+
if defined?(ActionController::Base) && AppOpticsAPM::Config[:action_controller][:enabled]
|
|
88
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting actioncontroller' if AppOpticsAPM::Config[:verbose]
|
|
89
|
+
require "appoptics_apm/frameworks/rails/inst/action_controller#{Rails::VERSION::MAJOR}"
|
|
90
|
+
if Rails::VERSION::MAJOR >= 5
|
|
91
|
+
ActionController::Base.send(:prepend, ::AppOpticsAPM::Inst::ActionController)
|
|
92
|
+
else
|
|
93
|
+
AppOpticsAPM::Util.send_include(::ActionController::Base, AppOpticsAPM::Inst::ActionController)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# ActionController::API - Rails 5+ or via the rails-api gem
|
|
98
|
+
if defined?(ActionController::API) && AppOpticsAPM::Config[:action_controller_api][:enabled]
|
|
99
|
+
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting actioncontroller api' if AppOpticsAPM::Config[:verbose]
|
|
100
|
+
require "appoptics_apm/frameworks/rails/inst/action_controller_api"
|
|
101
|
+
ActionController::API.send(:prepend, ::AppOpticsAPM::Inst::ActionControllerAPI)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# vim:set expandtab:tabstop=2
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
|
|
4
|
+
module AppOpticsAPM
|
|
5
|
+
module Inst
|
|
6
|
+
#
|
|
7
|
+
# ActionController
|
|
8
|
+
#
|
|
9
|
+
# This modules contains the instrumentation code specific
|
|
10
|
+
# to Rails v3
|
|
11
|
+
#
|
|
12
|
+
module ActionController
|
|
13
|
+
include AppOpticsAPM::Inst::RailsBase
|
|
14
|
+
|
|
15
|
+
def self.included(base)
|
|
16
|
+
base.class_eval do
|
|
17
|
+
alias_method_chain :process, :appoptics
|
|
18
|
+
alias_method_chain :process_action, :appoptics
|
|
19
|
+
alias_method_chain :render, :appoptics
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def process_with_appoptics(*args)
|
|
24
|
+
request.env['appoptics_apm.controller'] = self.class.name
|
|
25
|
+
request.env['appoptics_apm.action'] = self.action_name
|
|
26
|
+
|
|
27
|
+
trace('rails') do
|
|
28
|
+
process_without_appoptics(*args)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def process_action_with_appoptics(*args)
|
|
33
|
+
kvs = {
|
|
34
|
+
:Controller => self.class.name,
|
|
35
|
+
:Action => action_name,
|
|
36
|
+
}
|
|
37
|
+
request.env['appoptics_apm.controller'] = kvs[:Controller]
|
|
38
|
+
request.env['appoptics_apm.action'] = kvs[:Action]
|
|
39
|
+
|
|
40
|
+
return process_action_without_appoptics(*args) unless AppOpticsAPM.tracing?
|
|
41
|
+
begin
|
|
42
|
+
kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:action_controller][:collect_backtraces]
|
|
43
|
+
AppOpticsAPM::API.log(nil, 'info', kvs)
|
|
44
|
+
|
|
45
|
+
process_action_without_appoptics(*args)
|
|
46
|
+
rescue Exception
|
|
47
|
+
kvs[:Status] = 500
|
|
48
|
+
kvs.delete(:Backtrace)
|
|
49
|
+
AppOpticsAPM::API.log(nil, 'info', kvs)
|
|
50
|
+
raise
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|