appoptics_apm 4.8.2 → 4.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +6 -1
  3. data/.travis.yml +50 -28
  4. data/CONFIG.md +1 -1
  5. data/Gemfile +6 -7
  6. data/README.md +1 -1
  7. data/appoptics_apm.gemspec +4 -1
  8. data/examples/SDK/01_basic_tracing.rb +0 -2
  9. data/ext/oboe_metal/README.md +69 -0
  10. data/ext/oboe_metal/noop/noop.c +2 -1
  11. data/ext/oboe_metal/src/VERSION +1 -1
  12. data/ext/oboe_metal/src/bson/bson.h +105 -105
  13. data/ext/oboe_metal/src/bson/platform_hacks.h +10 -10
  14. data/ext/oboe_metal/src/oboe.h +104 -73
  15. data/ext/oboe_metal/src/oboe.hpp +103 -61
  16. data/ext/oboe_metal/src/oboe_wrap.cxx +1470 -314
  17. data/lib/appoptics_apm.rb +1 -3
  18. data/lib/appoptics_apm/api.rb +0 -1
  19. data/lib/appoptics_apm/api/tracing.rb +4 -0
  20. data/lib/appoptics_apm/config.rb +16 -5
  21. data/lib/appoptics_apm/frameworks/padrino.rb +6 -36
  22. data/lib/appoptics_apm/frameworks/rails.rb +0 -1
  23. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +5 -5
  24. data/lib/appoptics_apm/frameworks/rails/inst/action_controller6.rb +50 -0
  25. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +11 -24
  26. data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +3 -3
  27. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +1 -1
  28. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +1 -1
  29. data/lib/appoptics_apm/frameworks/sinatra.rb +3 -32
  30. data/lib/appoptics_apm/inst/curb.rb +6 -6
  31. data/lib/appoptics_apm/inst/faraday.rb +16 -4
  32. data/lib/appoptics_apm/inst/rack.rb +11 -11
  33. data/lib/appoptics_apm/oboe_init_options.rb +17 -4
  34. data/lib/appoptics_apm/sdk/custom_metrics.rb +2 -0
  35. data/lib/appoptics_apm/sdk/tracing.rb +118 -0
  36. data/lib/appoptics_apm/support/transaction_metrics.rb +1 -0
  37. data/lib/appoptics_apm/support/transaction_settings.rb +40 -15
  38. data/lib/appoptics_apm/support/x_trace_options.rb +110 -0
  39. data/lib/appoptics_apm/version.rb +2 -2
  40. data/lib/appoptics_apm/xtrace.rb +7 -7
  41. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +37 -12
  42. metadata +7 -15
  43. data/Rakefile +0 -229
  44. data/build_gem.sh +0 -15
  45. data/build_gem_upload_to_packagecloud.sh +0 -20
  46. data/lib/appoptics_apm/api/profiling.rb +0 -203
  47. data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +0 -55
  48. data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +0 -50
  49. data/lib/appoptics_apm/legacy_method_profiling.rb +0 -90
  50. data/lib/appoptics_apm/method_profiling.rb +0 -33
  51. data/lib/oboe/README +0 -2
  52. data/lib/oboe/backward_compatibility.rb +0 -80
  53. data/lib/oboe/inst/rack.rb +0 -11
