appoptics_apm 4.2.3 → 4.2.4

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 (55) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +5 -0
  3. data/.travis.yml +15 -12
  4. data/Gemfile +0 -1
  5. data/README.md +7 -38
  6. data/Rakefile +17 -1
  7. data/appoptics_apm.gemspec +2 -0
  8. data/{build_gems.sh → build_gem.sh} +1 -1
  9. data/build_gem_upload_to_packagecloud.sh +15 -0
  10. data/examples/SDK/01_basic_tracing.rb +1 -1
  11. data/ext/oboe_metal/src/VERSION +1 -1
  12. data/ext/oboe_metal/src/bson/bson.h +1 -2
  13. data/ext/oboe_metal/src/bson/platform_hacks.h +4 -4
  14. data/lib/appoptics_apm.rb +28 -30
  15. data/lib/appoptics_apm/api/logging.rb +13 -27
  16. data/lib/appoptics_apm/api/metrics.rb +25 -11
  17. data/lib/appoptics_apm/api/profiling.rb +6 -11
  18. data/lib/appoptics_apm/api/tracing.rb +3 -24
  19. data/lib/appoptics_apm/base.rb +7 -32
  20. data/lib/appoptics_apm/config.rb +26 -4
  21. data/lib/appoptics_apm/frameworks/grape.rb +10 -8
  22. data/lib/appoptics_apm/frameworks/padrino.rb +3 -0
  23. data/lib/appoptics_apm/frameworks/rails.rb +20 -42
  24. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +4 -6
  25. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +1 -1
  26. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +1 -1
  27. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +1 -1
  28. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +1 -9
  29. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +1 -1
  30. data/lib/appoptics_apm/frameworks/sinatra.rb +4 -1
  31. data/lib/appoptics_apm/inst/bunny-client.rb +16 -18
  32. data/lib/appoptics_apm/inst/memcached.rb +6 -10
  33. data/lib/appoptics_apm/inst/moped.rb +1 -1
  34. data/lib/appoptics_apm/inst/rack.rb +13 -15
  35. data/lib/appoptics_apm/inst/sidekiq-worker.rb +1 -1
  36. data/lib/appoptics_apm/inst/typhoeus.rb +4 -2
  37. data/lib/appoptics_apm/loading.rb +1 -1
  38. data/lib/appoptics_apm/sdk.rb +48 -50
  39. data/lib/appoptics_apm/version.rb +1 -1
  40. data/lib/appoptics_apm/xtrace.rb +1 -1
  41. data/lib/oboe_metal.rb +13 -11
  42. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +45 -7
  43. metadata +5 -16
  44. data/.codeclimate.yml +0 -43
  45. data/Dockerfile +0 -41
  46. data/Dockerfile_alpine +0 -66
  47. data/Dockerfile_test +0 -73
  48. data/config/initializers/.keep +0 -0
  49. data/docker-compose.yml +0 -95
  50. data/ext/oboe_metal/tests/test.rb +0 -11
  51. data/lib/appoptics_apm/frameworks/rails/inst/action_controller2.rb +0 -61
  52. data/lib/appoptics_apm/frameworks/rails/inst/action_view_2x.rb +0 -56
  53. data/ruby_setup.sh +0 -49
  54. data/run_docker_build_gem_upload_to_packagecloud.sh +0 -20
  55. data/run_tests_docker.rb +0 -38
@@ -7,28 +7,42 @@ module AppOpticsAPM
7
7
  # it checks if it can send metrics with the current transaction name
8
8
  # or a default transaction name and sets the transaction name accordingly
9
9
  #
10
- # === Arguments
10
+ # === Arguments:
11
11
  #
12
12
  # * +span+ the name of the current span (used to construct a transaction name if none is defined)
13
13
  # * +kvs+ A hash containing key/value pairs, only the value of :TransactionName will be relevant
14
14
  #
15
- # Returns the result of the block.
15
+ # === Returns:
16
+ # The result of the block.
16
17
  #
18
+ # === Assigns:
19
+ # The transaction_name to kvs[:TransactionName]
17
20
 
18
- def send_metrics(span, kvs = {})
19
- # This is a new span, we do not know the transaction name yet
20
- AppOpticsAPM.transaction_name = nil
21
-
22
- # if a transaction name is provided it will take precedence over transaction names defined
23
- # later or in lower spans
21
+ def send_metrics(span, kvs)
24
22
  start = Time.now
25
-
26
23
  yield
27
24
  ensure
28
25
  duration =(1000 * 1000 * (Time.now - start)).round(0)
