appoptics_apm_mnfst 4.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) 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/.gitignore +29 -0
  5. data/.rubocop.yml +8 -0
  6. data/.travis.yml +121 -0
  7. data/.yardopts +4 -0
  8. data/CHANGELOG.md +769 -0
  9. data/CONFIG.md +33 -0
  10. data/Gemfile +29 -0
  11. data/LICENSE +193 -0
  12. data/README.md +393 -0
  13. data/Rakefile +230 -0
  14. data/appoptics_apm.gemspec +61 -0
  15. data/bin/appoptics_apm_config +15 -0
  16. data/build_gem.sh +15 -0
  17. data/build_gem_upload_to_packagecloud.sh +20 -0
  18. data/examples/SDK/01_basic_tracing.rb +67 -0
  19. data/examples/carrying_context.rb +220 -0
  20. data/ext/oboe_metal/extconf.rb +114 -0
  21. data/ext/oboe_metal/lib/.keep +0 -0
  22. data/ext/oboe_metal/noop/noop.c +7 -0
  23. data/ext/oboe_metal/src/VERSION +1 -0
  24. data/init.rb +4 -0
  25. data/lib/appoptics_apm.rb +76 -0
  26. data/lib/appoptics_apm/api.rb +20 -0
  27. data/lib/appoptics_apm/api/layerinit.rb +41 -0
  28. data/lib/appoptics_apm/api/logging.rb +375 -0
  29. data/lib/appoptics_apm/api/memcache.rb +37 -0
  30. data/lib/appoptics_apm/api/metrics.rb +55 -0
  31. data/lib/appoptics_apm/api/profiling.rb +203 -0
  32. data/lib/appoptics_apm/api/tracing.rb +53 -0
  33. data/lib/appoptics_apm/api/util.rb +122 -0
  34. data/lib/appoptics_apm/base.rb +230 -0
  35. data/lib/appoptics_apm/config.rb +254 -0
  36. data/lib/appoptics_apm/frameworks/grape.rb +97 -0
  37. data/lib/appoptics_apm/frameworks/padrino.rb +108 -0
  38. data/lib/appoptics_apm/frameworks/rails.rb +94 -0
  39. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +104 -0
  40. data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +55 -0
  41. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
  42. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  43. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  44. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +58 -0
  45. data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +50 -0
  46. data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
  47. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  48. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
  49. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +31 -0
  50. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +119 -0
  51. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +108 -0
  52. data/lib/appoptics_apm/frameworks/sinatra.rb +125 -0
  53. data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
  54. data/lib/appoptics_apm/inst/bunny-consumer.rb +89 -0
  55. data/lib/appoptics_apm/inst/curb.rb +330 -0
  56. data/lib/appoptics_apm/inst/dalli.rb +85 -0
  57. data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
  58. data/lib/appoptics_apm/inst/em-http-request.rb +101 -0
  59. data/lib/appoptics_apm/inst/excon.rb +125 -0
  60. data/lib/appoptics_apm/inst/faraday.rb +94 -0
  61. data/lib/appoptics_apm/inst/grpc_client.rb +162 -0
  62. data/lib/appoptics_apm/inst/grpc_server.rb +120 -0
  63. data/lib/appoptics_apm/inst/http.rb +73 -0
  64. data/lib/appoptics_apm/inst/httpclient.rb +174 -0
  65. data/lib/appoptics_apm/inst/memcached.rb +86 -0
  66. data/lib/appoptics_apm/inst/mongo.rb +246 -0
  67. data/lib/appoptics_apm/inst/mongo2.rb +225 -0
  68. data/lib/appoptics_apm/inst/moped.rb +466 -0
  69. data/lib/appoptics_apm/inst/rack.rb +199 -0
  70. data/lib/appoptics_apm/inst/redis.rb +275 -0
  71. data/lib/appoptics_apm/inst/resque.rb +151 -0
  72. data/lib/appoptics_apm/inst/rest-client.rb +48 -0
  73. data/lib/appoptics_apm/inst/sequel.rb +178 -0
  74. data/lib/appoptics_apm/inst/sidekiq-client.rb +55 -0
  75. data/lib/appoptics_apm/inst/sidekiq-worker.rb +65 -0
  76. data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
  77. data/lib/appoptics_apm/inst/typhoeus.rb +108 -0
  78. data/lib/appoptics_apm/instrumentation.rb +22 -0
  79. data/lib/appoptics_apm/legacy_method_profiling.rb +90 -0
  80. data/lib/appoptics_apm/loading.rb +65 -0
  81. data/lib/appoptics_apm/logger.rb +42 -0
  82. data/lib/appoptics_apm/method_profiling.rb +33 -0
  83. data/lib/appoptics_apm/noop/README.md +9 -0
  84. data/lib/appoptics_apm/noop/context.rb +26 -0
  85. data/lib/appoptics_apm/noop/metadata.rb +22 -0
  86. data/lib/appoptics_apm/ruby.rb +35 -0
  87. data/lib/appoptics_apm/sdk/custom_metrics.rb +92 -0
  88. data/lib/appoptics_apm/sdk/tracing.rb +315 -0
  89. data/lib/appoptics_apm/support.rb +119 -0
  90. data/lib/appoptics_apm/test.rb +94 -0
  91. data/lib/appoptics_apm/thread_local.rb +26 -0
  92. data/lib/appoptics_apm/util.rb +319 -0
  93. data/lib/appoptics_apm/version.rb +15 -0
  94. data/lib/appoptics_apm/xtrace.rb +103 -0
  95. data/lib/joboe_metal.rb +212 -0
  96. data/lib/oboe.rb +7 -0
  97. data/lib/oboe/README +2 -0
  98. data/lib/oboe/backward_compatibility.rb +80 -0
  99. data/lib/oboe/inst/rack.rb +11 -0
  100. data/lib/oboe_metal.rb +198 -0
  101. data/lib/rails/generators/appoptics_apm/install_generator.rb +45 -0
  102. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +265 -0
  103. data/yardoc_frontpage.md +26 -0
  104. metadata +266 -0
