appoptics_apm_mnfst 4.5.2

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 (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