29
- transaction_name = AppOpticsAPM::API.determine_transaction_name(span, kvs)
30
- kvs[:TransactionName] = AppOpticsAPM::API.set_transaction_name(AppOpticsAPM::Span.createSpan(transaction_name, nil, duration))
26
+ transaction_name = determine_transaction_name(span)
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
+ # * +opts+ (hash) the value of :TransactionName will be set as custom transaction name
38
+ #
39
+ # === Returns:
40
+ # (string) the current transaction name
41
+ #
42
+ def determine_transaction_name(span)
43
+ AppOpticsAPM.transaction_name || AppOpticsAPM::SDK.set_transaction_name("custom-#{span}")
31
44
  end
45
+
32
46
  end
33
47
  end
34
48
  end
@@ -88,14 +88,13 @@ module AppOpticsAPM
88
88
  if !klass.is_a?(Module)
89
89
  AppOpticsAPM.logger.warn "[appoptics_apm/error] profile_method: Not sure what to do with #{klass}. Send a class or module."
90
90
  return false
91
+ end
91
92
 
93
+ if method.is_a?(String)
94
+ method = method.to_sym
92
95
  elsif !method.is_a?(Symbol)
93
- if method.is_a?(String)
94
- method = method.to_sym
95
- else
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
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
99
98
  end
100
99
 
101
100
  instance_method = klass.instance_methods.include?(method) || klass.private_instance_methods.include?(method)
@@ -177,11 +176,7 @@ module AppOpticsAPM
177
176
  report_kvs[:Language] ||= :ruby
178
177
  report_kvs[:ProfileName] ||= opts[:name] ? opts[:name] : method
179
178
 
180
- if klass.is_a?(Class)
181
- report_kvs[:Class] = klass.to_s
182
- else
183
- report_kvs[:Module] = klass.to_s
184
- end
179
+ klass.is_a?(Class) ? report_kvs[:Class] = klass.to_s : report_kvs[:Module] = klass.to_s
185
180
 
186
181
  # If this is a Rails Controller, report the KVs
187
182
  if defined?(::AbstractController::Base) && klass.ancestors.include?(::AbstractController::Base)
@@ -44,32 +44,11 @@ module AppOpticsAPM
44
44
  #
45
45
  # Returns an array with the result of the block and the last xtrace used
46
46
  def start_trace(span, xtrace = nil, opts = {})
47
- return [yield, nil] unless AppOpticsAPM.loaded
48
-
49
- # if it is not an entry span!
50
- return [trace(span, opts) { yield }, AppopticsAPM::Context.toString] if AppOpticsAPM::Context.isValid
51
-
52
- log_start(span, xtrace, opts)
53
-
54
- # send_metrics deals with the logic for setting AppOpticsAPM.transaction_name
55
- # and ensures that metrics are sent
56
- # log_end sets the transaction_name
57
- result = send_metrics(span, opts) do
58
- begin
59
- yield
60
- rescue Exception => e # rescue everything ok, since we are raising
61
- AppOpticsAPM::API.log_exception(span, e)
62
- e.instance_variable_set(:@xtrace, log_end(span))
63
- raise
64
- end
65
- end
66
- xtrace = AppopticsAPM::Context.toString
67
- log_end(span, opts)
68
-
69
- [result, xtrace]
47
+ target = {}
48
+ [start_trace_with_target(span, xtrace, target, opts) { yield }, target['X-Trace']]
70
49
  end
71
50
 
72
51
 
73
52
  end
74
53
  end
75
- end
54
+ end
@@ -99,6 +99,7 @@ module AppOpticsAPMBase
99
99
  ##
100
100
  # pickup_context
101
101
  #
102
+ # for JRUBY
102
103
  # Determines whether we should pickup context
103
104
  # from an incoming X-Trace request header. The answer
104
105
  # is generally yes but there are cases in JRuby under
@@ -134,17 +135,16 @@ module AppOpticsAPMBase
134
135
  # operation being traced. This is used in cases of recursive
135
136
  # operation tracing or one instrumented operation calling another.
136
137
  #
137
- # <operation> can be a single symbol or an array of symbols that
138
- # will be checked against.
139
- #
140
138
  # In such cases, we only want to trace the outermost operation.
141
139
  #
142
140
  def tracing_layer_op?(operation)
143
- if operation.is_a?(Array)
144
- operation.include?(AppOpticsAPM.layer_op)
145
- else
146
- AppOpticsAPM.layer_op == operation.to_sym
141
+ unless AppOpticsAPM.layer_op.nil? || AppOpticsAPM.layer_op.is_a?(Array)
142
+ AppOpticsAPM.logger.error('[appopticsapm/logging] INTERNAL: layer_op should be nil or an array, please report to support@appoptics.com')
143
+ return false
147
144
  end
