solarwinds_apm 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +5 -0
  3. data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
  4. data/.github/workflows/build_and_release_gem.yml +112 -0
  5. data/.github/workflows/build_for_packagecloud.yml +70 -0
  6. data/.github/workflows/docker-images.yml +47 -0
  7. data/.github/workflows/run_cpluplus_tests.yml +73 -0
  8. data/.github/workflows/run_tests.yml +155 -0
  9. data/.github/workflows/scripts/test_install.rb +23 -0
  10. data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
  11. data/.github/workflows/test_on_4_linux.yml +161 -0
  12. data/.gitignore +39 -0
  13. data/.rubocop.yml +29 -0
  14. data/.yardopts +7 -0
  15. data/CHANGELOG.md +769 -0
  16. data/CONFIG.md +31 -0
  17. data/Gemfile +14 -0
  18. data/LICENSE +202 -0
  19. data/README.md +383 -0
  20. data/bin/solarwinds_apm_config +15 -0
  21. data/examples/prepend.rb +13 -0
  22. data/examples/sdk_examples.rb +158 -0
  23. data/ext/oboe_metal/README.md +69 -0
  24. data/ext/oboe_metal/extconf.rb +141 -0
  25. data/ext/oboe_metal/extconf_local.rb +75 -0
  26. data/ext/oboe_metal/lib/.keep +0 -0
  27. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
  28. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
  29. data/ext/oboe_metal/noop/noop.c +8 -0
  30. data/ext/oboe_metal/src/README.md +6 -0
  31. data/ext/oboe_metal/src/VERSION +2 -0
  32. data/ext/oboe_metal/src/bson/bson.h +220 -0
  33. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  34. data/ext/oboe_metal/src/frames.cc +247 -0
  35. data/ext/oboe_metal/src/frames.h +40 -0
  36. data/ext/oboe_metal/src/init_solarwinds_apm.cc +21 -0
  37. data/ext/oboe_metal/src/logging.cc +95 -0
  38. data/ext/oboe_metal/src/logging.h +35 -0
  39. data/ext/oboe_metal/src/oboe.h +1169 -0
  40. data/ext/oboe_metal/src/oboe_api.cpp +658 -0
  41. data/ext/oboe_metal/src/oboe_api.hpp +433 -0
  42. data/ext/oboe_metal/src/oboe_debug.h +59 -0
  43. data/ext/oboe_metal/src/oboe_swig_wrap.cc +7562 -0
  44. data/ext/oboe_metal/src/profiling.cc +435 -0
  45. data/ext/oboe_metal/src/profiling.h +78 -0
  46. data/ext/oboe_metal/test/CMakeLists.txt +53 -0
  47. data/ext/oboe_metal/test/FindGMock.cmake +43 -0
  48. data/ext/oboe_metal/test/README.md +56 -0
  49. data/ext/oboe_metal/test/frames_test.cc +164 -0
  50. data/ext/oboe_metal/test/profiling_test.cc +93 -0
  51. data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
  52. data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
  53. data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
  54. data/ext/oboe_metal/test/test.h +11 -0
  55. data/ext/oboe_metal/test/test_main.cc +32 -0
  56. data/init.rb +4 -0
  57. data/lib/oboe.rb +7 -0
  58. data/lib/oboe_metal.rb +172 -0
  59. data/lib/rails/generators/solarwinds_apm/install_generator.rb +47 -0
  60. data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +424 -0
  61. data/lib/solarwinds_apm/api/layerinit.rb +41 -0
  62. data/lib/solarwinds_apm/api/logging.rb +356 -0
  63. data/lib/solarwinds_apm/api/memcache.rb +37 -0
  64. data/lib/solarwinds_apm/api/metrics.rb +63 -0
  65. data/lib/solarwinds_apm/api/util.rb +98 -0
  66. data/lib/solarwinds_apm/api.rb +21 -0
  67. data/lib/solarwinds_apm/base.rb +160 -0
  68. data/lib/solarwinds_apm/config.rb +301 -0
  69. data/lib/solarwinds_apm/frameworks/grape.rb +96 -0
  70. data/lib/solarwinds_apm/frameworks/padrino.rb +78 -0
  71. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller.rb +100 -0
  72. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  73. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  74. data/lib/solarwinds_apm/frameworks/rails/inst/action_view.rb +88 -0
  75. data/lib/solarwinds_apm/frameworks/rails/inst/active_record.rb +26 -0
  76. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
  77. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +22 -0
  78. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +103 -0
  79. data/lib/solarwinds_apm/frameworks/rails/inst/logger_formatters.rb +14 -0
  80. data/lib/solarwinds_apm/frameworks/rails.rb +100 -0
  81. data/lib/solarwinds_apm/frameworks/sinatra.rb +96 -0
  82. data/lib/solarwinds_apm/inst/bunny-client.rb +157 -0
  83. data/lib/solarwinds_apm/inst/bunny-consumer.rb +102 -0
  84. data/lib/solarwinds_apm/inst/curb.rb +288 -0
  85. data/lib/solarwinds_apm/inst/dalli.rb +89 -0
  86. data/lib/solarwinds_apm/inst/delayed_job.rb +100 -0
  87. data/lib/solarwinds_apm/inst/excon.rb +113 -0
  88. data/lib/solarwinds_apm/inst/faraday.rb +96 -0
  89. data/lib/solarwinds_apm/inst/graphql.rb +206 -0
  90. data/lib/solarwinds_apm/inst/grpc_client.rb +147 -0
  91. data/lib/solarwinds_apm/inst/grpc_server.rb +119 -0
  92. data/lib/solarwinds_apm/inst/httpclient.rb +181 -0
  93. data/lib/solarwinds_apm/inst/logger_formatter.rb +46 -0
  94. data/lib/solarwinds_apm/inst/logging_log_event.rb +24 -0
  95. data/lib/solarwinds_apm/inst/lumberjack_formatter.rb +9 -0
  96. data/lib/solarwinds_apm/inst/memcached.rb +86 -0
  97. data/lib/solarwinds_apm/inst/mongo.rb +246 -0
  98. data/lib/solarwinds_apm/inst/mongo2.rb +225 -0
  99. data/lib/solarwinds_apm/inst/moped.rb +466 -0
  100. data/lib/solarwinds_apm/inst/net_http.rb +60 -0
  101. data/lib/solarwinds_apm/inst/rack.rb +217 -0
  102. data/lib/solarwinds_apm/inst/rack_cache.rb +35 -0
  103. data/lib/solarwinds_apm/inst/redis.rb +273 -0
  104. data/lib/solarwinds_apm/inst/resque.rb +129 -0
  105. data/lib/solarwinds_apm/inst/rest-client.rb +43 -0
  106. data/lib/solarwinds_apm/inst/sequel.rb +241 -0
  107. data/lib/solarwinds_apm/inst/sidekiq-client.rb +63 -0
  108. data/lib/solarwinds_apm/inst/sidekiq-worker.rb +64 -0
  109. data/lib/solarwinds_apm/inst/typhoeus.rb +90 -0
  110. data/lib/solarwinds_apm/instrumentation.rb +22 -0
  111. data/lib/solarwinds_apm/loading.rb +65 -0
  112. data/lib/solarwinds_apm/logger.rb +14 -0
  113. data/lib/solarwinds_apm/noop/README.md +9 -0
  114. data/lib/solarwinds_apm/noop/context.rb +26 -0
  115. data/lib/solarwinds_apm/noop/metadata.rb +25 -0
  116. data/lib/solarwinds_apm/noop/profiling.rb +21 -0
  117. data/lib/solarwinds_apm/oboe_init_options.rb +191 -0
  118. data/lib/solarwinds_apm/ruby.rb +35 -0
  119. data/lib/solarwinds_apm/sdk/current_trace_info.rb +123 -0
  120. data/lib/solarwinds_apm/sdk/custom_metrics.rb +94 -0
  121. data/lib/solarwinds_apm/sdk/logging.rb +37 -0
  122. data/lib/solarwinds_apm/sdk/trace_context_headers.rb +69 -0
  123. data/lib/solarwinds_apm/sdk/tracing.rb +432 -0
  124. data/lib/solarwinds_apm/support/profiling.rb +22 -0
  125. data/lib/solarwinds_apm/support/trace_context.rb +53 -0
  126. data/lib/solarwinds_apm/support/trace_state.rb +69 -0
  127. data/lib/solarwinds_apm/support/trace_string.rb +89 -0
  128. data/lib/solarwinds_apm/support/transaction_metrics.rb +67 -0
  129. data/lib/solarwinds_apm/support/transaction_settings.rb +233 -0
  130. data/lib/solarwinds_apm/support/x_trace_options.rb +113 -0
  131. data/lib/solarwinds_apm/support.rb +12 -0
  132. data/lib/solarwinds_apm/support_report.rb +113 -0
  133. data/lib/solarwinds_apm/test.rb +165 -0
  134. data/lib/solarwinds_apm/thread_local.rb +26 -0
  135. data/lib/solarwinds_apm/util.rb +334 -0
  136. data/lib/solarwinds_apm/version.rb +17 -0
  137. data/lib/solarwinds_apm.rb +72 -0
  138. data/log/.keep +0 -0
  139. data/log/postgresql/.keep +0 -0
  140. data/solarwinds_apm.gemspec +52 -0
  141. data/yardoc_frontpage.md +24 -0
  142. metadata +228 -0
