appoptics_apm 4.2.3 → 4.2.4

Sign up to get free protection for your applications and to get access to all the features.
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')