@@ -0,0 +1,119 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'rbconfig'
5
+ require 'logger'
6
+
7
+ module AppOpticsAPM
8
+ ##
9
+ # This module is used to debug problematic setups and/or environments.
10
+ # Depending on the environment, output may be to stdout or the framework
11
+ # log file (e.g. log/production.log)
12
+
13
+ ##
14
+ # yesno
15
+ #
16
+ # Utility method to translate value/nil to "yes"/"no" strings
17
+ def self.yesno(x)
18
+ x ? 'yes' : 'no'
19
+ end
20
+
21
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
22
+ def self.support_report
23
+ @logger_level = AppOpticsAPM.logger.level
24
+ AppOpticsAPM.logger.level = ::Logger::DEBUG
25
+
26
+ AppOpticsAPM.logger.warn '********************************************************'
27
+ AppOpticsAPM.logger.warn '* BEGIN AppOpticsAPM Support Report'
28
+ AppOpticsAPM.logger.warn '* Please email the output of this report to support@appoptics.com'
29
+ AppOpticsAPM.logger.warn '********************************************************'
30
+ AppOpticsAPM.logger.warn "Ruby: #{RUBY_DESCRIPTION}"
31
+ AppOpticsAPM.logger.warn "$0: #{$0}"
32
+ AppOpticsAPM.logger.warn "$1: #{$1}" unless $1.nil?
33
+ AppOpticsAPM.logger.warn "$2: #{$2}" unless $2.nil?
34
+ AppOpticsAPM.logger.warn "$3: #{$3}" unless $3.nil?
35
+ AppOpticsAPM.logger.warn "$4: #{$4}" unless $4.nil?
36
+ AppOpticsAPM.logger.warn "AppOpticsAPM.loaded == #{AppOpticsAPM.loaded}"
37
+
38
+ using_jruby = defined?(JRUBY_VERSION)
39
+ AppOpticsAPM.logger.warn "Using JRuby?: #{yesno(using_jruby)}"
40
+ if using_jruby
41
+ AppOpticsAPM.logger.warn "Joboe Agent Status: #{Java::ComTracelyticsAgent::Agent.getStatus}"
42
+ end
43
+
44
+ on_heroku = AppOpticsAPM.heroku?
45
+ AppOpticsAPM.logger.warn "On Heroku?: #{yesno(on_heroku)}"
46
+ if on_heroku
47
+ AppOpticsAPM.logger.warn "APPOPTICS_URL: #{ENV['APPOPTICS_URL']}"
48
+ end
49
+
50
+ AppOpticsAPM.logger.warn "AppOpticsAPM::Ruby defined?: #{yesno(defined?(AppOpticsAPM::Ruby))}"
51
+ AppOpticsAPM.logger.warn "AppOpticsAPM.reporter: #{AppOpticsAPM.reporter}"
52
+
53
+ AppOpticsAPM.logger.warn '********************************************************'
54
+ AppOpticsAPM.logger.warn '* Frameworks'
55
+ AppOpticsAPM.logger.warn '********************************************************'
56
+
57
+ using_rails = defined?(::Rails)
58
+ AppOpticsAPM.logger.warn "Using Rails?: #{yesno(using_rails)}"
59
+ if using_rails
60
+ AppOpticsAPM.logger.warn "AppOpticsAPM::Rails loaded?: #{yesno(defined?(AppOpticsAPM::Rails))}"
61
+ if defined?(AppOpticsAPM::Rack)
62
+ AppOpticsAPM.logger.warn "AppOpticsAPM::Rack middleware loaded?: #{yesno(::Rails.configuration.middleware.include? AppOpticsAPM::Rack)}"
63
+ end
64
+ end
65
+
66
+ using_sinatra = defined?(::Sinatra)
67
+ AppOpticsAPM.logger.warn "Using Sinatra?: #{yesno(using_sinatra)}"
68
+
69
+ using_padrino = defined?(::Padrino)
70
+ AppOpticsAPM.logger.warn "Using Padrino?: #{yesno(using_padrino)}"
71
+
72
+ using_grape = defined?(::Grape)
73
+ AppOpticsAPM.logger.warn "Using Grape?: #{yesno(using_grape)}"
74
+
75
+ AppOpticsAPM.logger.warn '********************************************************'
76
+ AppOpticsAPM.logger.warn '* ActiveRecord Adapter'
77
+ AppOpticsAPM.logger.warn '********************************************************'
78
+ if defined?(::ActiveRecord)
79
+ if defined?(::ActiveRecord::Base.connection.adapter_name)
80
+ AppOpticsAPM.logger.warn "ActiveRecord adapter: #{::ActiveRecord::Base.connection.adapter_name}"
81
+ end
82
+ else
83
+ AppOpticsAPM.logger.warn 'No ActiveRecord'
84
+ end
85
+
86
+ AppOpticsAPM.logger.warn '********************************************************'
87
+ AppOpticsAPM.logger.warn '* AppOpticsAPM::Config Values'
88
+ AppOpticsAPM.logger.warn '********************************************************'
89
+ AppOpticsAPM::Config.print_config
90
+
91
+ AppOpticsAPM.logger.warn '********************************************************'
92
+ AppOpticsAPM.logger.warn '* OS, Platform + Env'
93
+ AppOpticsAPM.logger.warn '********************************************************'
94
+ AppOpticsAPM.logger.warn "host_os: " + RbConfig::CONFIG['host_os']
95
+ AppOpticsAPM.logger.warn "sitearch: " + RbConfig::CONFIG['sitearch']
96
+ AppOpticsAPM.logger.warn "arch: " + RbConfig::CONFIG['arch']
97
+ AppOpticsAPM.logger.warn RUBY_PLATFORM
98
+ AppOpticsAPM.logger.warn "RACK_ENV: #{ENV['RACK_ENV']}"
99
+ AppOpticsAPM.logger.warn "RAILS_ENV: #{ENV['RAILS_ENV']}" if using_rails
100
+
101
+ AppOpticsAPM.logger.warn '********************************************************'
102
+ AppOpticsAPM.logger.warn '* Raw __Init KVs'
103
+ AppOpticsAPM.logger.warn '********************************************************'
104
+ platform_info = AppOpticsAPM::Util.build_init_report
105
+ platform_info.each { |k,v|
106
+ AppOpticsAPM.logger.warn "#{k}: #{v}"
107
+ }
108
+
109
+ AppOpticsAPM.logger.warn '********************************************************'
110
+ AppOpticsAPM.logger.warn '* END AppOpticsAPM Support Report'
111
+ AppOpticsAPM.logger.warn '* Support Email: support@appoptics.com'
112
+ AppOpticsAPM.logger.warn '* Github: https://github.com/librato/ruby-appoptics'
113
+ AppOpticsAPM.logger.warn '********************************************************'
114
+
115
+ AppOpticsAPM.logger.level = @logger_level
116
+ nil
117
+ end
118
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
119
+ end
@@ -0,0 +1,94 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Test
6
+ class << self
7
+ ##
8
+ # load_extras
9
+ #
10
+ # This method simply loads all the extras needed to run
11
+ # tests such as models, jobs etc...
12
+ #
13
+ def load_extras
14
+ # If we're using the libraries gemfile (with sidekiq and resque)
15
+ if AppOpticsAPM::Test.gemfile?(:libraries)
16
+ # Load all of the test workers
17
+ pattern = File.join(File.dirname(__FILE__), '../../test/jobs/**/', '*.rb')
18
+ Dir.glob(pattern) do |f|
19
+ AppOpticsAPM.logger.debug "[appoptics_apm/test] Loading test job file: #{File.basename(f)}"
20
+ require f
21
+ end
22
+ end
23
+ end
24
+
25
+ ##
26
+ # gemfile?
27
+ #
28
+ # Method used to determine under which gemfile we're running.
29
+ # Pass <tt>name</tt> as the gemfile name only (without the
30
+ # .gemfile extension)
31
+ #
32
+ # returns true or fase depending on result
33
+ #
34
+ def gemfile?(name)
35
+ File.basename(ENV['BUNDLE_GEMFILE']) == (name.to_s + '.gemfile')
36
+ end
37
+
38
+ ##
39
+ # gemfile
40
+ #
41
+ # Used to determine under which gemfile we are running. This
42
+ # method will return the name of the active gemfile
43
+ #
44
+ def gemfile
45
+ File.basename(ENV['BUNDLE_GEMFILE']).split('.').first
46
+ end
47
+
48
+ ##
49
+ # set_postgresql_env
50
+ #
51
+ # Used to set the postgresql specific DATABASE_URL env based
52
+ # on various conditions
53
+ def set_postgresql_env
54
+ if ENV.key?('TRAVIS_PSQL_PASS')
55
+ ENV['DATABASE_URL'] = "postgresql://postgres:#{ENV['TRAVIS_PSQL_PASS']}@127.0.0.1:5432/travis_ci_test"
56
+ elsif ENV.key?('DOCKER_PSQL_PASS')
57
+ ENV['DATABASE_URL'] = "postgresql://docker:#{ENV['DOCKER_PSQL_PASS']}@127.0.0.1:5432/travis_ci_test"
58
+ else
59
+ ENV['DATABASE_URL'] = 'postgresql://postgres@127.0.0.1:5432/travis_ci_test'
60
+ end
61
+ end
62
+
63
+ ##
64
+ # set_mysql_env
65
+ #
66
+ # Used to set the mysql specific DATABASE_URL env based
67
+ # on various conditions
68
+ def set_mysql_env
69
+ if ENV.key?('TRAVIS_MYSQL_PASS')
70
+ ENV['DATABASE_URL'] = "mysql://root:#{ENV['TRAVIS_MYSQL_PASS']}@127.0.0.1:3306/travis_ci_test"
71
+ elsif ENV.key?('DOCKER_MYSQL_PASS')
72
+ ENV['DATABASE_URL'] = "mysql://root:#{ENV['DOCKER_MYSQL_PASS']}@mysql:3306/travis_ci_test"
73
+ else
74
+ ENV['DATABASE_URL'] = 'mysql://root@127.0.0.1:3306/travis_ci_test'
75
+ end
76
+ end
77
+
78
+ ##
79
+ # set_mysql2_env
80
+ #
81
+ # Used to set the mysql specific DATABASE_URL env based
82
+ # on various conditions
83
+ def set_mysql2_env
84
+ if ENV.key?('TRAVIS_MYSQL_PASS')
85
+ ENV['DATABASE_URL'] = "mysql2://root:#{ENV['TRAVIS_MYSQL_PASS']}@127.0.0.1:3306/travis_ci_test"
86
+ elsif ENV.key?('DOCKER_MYSQL_PASS')
87
+ ENV['DATABASE_URL'] = "mysql2://root:#{ENV['DOCKER_MYSQL_PASS']}@mysql:3306/travis_ci_test"
88
+ else
89
+ ENV['DATABASE_URL'] = 'mysql2://root@127.0.0.1:3306/travis_ci_test'
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ ##
6
+ # Provides thread local storage for AppOpticsAPM.
7
+ #
8
+ # Example usage:
9
+ # module AppOpticsAPMBase
10
+ # extend AppOpticsAPM::ThreadLocal
11
+ # thread_local :layer_op
12
+ # end
13
+ module ThreadLocal
14
+ def thread_local(name)
15
+ key = "__#{self}_#{name}__".intern
16
+
17
+ define_method(name) do
18
+ Thread.current[key]
19
+ end
20
+
21
+ define_method(name.to_s + '=') do |value|
22
+ Thread.current[key] = value
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,319 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ ##
6
+ # Provides utility methods for use while in the business
7
+ # of instrumenting code
8
+ module Util
9
+ class << self
10
+ def contextual_name(cls)
11
+ # Attempt to infer a contextual name if not indicated
12
+ #
13
+ # For example:
14
+ # ::ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.to_s.split(/::/).last
15
+ # => "AbstractMysqlAdapter"
16
+ #
17
+ cls.to_s.split(/::/).last
18
+ rescue
19
+ cls
20
+ end
21
+
22
+ ##
23
+ # method_alias
24
+ #
25
+ # Centralized utility method to alias a method on an arbitrary
26
+ # class or module.
27
+ #
28
+ def method_alias(cls, method, name = nil)
29
+ name ||= contextual_name(cls)
30
+
31
+ if cls.method_defined?(method.to_sym) || cls.private_method_defined?(method.to_sym)
32
+
33
+ # Strip '!' or '?' from method if present
34
+ safe_method_name = method.to_s.chop if method.to_s =~ /\?$|\!$/
35
+ safe_method_name ||= method
36
+
37
+ without_appoptics = "#{safe_method_name}_without_appoptics"
38
+ with_appoptics = "#{safe_method_name}_with_appoptics"
39
+
40
+ # Only alias if we haven't done so already
41
+ unless cls.method_defined?(without_appoptics.to_sym) ||
42
+ cls.private_method_defined?(without_appoptics.to_sym)
43
+
44
+ cls.class_eval do
45
+ alias_method without_appoptics, method.to_s
46
+ alias_method method.to_s, with_appoptics
47
+ end
48
+ end
49
+ else
50
+ AppOpticsAPM.logger.warn "[appoptics_apm/loading] Couldn't properly instrument #{name}.#{method}. Partial traces may occur."
51
+ end
52
+ end
53
+
54
+ ##
55
+ # class_method_alias
56
+ #
57
+ # Centralized utility method to alias a class method on an arbitrary
58
+ # class or module
59
+ #
60
+ def class_method_alias(cls, method, name = nil)
61
+ name ||= contextual_name(cls)
62
+
63
+ if cls.singleton_methods.include? method.to_sym
64
+
65
+ # Strip '!' or '?' from method if present
66
+ safe_method_name = method.to_s.chop if method.to_s =~ /\?$|\!$/
67
+ safe_method_name ||= method
68
+
69
+ without_appoptics = "#{safe_method_name}_without_appoptics"
70
+ with_appoptics = "#{safe_method_name}_with_appoptics"
71
+
72
+ # Only alias if we haven't done so already
73
+ unless cls.singleton_methods.include? without_appoptics.to_sym
74
+ cls.singleton_class.send(:alias_method, without_appoptics, method.to_s)
75
+ cls.singleton_class.send(:alias_method, method.to_s, with_appoptics)
76
+ end
77
+ else
78
+ AppOpticsAPM.logger.warn "[appoptics_apm/loading] Couldn't properly instrument #{name}. Partial traces may occur."
79
+ end
80
+ end
81
+
82
+ ##
83
+ # send_extend
84
+ #
85
+ # Centralized utility method to send an extend call for an
86
+ # arbitrary class
87
+ def send_extend(target_cls, cls)
88
+ target_cls.send(:extend, cls) if defined?(target_cls)
89
+ end
90
+
91
+ ##
92
+ # send_include
93
+ #
94
+ # Centralized utility method to send a include call for an
95
+ # arbitrary class
96
+ def send_include(target_cls, cls)
97
+ target_cls.send(:include, cls) if defined?(target_cls)
98
+ end
99
+
100
+ ##
101
+ # static_asset?
102
+ #
103
+ # Given a path, this method determines whether it is a static asset or not (based
104
+ # solely on filename)
105
+ #
106
+ def static_asset?(path)
107
+ path =~ Regexp.new(AppOpticsAPM::Config[:dnt_regexp], AppOpticsAPM::Config[:dnt_opts])
108
+ rescue => e
109
+ AppOpticsAPM.logger.warn "[AppOpticsAPM/debug] Could not apply Regex.new to path. #{e.inspect}"
110
+ false
111
+ end
112
+
113
+ ##
114
+ # prettify
115
+ #
116
+ # Even to my surprise, 'prettify' is a real word:
117
+ # transitive v. To make pretty or prettier, especially in a superficial or insubstantial way.
118
+ # from The American Heritage Dictionary of the English Language, 4th Edition
119
+ #
120
+ # This method makes things 'purty' for reporting.
121
+ def prettify(x)
122
+ if (x.to_s =~ /^#</) == 0
123
+ x.class.to_s
124
+ else
125
+ x.to_s
126
+ end
127
+ end
128
+
129
+ ##
130
+ # upcase
131
+ #
132
+ # Occasionally, we want to send some values in all caps. This is true
133
+ # for things like HTTP scheme or method. This takes anything and does
134
+ # it's best to safely convert it to a string (if needed) and convert it
135
+ # to all uppercase.
136
+ def upcase(o)
137
+ if o.is_a?(String) || o.respond_to?(:to_s)
138
+ o.to_s.upcase
139
+ else
140
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] AppOpticsAPM::Util.upcase: could not convert #{o.class}"
141
+ 'UNKNOWN'
142
+ end
143
+ end
144
+
145
+ ##
146
+ # to_query
147
+ #
148
+ # Used to convert a hash into a URL # query.
149
+ #
150
+ def to_query(h)
151
+ return '' unless h.is_a?(Hash)
152
+
153
+ result = []
154
+
155
+ h.each { |k, v| result.push(k.to_s + '=' + v.to_s) }
156
+ result.sort.join('&')
157
+ end
158
+
159
+ ##
160
+ # sanitize_sql
161
+ #
162
+ # Used to remove query literals from SQL. Used by all
163
+ # DB adapter instrumentation.
164
+ #
165
+ # The regular expression passed to String.gsub is configurable
166
+ # via AppOpticsAPM::Config[:sanitize_sql_regexp] and
167
+ # AppOpticsAPM::Config[:sanitize_sql_opts].
168
+ #
169
+ def sanitize_sql(sql)
170
+ return sql unless AppOpticsAPM::Config[:sanitize_sql]
171
+
172
+ regexp = Regexp.new(AppOpticsAPM::Config[:sanitize_sql_regexp], AppOpticsAPM::Config[:sanitize_sql_opts])
173
+ sql.gsub(/\\\'/,'').gsub(regexp, '?')
174
+ end
175
+
176
+ ##
177
+ # legacy_build_init_report
178
+ #
179
+ # Internal: Build a hash of KVs that reports on the status of the
180
+ # running environment. This is used on stack boot in __Init reporting
181
+ # and for AppOpticsAPM.support_report.
182
+ #
183
+ # This legacy version of build_init_report is used for apps without Bundler.
184
+ #
185
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
186
+ #
187
+ # @deprecated Please use {#build_init_report} instead
188
+ def legacy_build_init_report
189
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] Oboe::API will be deprecated in a future version.'
190
+ platform_info = {}
191
+
192
+ begin
193
+ # Report the framework in use
194
+ if defined?(::RailsLts::VERSION)
195
+ platform_info['Ruby.RailsLts.Version'] = "RailsLts-#{::RailsLts::VERSION}"
196
+ elsif defined?(::Rails.version)
197
+ platform_info['Ruby.Rails.Version'] = "Rails-#{::Rails.version}"
198
+ end
199
+ platform_info['Ruby.Grape.Version'] = "Grape-#{::Grape::VERSION}" if defined?(::Grape::VERSION)
200
+ platform_info['Ruby.Cramp.Version'] = "Cramp-#{::Cramp::VERSION}" if defined?(::Cramp::VERSION)
201
+
202
+ if defined?(::Padrino::VERSION)
203
+ platform_info['Ruby.Padrino.Version'] = "Padrino-#{::Padrino::VERSION}"
204
+ elsif defined?(::Sinatra::VERSION)
205
+ platform_info['Ruby.Sinatra.Version'] = "Sinatra-#{::Sinatra::VERSION}"
206
+ end
207
+
208
+ # Report the instrumented libraries
209
+ platform_info['Ruby.Cassandra.Version'] = "Cassandra-#{::Cassandra.VERSION}" if defined?(::Cassandra.VERSION)
210
+ platform_info['Ruby.Curb.Version'] = "Curb-#{::Curl::VERSION}" if defined?(::Curl::VERSION)
211
+ platform_info['Ruby.Dalli.Version'] = "Dalli-#{::Dalli::VERSION}" if defined?(::Dalli::VERSION)
212
+ platform_info['Ruby.Excon.Version'] = "Excon-#{::Excon::VERSION}" if defined?(::Excon::VERSION)
213
+ platform_info['Ruby.Faraday.Version'] = "Faraday-#{::Faraday::VERSION}" if defined?(::Faraday::VERSION)
214
+ platform_info['Ruby.HTTPClient.Version'] = "HTTPClient-#{::HTTPClient::VERSION}" if defined?(::HTTPClient::VERSION)
215
+ platform_info['Ruby.Memcached.Version'] = "Memcached-#{::Memcached::VERSION}" if defined?(::Memcached::VERSION)
216
+ platform_info['Ruby.Moped.Version'] = "Moped-#{::Moped::VERSION}" if defined?(::Moped::VERSION)
217
+ platform_info['Ruby.Redis.Version'] = "Redis-#{::Redis::VERSION}" if defined?(::Redis::VERSION)
218
+ platform_info['Ruby.Resque.Version'] = "Resque-#{::Resque::VERSION}" if defined?(::Resque::VERSION)
219
+ platform_info['Ruby.RestClient.Version'] = "RestClient-#{::RestClient::VERSION}" if defined?(::RestClient::VERSION)
220
+ platform_info['Ruby.Sidekiq.Version'] = "Sidekiq-#{::Sidekiq::VERSION}" if defined?(::Sidekiq::VERSION)
221
+ platform_info['Ruby.Typhoeus.Version'] = "Typhoeus-#{::Typhoeus::VERSION}" if defined?(::Typhoeus::VERSION)
222
+
223
+ if Gem.loaded_specs.key?('delayed_job')
224
+ # Oddly, DelayedJob doesn't have an embedded version number so we get it from the loaded
225
+ # gem specs.
226
+ version = Gem.loaded_specs['delayed_job'].version.to_s
227
+ platform_info['Ruby.DelayedJob.Version'] = "DelayedJob-#{version}"
228
+ end
229
+
230
+ # Special case since the Mongo 1.x driver doesn't embed the version number in the gem directly
231
+ if ::Gem.loaded_specs.key?('mongo')
232
+ platform_info['Ruby.Mongo.Version'] = "Mongo-#{::Gem.loaded_specs['mongo'].version}"
233
+ end
234
+
235
+ # Report the DB adapter in use
236
+ platform_info['Ruby.Mysql.Version'] = Mysql::GemVersion::VERSION if defined?(Mysql::GemVersion::VERSION)
237
+ platform_info['Ruby.PG.Version'] = PG::VERSION if defined?(PG::VERSION)
238
+ platform_info['Ruby.Mysql2.Version'] = Mysql2::VERSION if defined?(Mysql2::VERSION)
239
+ platform_info['Ruby.Sequel.Version'] = ::Sequel::VERSION if defined?(::Sequel::VERSION)
240
+ rescue StandardError, ScriptError => e
241
+ # Also rescue ScriptError (aka SyntaxError) in case one of the expected
242
+ # version defines don't exist
243
+
244
+ platform_info['Error'] = "Error in legacy_build_init_report: #{e.message}"
245
+
246
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Error in legacy_build_init_report: #{e.message}"
247
+ AppOpticsAPM.logger.debug e.backtrace
248
+ end
249
+ platform_info
250
+ end
251
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
252
+
253
+ ##
254
+ # build_init_report
255
+ #
256
+ # Internal: Build a hash of KVs that reports on the status of the
257
+ # running environment. This is used on stack boot in __Init reporting
258
+ # and for AppOpticsAPM.support_report.
259
+ #
260
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
261
+ def build_init_report
262
+ platform_info = { '__Init' => 1 }
263
+
264
+ begin
265
+ platform_info['Force'] = true
266
+ platform_info['Ruby.Platform.Version'] = RUBY_PLATFORM
267
+ platform_info['Ruby.Version'] = RUBY_VERSION
268
+ platform_info['Ruby.AppOptics.Version'] = AppOpticsAPM::Version::STRING
269
+
270
+ clib_version_file = File.join(Gem::Specification.find_by_name('appoptics_apm').gem_dir, 'ext', 'oboe_metal', 'src', 'VERSION')
271
+ platform_info['Ruby.clib.Version'] = File.read(clib_version_file).chomp
272
+ platform_info['RubyHeroku.AppOpticsAPM.Version'] = AppOpticsAPMHeroku::Version::STRING if defined?(AppOpticsAPMHeroku)
273
+ platform_info['Ruby.TraceMode.Version'] = AppOpticsAPM::Config[:tracing_mode]
274
+
275
+ # Collect up the loaded gems
276
+ if defined?(Gem) && Gem.respond_to?(:loaded_specs)
277
+ Gem.loaded_specs.each_pair { |k, v|
278
+ platform_info["Ruby.#{k}.Version"] = v.version.to_s
279
+ }
280
+ else
281
+ platform_info.merge!(legacy_build_init_report)
282
+ end
283
+
284
+ # Report the server in use (if possible)
285
+ if defined?(::Unicorn::Const::UNICORN_VERSION)
286
+ platform_info['Ruby.AppContainer.Version'] = "Unicorn-#{::Unicorn::Const::UNICORN_VERSION}"
287
+ elsif defined?(::Puma::Const::PUMA_VERSION)
288
+ platform_info['Ruby.AppContainer.Version'] = "Puma-#{::Puma::Const::PUMA_VERSION} (#{::Puma::Const::CODE_NAME})"
289
+ elsif defined?(::PhusionPassenger::PACKAGE_NAME)
290
+ platform_info['Ruby.AppContainer.Version'] = "#{::PhusionPassenger::PACKAGE_NAME}-#{::PhusionPassenger::VERSION_STRING}"
291
+ elsif defined?(::Thin::VERSION::STRING)
292
+ platform_info['Ruby.AppContainer.Version'] = "Thin-#{::Thin::VERSION::STRING} (#{::Thin::VERSION::CODENAME})"
293
+ elsif defined?(::Mongrel::Const::MONGREL_VERSION)
294
+ platform_info['Ruby.AppContainer.Version'] = "Mongrel-#{::Mongrel::Const::MONGREL_VERSION}"
295
+ elsif defined?(::Mongrel2::VERSION)
296
+ platform_info['Ruby.AppContainer.Version'] = "Mongrel2-#{::Mongrel2::VERSION}"
297
+ elsif defined?(::Trinidad::VERSION)
298
+ platform_info['Ruby.AppContainer.Version'] = "Trinidad-#{::Trinidad::VERSION}"
299
+ elsif defined?(::WEBrick::VERSION)
300
+ platform_info['Ruby.AppContainer.Version'] = "WEBrick-#{::WEBrick::VERSION}"
301
+ else
302
+ platform_info['Ruby.AppContainer.Version'] = File.basename($PROGRAM_NAME)
303
+ end
304
+
305
+ rescue StandardError, ScriptError => e
306
+ # Also rescue ScriptError (aka SyntaxError) in case one of the expected
307
+ # version defines don't exist
308
+
309
+ platform_info['Error'] = "Error in build_report: #{e.message}"
310
+
311
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Error in build_init_report: #{e.message}"
312
+ AppOpticsAPM.logger.debug e.backtrace
313
+ end
314
+ platform_info
315
+ end
316
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
317
+ end
318
+ end
319
+ end