145
+
146
+ return false if AppOpticsAPM.layer_op.nil? || AppOpticsAPM.layer_op.empty? || !operation.respond_to?(:to_sym)
147
+ AppOpticsAPM.layer_op.last == operation.to_sym
148
148
  end
149
149
 
150
150
  ##
@@ -190,31 +190,6 @@ module AppOpticsAPMBase
190
190
  end
191
191
  end
192
192
 
193
- ##
194
- # Debugging helper method
195
- #
196
- def pry!
197
- # Only valid for development or test environments
198
- env = ENV['RACK_ENV'] || ENV['RAILS_ENV']
199
- return unless %w(development, test).include? env
200
-
201
- require 'pry'
202
- require 'pry-byebug'
203
-
204
- if defined?(PryByebug)
205
- Pry.commands.alias_command 'c', 'continue'
206
- Pry.commands.alias_command 's', 'step'
207
- Pry.commands.alias_command 'n', 'next'
208
- Pry.commands.alias_command 'f', 'finish'
209
-
210
- Pry::Commands.command(/^$/, 'repeat last command') do
211
- _pry_.run_command Pry.history.to_a.last
212
- end
213
- end
214
-
215
- byebug
216
- end
217
-
218
193
  ##
219
194
  # Indicates whether a supported framework is in use
220
195
  # or not
@@ -57,13 +57,31 @@ module AppOpticsAPM
57
57
  config_file = File.join(Dir.pwd, 'appoptics_apm_config.rb')
58
58
  config_files << config_file if File.exist?(config_file)
59
59
 
60
- return if config_files.empty?
60
+ return if config_files.empty? # we use the defaults from the template in this case
61
61
 
62
62
  if config_files.size > 1
63
63
  $stderr.puts 'Found multiple configuration files, using the first one listed:'
64
64
  config_files.each { |path| $stderr.puts " #{path}" }
65
65
  end
66
66
  load(config_files[0])
67
+ check_env_vars
68
+ end
69
+
70
+ # There are 4 variables that can be set in the config file or as env vars.
71
+ # Oboe will override vars passed in if it finds an environment variable
72
+ # :debug_level and :verbose need special consideration, because they are used in Ruby
73
+ def self.check_env_vars
74
+ unless (0..6).include?(AppOpticsAPM::Config[:debug_level])
75
+ AppOpticsAPM::Config[:debug_level] = nil
76
+ end
77
+ # let's use the same debug level for ruby as well
78
+ debug_level = ENV['APPOPTICS_DEBUG_LEVEL'] || AppOpticsAPM::Config[:debug_level] || 3
79
+ AppOpticsAPM.logger.level = [4 - debug_level.to_i, 0].max
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
67
85
  end
68
86
 
69
87
  ##
@@ -109,12 +127,16 @@ module AppOpticsAPM
109
127
  #
110
128
  # rubocop:disable Metrics/AbcSize
111
129
  def self.initialize(_data = {})
112
- @@instrumentation.each do |k|
113
- @@config[k] = {}
114
- end
130
+ @@instrumentation.each { |k| @@config[k] = {} }
115
131
  @@config[:transaction_name] = {}
132
+
133
+ # Always load the template, it has all the keys and defaults defined,
134
+ # no guarantee of completeness in the user's config file
116
135
  load(File.join(File.dirname(File.dirname(__FILE__)),
117
136
  'rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb'))
137
+
138
+ # to make sure we include the service_key if it is set as an ENV var
139
+ check_env_vars
118
140
  end
119
141
  # rubocop:enable Metrics/AbcSize
120
142
 
@@ -1,5 +1,7 @@
1
1
  # Copyright (c) 2016 SolarWinds, LLC.
2
2
  # All rights reserved.
3
+ #
4
+ class GrapeError < StandardError; end
3
5
 
4
6
  module AppOpticsAPM
5
7
  module Grape
@@ -26,7 +28,8 @@ module AppOpticsAPM
26
28
 
27
29
  report_kvs[:Controller] = options[:for].name
28
30
  if route && route.pattern
29
- report_kvs[:Action] = route.pattern.origin
31
+ report_kvs[:Action] = route.options ? "#{route.options[:method]}#{route.pattern.origin}" : route.pattern.origin
32
+ # report_kvs[:Action] = route.pattern.origin
30
33
  else
31
34
  report_kvs[:Action] = args.empty? ? env['PATH_INFO'] : args[0]['PATH_INFO']