@@ -0,0 +1,100 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
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
+ SolarWindsAPM.logger.debug "[solarwinds_apm/debug] Error searching Rails handlers: #{e.message}"
32
+ return false
33
+ end
34
+
35
+ #
36
+ # log_rails_error?
37
+ #
38
+ # Determines whether we should log a raised exception to the
39
+ # SolarWinds dashboard. This is determined by whether the exception
40
+ # has a rescue handler setup and the value of
41
+ # SolarWindsAPM::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) && !SolarWindsAPM::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 SolarWindsAPM.tracing?
60
+ begin
61
+ SolarWindsAPM::API.log_entry(layer)
62
+ yield
63
+ rescue Exception => e
64
+ SolarWindsAPM::API.log_exception(layer, e) if log_rails_error?(e)
65
+ raise
66
+ ensure
67
+ SolarWindsAPM::API.log_exit(layer)
68
+ end
69
+ end
70
+
71
+
72
+ #
73
+ # render_with_sw_apm
74
+ #
75
+ # Our render wrapper that calls 'add_logging', which will log if we are tracing
76
+ #
77
+ def render_with_sw_apm(*args, &blk)
78
+ trace('actionview') do
79
+ render_without_sw_apm(*args, &blk)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ # ActionController::Base
87
+ if defined?(ActionController::Base) && SolarWindsAPM::Config[:action_controller][:enabled]
88
+ SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting actioncontroller' if SolarWindsAPM::Config[:verbose]
89
+ require "solarwinds_apm/frameworks/rails/inst/action_controller5"
90
+ ActionController::Base.send(:prepend, ::SolarWindsAPM::Inst::ActionController)
91
+ end
92
+
93
+ # ActionController::API
94
+ if defined?(ActionController::API) && SolarWindsAPM::Config[:action_controller_api][:enabled]
95
+ SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting actioncontroller api' if SolarWindsAPM::Config[:verbose]
96
+ require "solarwinds_apm/frameworks/rails/inst/action_controller_api"
97
+ ActionController::API.send(:prepend, ::SolarWindsAPM::Inst::ActionControllerAPI)
98
+ end
99
+
100
+ # vim:set expandtab:tabstop=2
@@ -0,0 +1,50 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ module Inst
6
+ #
7
+ # ActionController
8
+ #
9
+ # This modules contains the instrumentation code specific
10
+ # to Rails v5
11
+ #
12
+ module ActionController
13
+ include SolarWindsAPM::Inst::RailsBase
14
+
15
+ def process_action(method_name, *args)
16
+ kvs = {
17
+ :Controller => self.class.name,
18
+ :Action => self.action_name,
19
+ }
20
+ request.env['solarwinds_apm.controller'] = kvs[:Controller]
21
+ request.env['solarwinds_apm.action'] = kvs[:Action]
22
+
23
+ return super(method_name, *args) unless SolarWindsAPM.tracing?
24
+ begin
25
+ kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:action_controller][:collect_backtraces]
26
+
27
+ SolarWindsAPM::API.log_entry('rails', kvs)
28
+ super(method_name, *args)
29
+
30
+ rescue Exception => e
31
+ SolarWindsAPM::API.log_exception('rails', e) if log_rails_error?(e)
32
+ raise
33
+ ensure
34
+ SolarWindsAPM::API.log_exit('rails')
35
+ end
36
+ end
37
+
38
+ #
39
+ # render
40
+ #
41
+ # Our render wrapper that calls 'trace', which will log if we are tracing
42
+ #
43
+ def render(*args, &blk)
44
+ trace('actionview') do
45
+ super(*args, &blk)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,50 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ module Inst
6
+ #
7
+ # ActionController
8
+ #
9
+ # This modules contains the instrumentation code specific
10
+ # to Rails v5.
11
+ #
12
+ module ActionControllerAPI
13
+ include SolarWindsAPM::Inst::RailsBase
14
+
15
+ def process_action(method_name, *args)
16
+ kvs = {
17
+ :Controller => self.class.name,
18
+ :Action => self.action_name
19
+ }
20
+ request.env['solarwinds_apm.controller'] = kvs[:Controller]
21
+ request.env['solarwinds_apm.action'] = kvs[:Action]
22
+
23
+ return super(method_name, *args) unless SolarWindsAPM.tracing?
24
+ begin
25
+ kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:action_controller_api][:collect_backtraces]
26
+
27
+ SolarWindsAPM::API.log_entry('rails-api', kvs)
28
+ super(method_name, *args)
29
+
30
+ rescue Exception => e
31
+ SolarWindsAPM::API.log_exception('rails', e) if log_rails_error?(e)
32
+ raise
33
+ ensure
34
+ SolarWindsAPM::API.log_exit('rails-api')
35
+ end
36
+ end
37
+
38
+ #
39
+ # render
40
+ #
41
+ # Our render wrapper that calls 'trace', which will log if we are tracing
42
+ #
43
+ def render(*args, &blk)
44
+ trace('actionview') do
45
+ super(*args, &blk)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,88 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ if defined?(ActionView::Base) && SolarWindsAPM::Config[:action_view][:enabled]
5
+
6
+ if Rails::VERSION::MAJOR >= 4
7
+
8
+ SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting actionview' if SolarWindsAPM::Config[:verbose]
9
+ if ActionView.version >= Gem::Version.new('6.1.0') # the methods changed in this version
10
+
11
+ ActionView::PartialRenderer.class_eval do
12
+ alias :render_partial_template_without_sw_apm :render_partial_template
13
+
14
+ def render_partial_template(*args)
15
+ _, _, template, _, _ = args
16
+ entry_kvs = {}
17
+ begin
18
+ entry_kvs[:Partial] = template.virtual_path
19
+ rescue => e
20
+ SolarWindsAPM.logger.debug "[solarwinds_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if SolarWindsAPM::Config[:verbose]
21
+ end
22
+ SolarWindsAPM::SDK.trace(:partial, kvs: entry_kvs) do
23
+ entry_kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:action_view][:collect_backtraces]
24
+ render_partial_template_without_sw_apm(*args)
25
+ end
26
+ end
27
+ end
28
+
29
+ ActionView::CollectionRenderer.class_eval do
30
+ alias :render_collection_without_sw_apm :render_collection
31
+
32
+ def render_collection(*args)
33
+ _, _, _, template, _, _ = args
34
+ entry_kvs = {}
35
+ begin
36
+ entry_kvs[:Partial] = template.virtual_path
37
+ rescue => e
38
+ SolarWindsAPM.logger.debug "[solarwinds_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if SolarWindsAPM::Config[:verbose]
39
+ end
40
+ SolarWindsAPM::SDK.trace(:collection, kvs: entry_kvs) do
41
+ entry_kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:action_view][:collect_backtraces]
42
+ render_collection_without_sw_apm(*args)
43
+ end
44
+ end
45
+ end
46
+
47
+ else # Rails < 6.1.0
48
+
49
+ ActionView::PartialRenderer.class_eval do
50
+ alias :render_partial_without_sw_apm :render_partial
51
+ def render_partial(*args)
52
+ template = @template || args[1]
53
+ entry_kvs = {}
54
+ begin
55
+ entry_kvs[:Partial] = template.virtual_path
56
+ # entry_kvs[:Partial] = SolarWindsAPM::Util.prettify(@options[:partial]) if @options.is_a?(Hash)
57
+ rescue => e
58
+ SolarWindsAPM.logger.debug "[solarwinds_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if SolarWindsAPM::Config[:verbose]
59
+ end
60
+
61
+ SolarWindsAPM::SDK.trace('partial', kvs: entry_kvs) do
62
+ entry_kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:action_view][:collect_backtraces]
63
+ render_partial_without_sw_apm(*args)
64
+ end
65
+ end
66
+
67
+ alias :render_collection_without_sw_apm :render_collection
68
+ def render_collection(*args)
69
+ template = @template || args[1]
70
+ entry_kvs = {}
71
+ begin
72
+ entry_kvs[:Partial] = template.virtual_path
73
+ rescue => e
74
+ SolarWindsAPM.logger.debug "[solarwinds_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if SolarWindsAPM::Config[:verbose]
75
+ end
76
+
77
+ SolarWindsAPM::SDK.trace('collection', kvs: entry_kvs) do
78
+ entry_kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:action_view][:collect_backtraces]
79
+ render_collection_without_sw_apm(*args)
80
+ end
81
+ end
82
+ end
83
+
84
+ end
85
+ end
86
+ end
87
+
88
+ # vim:set expandtab:tabstop=2
@@ -0,0 +1,26 @@
1
+ # Copyright (c) SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'solarwinds_apm/frameworks/rails/inst/connection_adapters/mysql2'
5
+ require 'solarwinds_apm/frameworks/rails/inst/connection_adapters/postgresql'
6
+
7
+ if SolarWindsAPM::Config[:active_record][:enabled]
8
+ begin
9
+ SolarWindsAPM::Config[:verbose]
10
+ adapter = if ActiveRecord::Base.respond_to?(:connection_db_config)
11
+ ActiveRecord::Base.connection_db_config.adapter
12
+ else
13
+ ActiveRecord::Base.connection_config[:adapter]
14
+ end
15
+
16
+ require 'solarwinds_apm/frameworks/rails/inst/connection_adapters/utils5x'
17
+
18
+ SolarWindsAPM::Inst::ConnectionAdapters::FlavorInitializers.mysql2 if adapter == 'mysql2'
19
+ SolarWindsAPM::Inst::ConnectionAdapters::FlavorInitializers.postgresql if adapter =~ /postgresql|postgis/i
20
+
21
+ rescue StandardError => e
22
+ SolarWindsAPM.logger.error "[solarwinds_apm/error] SolarWindsAPM/ActiveRecord error: #{e.inspect}"
23
+ SolarWindsAPM.logger.debug e.backtrace.join("\n")
24
+ end
25
+ end
26
+ # vim:set expandtab:tabstop=2
@@ -0,0 +1,29 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ module Inst
6
+ module ConnectionAdapters
7
+ module FlavorInitializers
8
+ def self.mysql2
9
+ SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting activerecord mysql2adapter' if SolarWindsAPM::Config[:verbose]
10
+
11
+ SolarWindsAPM::Util.send_include(ActiveRecord::ConnectionAdapters::Mysql2Adapter,
12
+ SolarWindsAPM::Inst::ConnectionAdapters::Utils)
13
+
14
+ if (ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0) ||
15
+ ActiveRecord::VERSION::MAJOR == 2
16
+ # ActiveRecord 3.0 and prior
17
+ SolarWindsAPM::Util.method_alias(ActiveRecord::ConnectionAdapters::Mysql2Adapter, :execute)
18
+ else
19
+ # ActiveRecord 3.1 and above
20
+ SolarWindsAPM::Util.method_alias(ActiveRecord::ConnectionAdapters::Mysql2Adapter, :exec_insert)
21
+ SolarWindsAPM::Util.method_alias(ActiveRecord::ConnectionAdapters::Mysql2Adapter, :exec_query)
22
+ SolarWindsAPM::Util.method_alias(ActiveRecord::ConnectionAdapters::Mysql2Adapter, :exec_update)
23
+ SolarWindsAPM::Util.method_alias(ActiveRecord::ConnectionAdapters::Mysql2Adapter, :exec_delete)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ module Inst
6
+ module ConnectionAdapters
7
+ module FlavorInitializers
8
+ def self.postgresql
9
+
10
+ SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting activerecord postgresqladapter' if SolarWindsAPM::Config[:verbose]
11
+
12
+ SolarWindsAPM::Util.send_include(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter,
13
+ SolarWindsAPM::Inst::ConnectionAdapters::Utils)
14
+
15
+ SolarWindsAPM::Util.method_alias(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter, :exec_query)
16
+ SolarWindsAPM::Util.method_alias(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter, :exec_update)
17
+ SolarWindsAPM::Util.method_alias(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter, :exec_delete)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,103 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ module Inst
6
+ module ConnectionAdapters
7
+ module Utils
8
+
9
+ def exec_query_with_sw_apm(*args, **args2)
10
+ trace_wrap(*args) do |args|
11
+ exec_query_without_sw_apm(*args, **args2)
12
+ end
13
+ end
14
+
15
+ # need to instrument them all
16
+ def exec_insert_with_sw_apm(*args)
17
+ trace_wrap(*args) do |args|
18
+ exec_insert_without_sw_apm(*args)
19
+ end
20
+ end
21
+
22
+ def exec_delete_with_sw_apm(*args)
23
+ trace_wrap(*args) do |args|
24
+ exec_delete_without_sw_apm(*args)
25
+ end
26
+ end
27
+
28
+ def exec_update_with_sw_apm(*args)
29
+ trace_wrap(*args) do |args|
30
+ exec_update_without_sw_apm(*args)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def trace_wrap(*args)
37
+ sql, name, binds, _ = args
38
+ kvs = {}
39
+ args[0] = SolarWindsAPM::SDK.current_trace_info.add_traceparent_to_sql(sql, kvs)
40
+ if SolarWindsAPM.tracing? && !ignore_payload?(name)
41
+ assign_kvs(sql, kvs, name, binds || [])
42
+ # use protect_op to avoid double tracing in mysql2
43
+ SolarWindsAPM::SDK.trace('activerecord', kvs: kvs, protect_op: :ar_started) do
44
+ yield args
45
+ end
46
+ else
47
+ yield args
48
+ end
49
+ end
50
+
51
+ def assign_kvs(sql, kvs, name = nil, binds = [])
52
+ sql = SolarWindsAPM::Util.remove_traceparent(sql.to_s)
53
+ if SolarWindsAPM::Config[:sanitize_sql]
54
+ # Sanitize SQL and don't report binds
55
+ kvs[:Query] = SolarWindsAPM::Util.sanitize_sql(sql)
56
+ else
57
+ # Report raw SQL or name of statement and any binds if they exist
58
+ kvs[:Query] = sql
59
+ if binds && !binds.empty?
60
+ kvs[:QueryArgs] = binds.map(&:value)
61
+ end
62
+ end
63
+
64
+ kvs[:Name] = name.to_s if name
65
+ if SolarWindsAPM::Config[:active_record] && SolarWindsAPM::Config[:active_record][:collect_backtraces]
66
+ kvs[:Backtrace] = SolarWindsAPM::API.backtrace
67
+ end
68
+
69
+ if ActiveRecord::Base.respond_to?(:connection_db_config)
70
+ config = ActiveRecord::Base.connection_db_config.configuration_hash
71
+ else
72
+ config = ActiveRecord::Base.connection_config
73
+ end
74
+
75
+ if config
76
+ kvs[:Database] = config[:database] if config.key?(:database)
77
+ kvs[:RemoteHost] = config[:host] if config.key?(:host)
78
+ adapter_name = config[:adapter]
79
+
80
+ case adapter_name
81
+ when /mysql/i
82
+ kvs[:Flavor] = 'mysql'
83
+ when /^postgres|^postgis/i
84
+ kvs[:Flavor] = 'postgresql'
85
+ end
86
+ end
87
+ rescue StandardError => e
88
+ SolarWindsAPM.logger.debug "[solarwinds_apm/rails] Exception raised capturing ActiveRecord KVs: #{e.inspect}"
89
+ SolarWindsAPM.logger.debug e.backtrace.join('\n')
90
+ end
91
+
92
+ # We don't want to trace framework caches.
93
+ # Only instrument SQL that directly hits the database.
94
+ def ignore_payload?(name)
95
+ %w(SCHEMA EXPLAIN CACHE).include?(name.to_s) ||
96
+ (name && name.to_sym == :skip_logging) ||
97
+ name == 'ActiveRecord::SchemaMigration Load'
98
+ end
99
+
100
+ end # Utils
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,14 @@
1
+ # Copyright (c) 2019 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ if SolarWindsAPM.loaded && defined?(ActiveSupport::Logger::SimpleFormatter)
5
+ # even though SimpleFormatter inherits from Logger,
6
+ # this will not append trace info twice,
7
+ # because SimpleFormatter#call does not call super
8
+ ActiveSupport::Logger::SimpleFormatter.send(:prepend, SolarWindsAPM::Logger::Formatter)
9
+ end
10
+
11
+
12
+ if SolarWindsAPM.loaded && defined?(ActiveSupport::TaggedLogging::Formatter)
13
+ ActiveSupport::TaggedLogging::Formatter.send(:prepend, SolarWindsAPM::Logger::Formatter)
14
+ end
@@ -0,0 +1,100 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require_relative '../../../lib/solarwinds_apm/inst/logger_formatter'
5
+
6
+ module SolarWindsAPM
7
+ module Rails
8
+ module Helpers
9
+ extend ActiveSupport::Concern if defined?(::Rails)
10
+
11
+ # Deprecated
12
+ # no usages
13
+ def sw_apm_rum_header
14
+ SolarWindsAPM.logger.warn '[solarwinds_apm/warn] Note that sw_apm_rum_header is deprecated. It is now a no-op and should be removed from your application code.'
15
+ return ''
16
+ end
17
+ alias_method :oboe_rum_header, :sw_apm_rum_header
18
+
19
+ # Deprecated
20
+ def sw_apm_rum_footer
21
+ SolarWindsAPM.logger.warn '[solarwinds_apm/warn] Note that sw_apm_rum_footer is deprecated. It is now a no-op and should be removed from your application code.'
22
+ return ''
23
+ end
24
+ alias_method :oboe_rum_footer, :sw_apm_rum_footer
25
+ end # Helpers
26
+
27
+ def self.load_initializer
28
+ # Force load the SolarWindsAPM Rails initializer if there is one
29
+ # Prefer solarwinds_apm.rb but give priority to the legacy tracelytics.rb if it exists
30
+ if ::Rails::VERSION::MAJOR > 2
31
+ rails_root = ::Rails.root.to_s
32
+ else
33
+ rails_root = RAILS_ROOT.to_s
34
+ end
35
+
36
+ #
37
+ # We've been through 3 initializer names. Try each one.
38
+ #
39
+ if File.exist?("#{rails_root}/config/initializers/tracelytics.rb")
40
+ tr_initializer = "#{rails_root}/config/initializers/tracelytics.rb"
41
+ elsif File.exist?("#{rails_root}/config/initializers/oboe.rb")
42
+ tr_initializer = "#{rails_root}/config/initializers/oboe.rb"
43
+ else
44
+ tr_initializer = "#{rails_root}/config/initializers/solarwinds_apm.rb"
45
+ end
46
+ require tr_initializer if File.exist?(tr_initializer)
47
+ end
48
+
49
+ def self.load_instrumentation
50
+ # Load the Rails specific instrumentation
51
+ require 'solarwinds_apm/frameworks/rails/inst/action_controller'
52
+ require 'solarwinds_apm/frameworks/rails/inst/action_view'
53
+ require 'solarwinds_apm/frameworks/rails/inst/active_record'
54
+ require 'solarwinds_apm/frameworks/rails/inst/logger_formatters'
55
+
56
+ SolarWindsAPM.logger.info "[solarwinds_apm/rails] SolarWindsAPM gem #{SolarWindsAPM::Version::STRING} successfully loaded."
57
+ end
58
+
59
+ def self.include_helpers
60
+ # TBD: This would make the helpers available to controllers which is occasionally desired.
61
+ # ActiveSupport.on_load(:action_controller) do
62
+ # include SolarWindsAPM::Rails::Helpers
63
+ # end
64
+ ActiveSupport.on_load(:action_view) do
65
+ include SolarWindsAPM::Rails::Helpers
66
+ end
67
+ end
68
+ end # Rails
69
+ end # SolarWindsAPM
70
+
71
+ if defined?(::Rails)
72
+ require 'solarwinds_apm/inst/rack'
73
+
74
+ module SolarWindsAPM
75
+ class Railtie < ::Rails::Railtie
76
+ initializer 'solarwinds_apm.helpers' do
77
+ SolarWindsAPM::Rails.include_helpers
78
+ end
79
+
80
+ initializer 'solarwinds_apm.controller', before: 'wicked_pdf.register' do
81
+ SolarWindsAPM::Rails.load_instrumentation
82
+ end
83
+
84
+ initializer 'solarwinds_apm.rack' do |app|
85
+ SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting rack' if SolarWindsAPM::Config[:verbose]
86
+ app.config.middleware.insert 0, SolarWindsAPM::Rack
87
+ end
88
+
89
+ config.after_initialize do
90
+ SolarWindsAPM.logger = ::Rails.logger if ::Rails.logger && !ENV.key?('SW_APM_GEM_TEST')
91
+
92
+ SolarWindsAPM::Inst.load_instrumentation
93
+ # SolarWindsAPM::Rails.load_instrumentation
94
+
95
+ # Report __Init after fork when in Heroku
96
+ SolarWindsAPM::API.report_init unless SolarWindsAPM.heroku?
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,96 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ module Sinatra
6
+ module Base
7
+ def self.included(klass)
8
+ SolarWindsAPM::Util.method_alias(klass, :dispatch!, ::Sinatra::Base)
9
+ SolarWindsAPM::Util.method_alias(klass, :handle_exception!, ::Sinatra::Base)
10
+ end
11
+
12
+ def dispatch_with_sw_apm
13
+
14
+ SolarWindsAPM::API.log_entry('sinatra', {})
15
+
16
+ response = dispatch_without_sw_apm
17
+
18
+ # Report Controller/Action and transaction as best possible
19
+ report_kvs = {}
20
+ report_kvs[:Controller] = self.class
21
+ report_kvs[:Action] = env['sinatra.route']
22
+ env['solarwinds_apm.controller'] = report_kvs[:Controller]
23
+ env['solarwinds_apm.action'] = report_kvs[:Action]
24
+
25
+ response
26
+ rescue => e
27
+ SolarWindsAPM::API.log_exception('sinatra', e)
28
+ raise e
29
+ ensure
30
+ report_kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:sinatra][:collect_backtraces]
31
+ SolarWindsAPM::API.log_exit('sinatra', report_kvs)
32
+ end
33
+
34
+ def handle_exception_with_sw_apm(boom)
35
+ SolarWindsAPM::API.log_exception(:sinatra, boom)
36
+ handle_exception_without_sw_apm(boom)
37
+ end
38
+
39
+ def sw_apm_rum_header
40
+ SolarWindsAPM.logger.warn '[solarwinds_apm/warn] Note that sw_apm_rum_header is deprecated. It is now a no-op and should be removed from your application code.'
41
+ return ''
42
+ end
43
+ alias_method :oboe_rum_header, :sw_apm_rum_header
44
+
45
+ def sw_apm_rum_footer
46
+ SolarWindsAPM.logger.warn '[solarwinds_apm/warn] Note that sw_apm_rum_footer is deprecated. It is now a no-op and should be removed from your application code.'
47
+ return ''
48
+ end
49
+ alias_method :oboe_rum_footer, :sw_apm_rum_footer
50
+ end
51
+
52
+ module Templates
53
+ def self.included(klass)
54
+ SolarWindsAPM::Util.method_alias(klass, :render, ::Sinatra::Templates)
55
+ end
56
+
57
+ def render_with_sw_apm(engine, data, options = {}, locals = {}, &block)
58
+ if SolarWindsAPM.tracing?
59
+ report_kvs = {}
60
+
61
+ report_kvs[:engine] = engine
62
+ report_kvs[:template] = data
63
+
64
+ SolarWindsAPM::SDK.trace(:sinatra_render, kvs: report_kvs, protect_op: :sinatra_render) do
65
+ report_kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:sinatra][:collect_backtraces]
66
+ render_without_sw_apm(engine, data, options, locals, &block)
67
+ end
68
+ else
69
+ render_without_sw_apm(engine, data, options, locals, &block)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ if defined?(Sinatra) && SolarWindsAPM::Config[:sinatra][:enabled]
77
+ require 'solarwinds_apm/inst/rack'
78
+
79
+ SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting Sinatra' if SolarWindsAPM::Config[:verbose]
80
+
81
+ SolarWindsAPM::Inst.load_instrumentation
82
+
83
+ Sinatra::Base.use SolarWindsAPM::Rack
84
+
85
+ # When in the gem TEST environment, we load this instrumentation regardless.
86
+ # Otherwise, only when Padrino isn't around.
87
+ unless defined?(Padrino) && !ENV.key?('SW_APM_GEM_TEST')
88
+ # Padrino has 'enhanced' routes and rendering so the Sinatra
89
+ # instrumentation won't work anyways. Only load for pure Sinatra apps.
90
+ SolarWindsAPM::Util.send_include(Sinatra::Base, SolarWindsAPM::Sinatra::Base)
91
+ SolarWindsAPM::Util.send_include(Sinatra::Templates, SolarWindsAPM::Sinatra::Templates)
92
+
93
+ # Report __Init after fork when in Heroku
94
+ SolarWindsAPM::API.report_init unless SolarWindsAPM.heroku?
95
+ end
96
+ end