data/build_gem.sh DELETED
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env bash
2
- # builds the appoptics_apm gem for MRI.
3
-
4
- # we currently only build for MRI, no JRuby
5
- echo -e "\n=== building for MRI ===\n"
6
- rm -f Gemfile.lock
7
- bundle install
8
- bundle exec rake distclean
9
- bundle exec rake fetch_ext_deps
10
- gem build appoptics_apm.gemspec
11
-
12
- echo -e "\n=== built gems ===\n"
13
- ls -la appoptics_apm*.gem
14
-
15
- echo -e "\n=== publish to rubygems via: gem push <gem> ===\n"
@@ -1,20 +0,0 @@
1
- #!/bin/bash
2
-
3
- # build the gem,
4
- # oboe/c-lib version can be given as optional parameter
5
- if [ "$1" != "" ]; then
6
- OBOE_VERSION=$1 ./build_gem.sh
7
- else
8
- ./build_gem.sh
9
- fi
10
-
11
- # save current rbenv setting and switch to 2.4.1 for the package_cloud commands
12
- current_ruby=`rbenv global`
13
- rbenv global 2.4.1
14
-
15
- # prerequisite: package_cloud token needs to be in ~/.packagecloud
16
- gem=`ls -dt1 appoptics_apm-[^pre]*.gem | head -1`
17
- package_cloud push solarwinds/appoptics-apm-ruby $gem
18
-
19
- # restore ruby version
20
- rbenv global $current_ruby
@@ -1,203 +0,0 @@
1
- #--
2
- # Copyright (c) 2016 SolarWinds, LLC.
3
- # All rights reserved.
4
- #++
5
-
6
- module AppOpticsAPM
7
- module API
8
- ##
9
- # Module to create profiling traces for blocks of code or methods
10
- module Profiling
11
- ##
12
- # Public: Profile a given block of code. Detect any exceptions thrown by
13
- # the block and report errors.
14
- #
15
- # ==== Arguments
16
- #
17
- # * +profile_name+ - A name used to identify the block being profiled.
18
- # * +report_kvs+ - A hash containing key/value pairs that will be reported along
19
- # with the event of this profile (optional).
20
- # * +with_backtrace+ - Boolean to indicate whether a backtrace should
21
- # be collected with this trace event.
22
- #
23
- # ==== Example
24
- #
25
- # def computation(n)
26
- # AppOpticsAPM::API.profile('fib', { :n => n }) do
27
- # fib(n)
28
- # end
29
- # end
30
- #
31
- # Returns the result of the block.
32
- #
33
-
34
- def profile(profile_name, report_kvs = {}, with_backtrace = false)
35
- return yield unless AppOpticsAPM.tracing?
36
-
37
- begin
38
- report_kvs[:Language] ||= :ruby
39
- report_kvs[:ProfileName] ||= profile_name
40
- report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if with_backtrace
41
-
42
- AppOpticsAPM::API.log(nil, :profile_entry, report_kvs)
43
-
44
- begin
45
- yield
46
- rescue => e
47
- log_exception(nil, e)
48
- raise
49
- ensure
50
- exit_kvs = {}
51
- exit_kvs[:Language] = :ruby
52
- exit_kvs[:ProfileName] = report_kvs[:ProfileName]
53
-
54
- AppOpticsAPM::API.log(nil, :profile_exit, exit_kvs)
55
- end
56
- end
57
- end
58
-
59
- ##
60
- # Public: Add profiling to a method on a class or module. That method can be of any (accessible)
61
- # type (instance, singleton, private, protected etc.).
62
- #
63
- # ==== Arguments
64
- #
65
- # * +klass+ - the class or module that has the method to profile
66
- # * +method+ - the method to profile. Can be singleton, instance, private etc...
67
- # * +opts+ - a hash specifying the one or more of the following options:
68
- # * +:arguments+ - report the arguments passed to <tt>method</tt> on each profile (default: false)
69
- # * +:result+ - report the return value of <tt>method</tt> on each profile (default: false)
70
- # * +:backtrace+ - report the return value of <tt>method</tt> on each profile (default: false)
71
- # * +:name+ - alternate name for the profile reported in the dashboard (default: method name)
72
- # * +extra_kvs+ - a hash containing any additional key/value pairs you would like reported with the profile
73
- #
74
- # ==== Example
75
- #
76
- # opts = {}
77
- # opts[:backtrace] = true
78
- # opts[:arguments] = false
79
- # opts[:name] = :array_sort
80
- #
81
- # AppOpticsAPM::API.profile_method(Array, :sort, opts)
82
- #
83
- def profile_method(klass, method, opts = {}, extra_kvs = {})
84
- # If we're on an unsupported platform (ahem Mac), just act
85
- # like we did something to nicely play the no-op part.
86
- return true unless AppOpticsAPM.loaded
87
-
88
- if !klass.is_a?(Module)
89
- AppOpticsAPM.logger.warn "[appoptics_apm/error] profile_method: Not sure what to do with #{klass}. Send a class or module."
90
- return false
91
- end
92
-
93
- if method.is_a?(String)
94
- method = method.to_sym
95
- elsif !method.is_a?(Symbol)
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
99
-
100
- instance_method = klass.instance_methods.include?(method) || klass.private_instance_methods.include?(method)
101
- class_method = klass.singleton_methods.include?(method)
102
-
103
- # Make sure the request klass::method exists
104
- if !instance_method && !class_method
105
- AppOpticsAPM.logger.warn "[appoptics_apm/error] profile_method: Can't instrument #{klass}.#{method} as it doesn't seem to exist."
106
- AppOpticsAPM.logger.warn "[appoptics_apm/error] #{__FILE__}:#{__LINE__}"
107
- return false
108
- end
109
-
110
- # Strip '!' or '?' from method if present
111
- safe_method_name = method.to_s.chop if method.to_s =~ /\?$|\!$/
112
- safe_method_name ||= method
113
-
114
- without_appoptics = "#{safe_method_name}_without_appoptics"
115
- with_appoptics = "#{safe_method_name}_with_appoptics"
116
-
117
- # Check if already profiled
118
- if klass.instance_methods.include?(with_appoptics.to_sym) ||
119
- klass.singleton_methods.include?(with_appoptics.to_sym)
120
- AppOpticsAPM.logger.warn "[appoptics_apm/error] profile_method: #{klass}::#{method} already profiled."
121
- AppOpticsAPM.logger.warn "[appoptics_apm/error] profile_method: #{__FILE__}:#{__LINE__}"
122
- return false
123
- end
124
-
125
- source_location = []
126
- if instance_method
127
- AppOpticsAPM::Util.send_include(klass, AppOpticsAPM::MethodProfiling)
128
- source_location = klass.instance_method(method).source_location
129
- elsif class_method
130
- AppOpticsAPM::Util.send_extend(klass, AppOpticsAPM::MethodProfiling)
131
- source_location = klass.method(method).source_location
132
- end
133
-
134
- report_kvs = collect_profile_kvs(klass, method, opts, extra_kvs, source_location)
135
- report_kvs[:MethodName] = safe_method_name
136
-
137
- if instance_method
138
- klass.class_eval do
139
- define_method(with_appoptics) do |*args, &block|
140
- profile_wrapper(without_appoptics, report_kvs, opts, *args, &block)
141
- end
142
-
143
- alias_method without_appoptics, method.to_s
144
- alias_method method.to_s, with_appoptics
145
- end
146
- elsif class_method
147
- klass.define_singleton_method(with_appoptics) do |*args, &block|
148
- profile_wrapper(without_appoptics, report_kvs, opts, *args, &block)
149
- end
150
-
151
- klass.singleton_class.class_eval do
152
- alias_method without_appoptics, method.to_s
153
- alias_method method.to_s, with_appoptics
154
- end
155
- end
156
- true
157
- end
158
-
159
- private
160
-
161
- ##
162
- # Private: Helper method to aggregate KVs to report
163
- #
164
- # klass - the class or module that has the method to profile
165
- # method - the method to profile. Can be singleton, instance, private etc...
166
- # opts - a hash specifying the one or more of the following options:
167
- # * :arguments - report the arguments passed to <tt>method</tt> on each profile (default: false)
168
- # * :result - report the return value of <tt>method</tt> on each profile (default: false)
169
- # * :backtrace - report the return value of <tt>method</tt> on each profile (default: false)
170
- # * :name - alternate name for the profile reported in the dashboard (default: method name)
171
- # extra_kvs - a hash containing any additional KVs you would like reported with the profile
172
- # source_location - array returned from klass.method(:name).source_location
173
- #
174
- def collect_profile_kvs(klass, method, opts, extra_kvs, source_location)
175
- report_kvs = {}
176
- report_kvs[:Language] ||= :ruby
177
- report_kvs[:ProfileName] ||= opts[:name] ? opts[:name] : method
178
-
179
- klass.is_a?(Class) ? report_kvs[:Class] = klass.to_s : report_kvs[:Module] = klass.to_s
180
-
181
- # If this is a Rails Controller, report the KVs
182
- if defined?(::AbstractController::Base) && klass.ancestors.include?(::AbstractController::Base)
183
- report_kvs[:Controller] = klass.to_s
184
- report_kvs[:Action] = method.to_s
185
- end
186
-
187
- # We won't have access to this info for native methods (those not defined in Ruby).
188
- if source_location.is_a?(Array) && source_location.length == 2
189
- report_kvs[:File] = source_location[0]
190
- report_kvs[:LineNumber] = source_location[1]
191
- end
192
-
193
- # Merge in any extra_kvs requested
194
- report_kvs.merge!(extra_kvs)
195
- end
196
-
197
-
198
- # need to set the context to public, otherwise the following `extends` will be private in api.rb
199
- public
200
-
201
- end
202
- end
203
- end
@@ -1,55 +0,0 @@
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
@@ -1,50 +0,0 @@
1
- # Copyright (c) 2016 SolarWinds, LLC.
2
- # All rights reserved.
3
-
4
- if defined?(ActionView::Base) && AppOpticsAPM::Config[:action_view][:enabled]
5
-
6
- if Rails::VERSION::MAJOR == 3 && Rails::VERSION::MINOR == 0
7
-
8
- ActionView::Partials::PartialRenderer.class_eval do
9
- alias :render_partial_without_appoptics :render_partial
10
- def render_partial(object = @object)
11
- entry_kvs = {}
12
- begin
13
- name = AppOpticsAPM::Util.prettify(@options[:partial]) if @options.is_a?(Hash)
14
- entry_kvs[:FunctionName] = :render_partial
15
- entry_kvs[:Class] = :PartialRenderer
16
- entry_kvs[:Module] = 'ActionView::Partials'
17
- entry_kvs[:File] = __FILE__
18
- entry_kvs[:LineNumber] = __LINE__
19
- rescue => e
20
- AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
21
- end
22
-
23
- AppOpticsAPM::API.profile(name, entry_kvs, AppOpticsAPM::Config[:action_view][:collect_backtraces]) do
24
- render_partial_without_appoptics(object)
25
- end
26
- end
27
-
28
- alias :render_collection_without_appoptics :render_collection
29
- def render_collection
30
- entry_kvs = {}
31
- begin
32
- name = AppOpticsAPM::Util.prettify(@path)
33
- entry_kvs[:FunctionName] = :render_collection
34
- entry_kvs[:Class] = :PartialRenderer
35
- entry_kvs[:Module] = 'ActionView::Partials'
36
- entry_kvs[:File] = __FILE__
37
- entry_kvs[:LineNumber] = __LINE__
38
- rescue => e
39
- AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
40
- end
41
-
42
- AppOpticsAPM::API.profile(name, entry_kvs, AppOpticsAPM::Config[:action_view][:collect_backtraces]) do
43
- render_collection_without_appoptics
44
- end
45
- end
46
- end
47
- end
48
- end
49
-
50
- # vim:set expandtab:tabstop=2
@@ -1,90 +0,0 @@
1
- # Copyright (c) 2016 SolarWinds, LLC.
2
- # All rights reserved.
3
-
4
- ##
5
- # Provides the methods necessary for method profiling. Profiling
6
- # results are sent to the AppOptics dashboard.
7
- #
8
- # Example usage:
9
- # class MyApp
10
- # include AppOpticsAPMMethodProfiling
11
- #
12
- # def process_request()
13
- # # The hard work
14
- # end
15
- #
16
- # # call syntax: profile_method <method>, <profile_name>
17
- # profile_method :process_request, 'request_processor'
18
- # end
19
- module AppOpticsAPMMethodProfiling
20
- def self.included(klass)
21
- klass.extend ClassMethods
22
- end
23
-
24
- module ClassMethods
25
- def profile_method_noop(*args)
26
- nil
27
- end
28
-
29
- def profile_method_real(method_name, profile_name, store_args = false, store_return = false, *_)
30
- begin
31
- # this only gets file and line where profiling is turned on, presumably
32
- # right after the function definition.
33
- file = ''
34
- line = ''
35
- info = instance_method(method_name).source_location
36
- unless info.nil?
37
- file = info[0].to_s
38
- line = info[1].to_s
39
- end
40
-
41
- # Safety: Make sure there are no quotes or double quotes to break the class_eval
42
- file = file.gsub(/[\'\"]/, '')
43
- line = line.gsub(/[\'\"]/, '')
44
-
45
- # profiling via ruby-prof, is it possible to get return value of profiled code?
46
- code = "def _appoptics_profiled_#{method_name}(*args, &block)
47
- entry_kvs = {}
48
- entry_kvs['Language'] = 'ruby'
49
- entry_kvs['ProfileName'] = '#{AppOpticsAPM::Util.prettify(profile_name)}'
50
- entry_kvs['FunctionName'] = '#{AppOpticsAPM::Util.prettify(method_name)}'
51
- entry_kvs['File'] = '#{file}'
52
- entry_kvs['LineNumber'] = '#{line}'
53
- entry_kvs['Args'] = AppOpticsAPM::API.pps(*args) if #{store_args}
54
- entry_kvs.merge!(AppOpticsAPM::API.get_class_name(self))
55
-
56
- AppOpticsAPM::API.log(nil, 'profile_entry', entry_kvs)
57
-
58
- ret = _appoptics_orig_#{method_name}(*args, &block)
59
-
60
- exit_kvs = {}
61
- exit_kvs['Language'] = 'ruby'
62
- exit_kvs['ProfileName'] = '#{AppOpticsAPM::Util.prettify(profile_name)}'
63
- exit_kvs['ReturnValue'] = AppOpticsAPM::API.pps(ret) if #{store_return}
64
-
65
- AppOpticsAPM::API.log(nil, 'profile_exit', exit_kvs)
66
- ret
67
- end"
68
- rescue => e
69
- AppOpticsAPM.logger.warn "[appoptics_apm/warn] profile_method: #{e.inspect}"
70
- end
71
-
72
- begin
73
- class_eval code, __FILE__, __LINE__
74
- alias_method "_appoptics_orig_#{method_name}", method_name
75
- alias_method method_name, "_appoptics_profiled_#{method_name}"
76
- rescue => e
77
- AppOpticsAPM.logger.warn "[appoptics_apm/warn] Fatal error profiling method (#{method_name}): #{e.inspect}" if AppOpticsAPM::Config[:verbose]
78
- end
79
- end
80
-
81
- # This allows this module to be included and called even if the gem is in
82
- # no-op mode (no base libraries).
83
- if AppOpticsAPM.loaded
84
- alias :profile_method :profile_method_real
85
- else
86
- alias :profile_method :profile_method_noop
87
- end
88
-
89
- end
90
- end
@@ -1,33 +0,0 @@
1
-
2
- module AppOpticsAPM
3
- module MethodProfiling
4
- def profile_wrapper(method, report_kvs, opts, *args, &block)
5
- report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace(2) if opts[:backtrace]
6
- report_kvs[:Arguments] = args if opts[:arguments]
7
-
8
- # if this is a rails controller we want to set the transaction for the outbound metrics
9
- if defined?(request) && defined?(request.env)
10
- report_kvs['Controller'] = self.class.name
11
- report_kvs['Action'] = self.action_name
12
- request.env['appoptics_apm.controller'] = report_kvs['Controller']
13
- request.env['appoptics_apm.action'] = report_kvs['Action']
14
- end
15
-
16
- AppOpticsAPM::API.log(nil, :profile_entry, report_kvs)
17
-
18
- begin
19
- rv = self.send(method, *args, &block)
20
- report_kvs[:ReturnValue] = rv if opts[:result]
21
- rv
22
- rescue => e
23
- AppOpticsAPM::API.log_exception(nil, e)
24
- raise
25
- ensure
26
- report_kvs.delete(:Backtrace)
27
- report_kvs.delete(:Controller)
28
- report_kvs.delete(:Action)
29
- AppOpticsAPM::API.log(nil, :profile_exit, report_kvs)
30
- end
31
- end
32
- end
33
- end