32
35
  end
@@ -54,13 +57,12 @@ module AppOpticsAPM
54
57
  xtrace = AppOpticsAPM::Context.toString
55
58
 
56
59
  if AppOpticsAPM.tracing?
57
- # Since Grape uses throw/catch and not Exceptions, we manually log
58
- # the error here.
59
- kvs = {}
60
- kvs[:ErrorClass] = 'GrapeError'
61
- kvs[:ErrorMsg] = error[:message] ? error[:message] : "No message given."
62
- kvs[:Backtrace] = ::AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:grape][:collect_backtraces]
63
- ::AppOpticsAPM::API.log('rack', 'error', kvs)
60
+
61
+ # Since Grape uses throw/catch and not Exceptions, we have to create an exception here
62
+ exception = GrapeError.new(error[:message] ? error[:message] : "No message given.")
63
+ exception.set_backtrace(::AppOpticsAPM::API.backtrace) if AppOpticsAPM::Config[:grape][:collect_backtraces]
64
+
65
+ ::AppOpticsAPM::API.log_exception('rack', exception )
64
66
 
65
67
  # Since calls to error() are handled similar to abort in Grape. We
66
68
  # manually log the rack exit here since the original code won't
@@ -23,6 +23,9 @@ module AppOpticsAPM
23
23
  env['appoptics_apm.action'] = report_kvs[:Action]
24
24
 
25
25
  result
26
+ rescue => e
27
+ ::AppOpticsAPM::API.log_exception('padrino', e)
28
+ raise e
26
29
  ensure
27
30
  ::AppOpticsAPM::API.log_exit('padrino', report_kvs)
28
31
  end
@@ -6,12 +6,15 @@ module AppOpticsAPM
6
6
  module Helpers
7
7
  extend ActiveSupport::Concern if defined?(::Rails) and ::Rails::VERSION::MAJOR > 2
8
8
 
9
+ # Deprecated
10
+ # no usages
9
11
  def appoptics_rum_header
10
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.'
11
13
  return ''
12
14
  end
13
15
  alias_method :oboe_rum_header, :appoptics_rum_header
14
16
 
17
+ # Deprecated
15
18
  def appoptics_rum_footer
16
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.'
17
20
  return ''
@@ -33,10 +36,8 @@ module AppOpticsAPM
33
36
  #
34
37
  if File.exist?("#{rails_root}/config/initializers/tracelytics.rb")
35
38
  tr_initializer = "#{rails_root}/config/initializers/tracelytics.rb"
36
-
37
39
  elsif File.exist?("#{rails_root}/config/initializers/oboe.rb")
38
40
  tr_initializer = "#{rails_root}/config/initializers/oboe.rb"
39
-
40
41
  else
41
42
  tr_initializer = "#{rails_root}/config/initializers/appoptics_apm.rb"
42
43
  end
@@ -47,7 +48,6 @@ module AppOpticsAPM
47
48
  # Load the Rails specific instrumentation
48
49
  require 'appoptics_apm/frameworks/rails/inst/action_controller'
49
50
  require 'appoptics_apm/frameworks/rails/inst/action_view'
50
- require 'appoptics_apm/frameworks/rails/inst/action_view_2x'
51
51
  require 'appoptics_apm/frameworks/rails/inst/action_view_30'
52
52
  require 'appoptics_apm/frameworks/rails/inst/active_record'
53
53
 
@@ -59,12 +59,8 @@ module AppOpticsAPM
59
59
  # ActiveSupport.on_load(:action_controller) do
60
60
  # include AppOpticsAPM::Rails::Helpers
61
61
  # end
62
- if ::Rails::VERSION::MAJOR > 2
63
- ActiveSupport.on_load(:action_view) do
64
- include AppOpticsAPM::Rails::Helpers
65
- end
66
- else
67
- ActionView::Base.send :include, AppOpticsAPM::Rails::Helpers
62
+ ActiveSupport.on_load(:action_view) do
63
+ include AppOpticsAPM::Rails::Helpers
68
64
  end
69
65
  end
70
66
  end # Rails
@@ -73,44 +69,26 @@ end # AppOpticsAPM
73
69
  if defined?(::Rails)
74
70
  require 'appoptics_apm/inst/rack'
75
71
 
76
- if ::Rails::VERSION::MAJOR > 2
77
- module AppOpticsAPM
78
- class Railtie < ::Rails::Railtie
79
- initializer 'appoptics_apm.helpers' do
80
- AppOpticsAPM::Rails.include_helpers
81
- end
82
-
83
- initializer 'appoptics_apm.rack' do |app|
84
- AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting rack' if AppOpticsAPM::Config[:verbose]
85
- app.config.middleware.insert 0, AppOpticsAPM::Rack
86
- end
87
-
88
- config.after_initialize do
89
- AppOpticsAPM.logger = ::Rails.logger if ::Rails.logger && !ENV.key?('APPOPTICS_GEM_TEST')
90
-
91
- AppOpticsAPM::Inst.load_instrumentation
92
- AppOpticsAPM::Rails.load_instrumentation
93
-
94
- # Report __Init after fork when in Heroku
95
- AppOpticsAPM::API.report_init unless AppOpticsAPM.heroku?
96
- end
72
+ module AppOpticsAPM
73
+ class Railtie < ::Rails::Railtie
74
+ initializer 'appoptics_apm.helpers' do
75
+ AppOpticsAPM::Rails.include_helpers
97
76
  end
98
- end
99
- else
100
- AppOpticsAPM.logger = ::Rails.logger if ::Rails.logger
101
77
 
102
- AppOpticsAPM::Rails.load_initializer
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
103
82
 
104
- Rails.configuration.after_initialize do
105
- AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting rack' if AppOpticsAPM::Config[:verbose]
106
- Rails.configuration.middleware.insert 0, 'AppOpticsAPM::Rack'
83
+ config.after_initialize do
84
+ AppOpticsAPM.logger = ::Rails.logger if ::Rails.logger && !ENV.key?('APPOPTICS_GEM_TEST')
107
85
 
108
- AppOpticsAPM::Inst.load_instrumentation
109
- AppOpticsAPM::Rails.load_instrumentation
110
- AppOpticsAPM::Rails.include_helpers
86
+ AppOpticsAPM::Inst.load_instrumentation
87
+ AppOpticsAPM::Rails.load_instrumentation
111
88
 
112
- # Report __Init after fork when in Heroku
113
- AppOpticsAPM::API.report_init unless AppOpticsAPM.heroku?
89
+ # Report __Init after fork when in Heroku
90
+ AppOpticsAPM::API.report_init unless AppOpticsAPM.heroku?
91
+ end
114
92
  end
115
93
  end
116
94
  end
@@ -43,20 +43,18 @@ module AppOpticsAPM
43
43
  def log_rails_error?(exception)
44
44
  # As it's perculating up through the layers... make sure that
45
45
  # we only report it once.
46
- return false if exception.instance_variable_get(:@appoptics_logged)
46
+ return false if exception.instance_variable_get(:@exn_logged)
47
47
 
48
- has_handler = has_handler?(exception)
48
+ return false if has_handler?(exception) && !AppOpticsAPM::Config[:report_rescued_errors]
49
49
 
50
- if !has_handler || (has_handler && AppOpticsAPM::Config[:report_rescued_errors])
51
- return true
52
- end
53
- false
50
+ true
54
51
  end
55
52
 
56
53
  ##
57
54
  # This method does the logging if we are tracing
58
55
  # it `wraps` around the call to the original method
59
56
  #
57
+ # This can't use the SDK trace() method because of the log_rails_error?(e) condition
60
58
  def trace(layer)
61
59
  return yield unless AppOpticsAPM.tracing?
62
60
  begin
@@ -36,7 +36,7 @@ module AppOpticsAPM
36
36
  process_action_without_appoptics(method_name, *args)
37
37
 
38
38
  rescue Exception => e
39
- AppOpticsAPM::API.log_exception(nil, e) if log_rails_error?(e)
39
+ AppOpticsAPM::API.log_exception('rails', e) if log_rails_error?(e)
40
40
  raise
41
41
  ensure
42
42
  AppOpticsAPM::API.log_exit('rails')
@@ -28,7 +28,7 @@ module AppOpticsAPM
28
28
  super(method_name, *args)
29
29
 
30
30
  rescue Exception => e
31
- AppOpticsAPM::API.log_exception(nil, e) if log_rails_error?(e)
31
+ AppOpticsAPM::API.log_exception('rails', e) if log_rails_error?(e)
32
32
  raise
33
33
  ensure
34
34
  AppOpticsAPM::API.log_exit('rails')
@@ -28,7 +28,7 @@ module AppOpticsAPM
28
28
  super(method_name, *args)
29
29
 
30
30
  rescue Exception => e
31
- AppOpticsAPM::API.log_exception(nil, e) if log_rails_error?(e)
31
+ AppOpticsAPM::API.log_exception('rails', e) if log_rails_error?(e)
32
32
  raise
33
33
  ensure
34
34
  AppOpticsAPM::API.log_exit('rails-api')