appoptics_apm 4.0.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 (226) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +43 -0
  3. data/.dockerignore +5 -0
  4. data/.gitignore +23 -0
  5. data/.rubocop.yml +5 -0
  6. data/.travis.yml +82 -0
  7. data/CHANGELOG.md +769 -0
  8. data/CONFIG.md +33 -0
  9. data/Dockerfile +41 -0
  10. data/Dockerfile_test +66 -0
  11. data/Gemfile +41 -0
  12. data/LICENSE +193 -0
  13. data/README.md +351 -0
  14. data/Rakefile +202 -0
  15. data/Vagrantfile +67 -0
  16. data/appoptics_apm.gemspec +55 -0
  17. data/build_gems.sh +15 -0
  18. data/docker-compose.yml +73 -0
  19. data/examples/DNT.md +35 -0
  20. data/examples/carrying_context.rb +220 -0
  21. data/examples/instrumenting_metal_controller.rb +8 -0
  22. data/examples/puma_on_heroku_config.rb +17 -0
  23. data/examples/tracing_async_threads.rb +124 -0
  24. data/examples/tracing_background_jobs.rb +53 -0
  25. data/examples/tracing_forked_processes.rb +99 -0
  26. data/examples/unicorn_on_heroku_config.rb +28 -0
  27. data/ext/oboe_metal/extconf.rb +54 -0
  28. data/ext/oboe_metal/lib/.keep +0 -0
  29. data/ext/oboe_metal/lib/liboboe-1.0.so.0.0.0 +0 -0
  30. data/ext/oboe_metal/noop/noop.c +7 -0
  31. data/ext/oboe_metal/src/VERSION +1 -0
  32. data/ext/oboe_metal/src/bson/bson.h +221 -0
  33. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  34. data/ext/oboe_metal/src/oboe.h +883 -0
  35. data/ext/oboe_metal/src/oboe.hpp +793 -0
  36. data/ext/oboe_metal/src/oboe_debug.h +50 -0
  37. data/ext/oboe_metal/src/oboe_wrap.cxx +6088 -0
  38. data/ext/oboe_metal/tests/test.rb +11 -0
  39. data/gemfiles/delayed_job.gemfile +36 -0
  40. data/gemfiles/frameworks.gemfile +44 -0
  41. data/gemfiles/instrumentation_mocked.gemfile +29 -0
  42. data/gemfiles/libraries.gemfile +85 -0
  43. data/gemfiles/rails23.gemfile +39 -0
  44. data/gemfiles/rails30.gemfile +42 -0
  45. data/gemfiles/rails31.gemfile +44 -0
  46. data/gemfiles/rails32.gemfile +54 -0
  47. data/gemfiles/rails40.gemfile +27 -0
  48. data/gemfiles/rails41.gemfile +27 -0
  49. data/gemfiles/rails42.gemfile +35 -0
  50. data/gemfiles/rails50.gemfile +44 -0
  51. data/gemfiles/rails51.gemfile +44 -0
  52. data/get_version.rb +5 -0
  53. data/init.rb +4 -0
  54. data/lib/appoptics_apm/api/layerinit.rb +39 -0
  55. data/lib/appoptics_apm/api/logging.rb +359 -0
  56. data/lib/appoptics_apm/api/memcache.rb +34 -0
  57. data/lib/appoptics_apm/api/profiling.rb +201 -0
  58. data/lib/appoptics_apm/api/tracing.rb +152 -0
  59. data/lib/appoptics_apm/api/util.rb +128 -0
  60. data/lib/appoptics_apm/api.rb +18 -0
  61. data/lib/appoptics_apm/base.rb +252 -0
  62. data/lib/appoptics_apm/config.rb +281 -0
  63. data/lib/appoptics_apm/frameworks/grape.rb +93 -0
  64. data/lib/appoptics_apm/frameworks/padrino/templates.rb +58 -0
  65. data/lib/appoptics_apm/frameworks/padrino.rb +52 -0
  66. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +106 -0
  67. data/lib/appoptics_apm/frameworks/rails/inst/action_controller2.rb +61 -0
  68. data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +58 -0
  69. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
  70. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  71. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  72. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +58 -0
  73. data/lib/appoptics_apm/frameworks/rails/inst/action_view_2x.rb +56 -0
  74. data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +50 -0
  75. data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
  76. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  77. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
  78. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
  79. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +120 -0
  80. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +101 -0
  81. data/lib/appoptics_apm/frameworks/rails.rb +116 -0
  82. data/lib/appoptics_apm/frameworks/sinatra/templates.rb +56 -0
  83. data/lib/appoptics_apm/frameworks/sinatra.rb +71 -0
  84. data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
  85. data/lib/appoptics_apm/inst/bunny-consumer.rb +92 -0
  86. data/lib/appoptics_apm/inst/curb.rb +329 -0
  87. data/lib/appoptics_apm/inst/dalli.rb +85 -0
  88. data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
  89. data/lib/appoptics_apm/inst/em-http-request.rb +105 -0
  90. data/lib/appoptics_apm/inst/excon.rb +130 -0
  91. data/lib/appoptics_apm/inst/faraday.rb +77 -0
  92. data/lib/appoptics_apm/inst/http.rb +83 -0
  93. data/lib/appoptics_apm/inst/httpclient.rb +176 -0
  94. data/lib/appoptics_apm/inst/memcache.rb +102 -0
  95. data/lib/appoptics_apm/inst/memcached.rb +94 -0
  96. data/lib/appoptics_apm/inst/mongo.rb +242 -0
  97. data/lib/appoptics_apm/inst/mongo2.rb +225 -0
  98. data/lib/appoptics_apm/inst/moped.rb +466 -0
  99. data/lib/appoptics_apm/inst/rack.rb +146 -0
  100. data/lib/appoptics_apm/inst/redis.rb +275 -0
  101. data/lib/appoptics_apm/inst/resque.rb +151 -0
  102. data/lib/appoptics_apm/inst/rest-client.rb +50 -0
  103. data/lib/appoptics_apm/inst/sequel.rb +178 -0
  104. data/lib/appoptics_apm/inst/sidekiq-client.rb +53 -0
  105. data/lib/appoptics_apm/inst/sidekiq-worker.rb +67 -0
  106. data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
  107. data/lib/appoptics_apm/inst/typhoeus.rb +113 -0
  108. data/lib/appoptics_apm/instrumentation.rb +22 -0
  109. data/lib/appoptics_apm/legacy_method_profiling.rb +97 -0
  110. data/lib/appoptics_apm/loading.rb +66 -0
  111. data/lib/appoptics_apm/logger.rb +41 -0
  112. data/lib/appoptics_apm/method_profiling.rb +33 -0
  113. data/lib/appoptics_apm/ruby.rb +35 -0
  114. data/lib/appoptics_apm/support.rb +135 -0
  115. data/lib/appoptics_apm/test.rb +94 -0
  116. data/lib/appoptics_apm/thread_local.rb +26 -0
  117. data/lib/appoptics_apm/util.rb +312 -0
  118. data/lib/appoptics_apm/version.rb +15 -0
  119. data/lib/appoptics_apm/xtrace.rb +103 -0
  120. data/lib/appoptics_apm.rb +72 -0
  121. data/lib/joboe_metal.rb +214 -0
  122. data/lib/oboe/README +2 -0
  123. data/lib/oboe/backward_compatibility.rb +80 -0
  124. data/lib/oboe/inst/rack.rb +11 -0
  125. data/lib/oboe.rb +7 -0
  126. data/lib/oboe_metal.rb +187 -0
  127. data/lib/rails/generators/appoptics_apm/install_generator.rb +45 -0
  128. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +222 -0
  129. data/ruby_setup.sh +47 -0
  130. data/run_docker_build_gem_upload_to_packagecloud.sh +20 -0
  131. data/run_tests_docker.rb +32 -0
  132. data/test/benchmark/README.md +65 -0
  133. data/test/benchmark/logging_bench.rb +54 -0
  134. data/test/benchmark/with_libraries_gemfile/bunny_bench.rb +69 -0
  135. data/test/benchmark/with_rails5x_gemfile/action_controller5x_bench.rb +43 -0
  136. data/test/frameworks/apps/grape_nested.rb +33 -0
  137. data/test/frameworks/apps/grape_simple.rb +80 -0
  138. data/test/frameworks/apps/padrino_simple.rb +80 -0
  139. data/test/frameworks/apps/sinatra_simple.rb +55 -0
  140. data/test/frameworks/grape_test.rb +286 -0
  141. data/test/frameworks/padrino_test.rb +222 -0
  142. data/test/frameworks/rails3x_test.rb +554 -0
  143. data/test/frameworks/rails4x_test.rb +570 -0
  144. data/test/frameworks/rails5x_api_test.rb +210 -0
  145. data/test/frameworks/rails5x_test.rb +376 -0
  146. data/test/frameworks/rails_shared_tests.rb +172 -0
  147. data/test/frameworks/sinatra_test.rb +140 -0
  148. data/test/instrumentation/bunny_client_test.rb +276 -0
  149. data/test/instrumentation/bunny_consumer_test.rb +204 -0
  150. data/test/instrumentation/curb_test.rb +398 -0
  151. data/test/instrumentation/dalli_test.rb +177 -0
  152. data/test/instrumentation/em_http_request_test.rb +89 -0
  153. data/test/instrumentation/excon_test.rb +231 -0
  154. data/test/instrumentation/faraday_test.rb +228 -0
  155. data/test/instrumentation/http_test.rb +143 -0
  156. data/test/instrumentation/httpclient_test.rb +320 -0
  157. data/test/instrumentation/memcache_test.rb +260 -0
  158. data/test/instrumentation/memcached_test.rb +229 -0
  159. data/test/instrumentation/mongo_v1_test.rb +479 -0
  160. data/test/instrumentation/mongo_v2_index_test.rb +124 -0
  161. data/test/instrumentation/mongo_v2_test.rb +584 -0
  162. data/test/instrumentation/mongo_v2_view_test.rb +435 -0
  163. data/test/instrumentation/moped_test.rb +517 -0
  164. data/test/instrumentation/rack_test.rb +165 -0
  165. data/test/instrumentation/redis_hashes_test.rb +268 -0
  166. data/test/instrumentation/redis_keys_test.rb +321 -0
  167. data/test/instrumentation/redis_lists_test.rb +310 -0
  168. data/test/instrumentation/redis_misc_test.rb +163 -0
  169. data/test/instrumentation/redis_sets_test.rb +296 -0
  170. data/test/instrumentation/redis_sortedsets_test.rb +328 -0
  171. data/test/instrumentation/redis_strings_test.rb +349 -0
  172. data/test/instrumentation/resque_test.rb +185 -0
  173. data/test/instrumentation/rest-client_test.rb +288 -0
  174. data/test/instrumentation/sequel_mysql2_test.rb +353 -0
  175. data/test/instrumentation/sequel_mysql_test.rb +334 -0
  176. data/test/instrumentation/sequel_pg_test.rb +336 -0
  177. data/test/instrumentation/sidekiq-client_test.rb +159 -0
  178. data/test/instrumentation/sidekiq-worker_test.rb +180 -0
  179. data/test/instrumentation/twitter-cassandra_test.rb +424 -0
  180. data/test/instrumentation/typhoeus_test.rb +284 -0
  181. data/test/jobs/delayed_job/db_worker_job.rb +29 -0
  182. data/test/jobs/delayed_job/error_worker_job.rb +10 -0
  183. data/test/jobs/delayed_job/remote_call_worker_job.rb +20 -0
  184. data/test/jobs/resque/db_worker_job.rb +29 -0
  185. data/test/jobs/resque/error_worker_job.rb +10 -0
  186. data/test/jobs/resque/remote_call_worker_job.rb +20 -0
  187. data/test/jobs/sidekiq/db_worker_job.rb +29 -0
  188. data/test/jobs/sidekiq/error_worker_job.rb +10 -0
  189. data/test/jobs/sidekiq/remote_call_worker_job.rb +20 -0
  190. data/test/minitest_helper.rb +276 -0
  191. data/test/mocked/curb_mocked_test.rb +311 -0
  192. data/test/mocked/excon_mocked_test.rb +166 -0
  193. data/test/mocked/faraday_mocked_test.rb +93 -0
  194. data/test/mocked/http_mocked_test.rb +129 -0
  195. data/test/mocked/httpclient_mocked_test.rb +245 -0
  196. data/test/mocked/rest_client_mocked_test.rb +103 -0
  197. data/test/mocked/typhoeus_mocked_test.rb +192 -0
  198. data/test/models/widget.rb +36 -0
  199. data/test/profiling/legacy_method_profiling_test.rb +201 -0
  200. data/test/profiling/method_profiling_test.rb +631 -0
  201. data/test/queues/delayed_job-client_test.rb +95 -0
  202. data/test/queues/delayed_job-worker_test.rb +91 -0
  203. data/test/reporter/reporter_test.rb +14 -0
  204. data/test/servers/delayed_job.rb +107 -0
  205. data/test/servers/rackapp_8101.rb +29 -0
  206. data/test/servers/rails3x_8140.rb +96 -0
  207. data/test/servers/rails4x_8140.rb +96 -0
  208. data/test/servers/rails5x_8140.rb +95 -0
  209. data/test/servers/rails5x_api_8150.rb +78 -0
  210. data/test/servers/sidekiq.rb +29 -0
  211. data/test/servers/sidekiq.yml +7 -0
  212. data/test/servers/sidekiq_initializer.rb +25 -0
  213. data/test/settings +0 -0
  214. data/test/support/auto_tracing_test.rb +50 -0
  215. data/test/support/backcompat_test.rb +276 -0
  216. data/test/support/config_test.rb +149 -0
  217. data/test/support/dnt_test.rb +98 -0
  218. data/test/support/init_report_test.rb +25 -0
  219. data/test/support/liboboe_settings_test.rb +110 -0
  220. data/test/support/logging_test.rb +130 -0
  221. data/test/support/noop_test.rb +88 -0
  222. data/test/support/sql_sanitize_test.rb +55 -0
  223. data/test/support/tracing_mode_test.rb +33 -0
  224. data/test/support/tvalias_test.rb +15 -0
  225. data/test/support/xtrace_test.rb +41 -0
  226. metadata +475 -0
@@ -0,0 +1,312 @@
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
+ end
109
+
110
+ ##
111
+ # prettify
112
+ #
113
+ # Even to my surprise, 'prettify' is a real word:
114
+ # transitive v. To make pretty or prettier, especially in a superficial or insubstantial way.
115
+ # from The American Heritage Dictionary of the English Language, 4th Edition
116
+ #
117
+ # This method makes things 'purty' for reporting.
118
+ def prettify(x)
119
+ if (x.to_s =~ /^#</) == 0
120
+ x.class.to_s
121
+ else
122
+ x.to_s
123
+ end
124
+ end
125
+
126
+ ##
127
+ # upcase
128
+ #
129
+ # Occasionally, we want to send some values in all caps. This is true
130
+ # for things like HTTP scheme or method. This takes anything and does
131
+ # it's best to safely convert it to a string (if needed) and convert it
132
+ # to all uppercase.
133
+ def upcase(o)
134
+ if o.is_a?(String) || o.respond_to?(:to_s)
135
+ o.to_s.upcase
136
+ else
137
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] AppOpticsAPM::Util.upcase: could not convert #{o.class}"
138
+ 'UNKNOWN'
139
+ end
140
+ end
141
+
142
+ ##
143
+ # to_query
144
+ #
145
+ # Used to convert a hash into a URL # query.
146
+ #
147
+ def to_query(h)
148
+ return '' unless h.is_a?(Hash)
149
+
150
+ result = []
151
+
152
+ h.each { |k, v| result.push(k.to_s + '=' + v.to_s) }
153
+ result.sort.join('&')
154
+ end
155
+
156
+ ##
157
+ # sanitize_sql
158
+ #
159
+ # Used to remove query literals from SQL. Used by all
160
+ # DB adapter instrumentation.
161
+ #
162
+ # The regular expression passed to String.gsub is configurable
163
+ # via AppOpticsAPM::Config[:sanitize_sql_regexp] and
164
+ # AppOpticsAPM::Config[:sanitize_sql_opts].
165
+ #
166
+ def sanitize_sql(sql)
167
+ return sql unless AppOpticsAPM::Config[:sanitize_sql]
168
+
169
+ regexp = Regexp.new(AppOpticsAPM::Config[:sanitize_sql_regexp], AppOpticsAPM::Config[:sanitize_sql_opts])
170
+ sql.gsub(regexp, '?')
171
+ end
172
+
173
+ ##
174
+ # legacy_build_init_report
175
+ #
176
+ # Internal: Build a hash of KVs that reports on the status of the
177
+ # running environment. This is used on stack boot in __Init reporting
178
+ # and for AppOpticsAPM.support_report.
179
+ #
180
+ # This legacy version of build_init_report is used for apps without Bundler.
181
+ #
182
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
183
+ def legacy_build_init_report
184
+ platform_info = {}
185
+
186
+ begin
187
+ # Report the framework in use
188
+ if defined?(::RailsLts::VERSION)
189
+ platform_info['Ruby.RailsLts.Version'] = "RailsLts-#{::RailsLts::VERSION}"
190
+ elsif defined?(::Rails.version)
191
+ platform_info['Ruby.Rails.Version'] = "Rails-#{::Rails.version}"
192
+ end
193
+ platform_info['Ruby.Grape.Version'] = "Grape-#{::Grape::VERSION}" if defined?(::Grape::VERSION)
194
+ platform_info['Ruby.Cramp.Version'] = "Cramp-#{::Cramp::VERSION}" if defined?(::Cramp::VERSION)
195
+
196
+ if defined?(::Padrino::VERSION)
197
+ platform_info['Ruby.Padrino.Version'] = "Padrino-#{::Padrino::VERSION}"
198
+ elsif defined?(::Sinatra::VERSION)
199
+ platform_info['Ruby.Sinatra.Version'] = "Sinatra-#{::Sinatra::VERSION}"
200
+ end
201
+
202
+ # Report the instrumented libraries
203
+ platform_info['Ruby.Cassandra.Version'] = "Cassandra-#{::Cassandra.VERSION}" if defined?(::Cassandra.VERSION)
204
+ platform_info['Ruby.Curb.Version'] = "Curb-#{::Curl::VERSION}" if defined?(::Curl::VERSION)
205
+ platform_info['Ruby.Dalli.Version'] = "Dalli-#{::Dalli::VERSION}" if defined?(::Dalli::VERSION)
206
+ platform_info['Ruby.Excon.Version'] = "Excon-#{::Excon::VERSION}" if defined?(::Excon::VERSION)
207
+ platform_info['Ruby.Faraday.Version'] = "Faraday-#{::Faraday::VERSION}" if defined?(::Faraday::VERSION)
208
+ platform_info['Ruby.HTTPClient.Version'] = "HTTPClient-#{::HTTPClient::VERSION}" if defined?(::HTTPClient::VERSION)
209
+ platform_info['Ruby.MemCache.Version'] = "MemCache-#{::MemCache::VERSION}" if defined?(::MemCache::VERSION)
210
+ platform_info['Ruby.Moped.Version'] = "Moped-#{::Moped::VERSION}" if defined?(::Moped::VERSION)
211
+ platform_info['Ruby.Redis.Version'] = "Redis-#{::Redis::VERSION}" if defined?(::Redis::VERSION)
212
+ platform_info['Ruby.Resque.Version'] = "Resque-#{::Resque::VERSION}" if defined?(::Resque::VERSION)
213
+ platform_info['Ruby.RestClient.Version'] = "RestClient-#{::RestClient::VERSION}" if defined?(::RestClient::VERSION)
214
+ platform_info['Ruby.Sidekiq.Version'] = "Sidekiq-#{::Sidekiq::VERSION}" if defined?(::Sidekiq::VERSION)
215
+ platform_info['Ruby.Typhoeus.Version'] = "Typhoeus-#{::Typhoeus::VERSION}" if defined?(::Typhoeus::VERSION)
216
+
217
+ if Gem.loaded_specs.key?('delayed_job')
218
+ # Oddly, DelayedJob doesn't have an embedded version number so we get it from the loaded
219
+ # gem specs.
220
+ version = Gem.loaded_specs['delayed_job'].version.to_s
221
+ platform_info['Ruby.DelayedJob.Version'] = "DelayedJob-#{version}"
222
+ end
223
+
224
+ # Special case since the Mongo 1.x driver doesn't embed the version number in the gem directly
225
+ if ::Gem.loaded_specs.key?('mongo')
226
+ platform_info['Ruby.Mongo.Version'] = "Mongo-#{::Gem.loaded_specs['mongo'].version}"
227
+ end
228
+
229
+ # Report the DB adapter in use
230
+ platform_info['Ruby.Mysql.Version'] = Mysql::GemVersion::VERSION if defined?(Mysql::GemVersion::VERSION)
231
+ platform_info['Ruby.PG.Version'] = PG::VERSION if defined?(PG::VERSION)
232
+ platform_info['Ruby.Mysql2.Version'] = Mysql2::VERSION if defined?(Mysql2::VERSION)
233
+ platform_info['Ruby.Sequel.Version'] = ::Sequel::VERSION if defined?(::Sequel::VERSION)
234
+ rescue StandardError, ScriptError => e
235
+ # Also rescue ScriptError (aka SyntaxError) in case one of the expected
236
+ # version defines don't exist
237
+
238
+ platform_info['Error'] = "Error in legacy_build_init_report: #{e.message}"
239
+
240
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Error in legacy_build_init_report: #{e.message}"
241
+ AppOpticsAPM.logger.debug e.backtrace
242
+ end
243
+ platform_info
244
+ end
245
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
246
+
247
+ ##
248
+ # build_init_report
249
+ #
250
+ # Internal: Build a hash of KVs that reports on the status of the
251
+ # running environment. This is used on stack boot in __Init reporting
252
+ # and for AppOpticsAPM.support_report.
253
+ #
254
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
255
+ def build_init_report
256
+ platform_info = { '__Init' => 1 }
257
+
258
+ begin
259
+ platform_info['Force'] = true
260
+ platform_info['Ruby.Platform.Version'] = RUBY_PLATFORM
261
+ platform_info['Ruby.Version'] = RUBY_VERSION
262
+ platform_info['Ruby.AppOpticsAPM.Version'] = ::AppOpticsAPM::Version::STRING
263
+ # Should this be the oboe version, separate from the Ruby library's version?
264
+ platform_info['Ruby.Oboe.Version'] = ::AppOpticsAPM::Version::STRING
265
+ platform_info['RubyHeroku.AppOpticsAPM.Version'] = ::AppOpticsAPMHeroku::Version::STRING if defined?(::AppOpticsAPMHeroku)
266
+ platform_info['Ruby.TraceMode.Version'] = ::AppOpticsAPM::Config[:tracing_mode]
267
+
268
+ # Collect up the loaded gems
269
+ if defined?(Gem) && Gem.respond_to?(:loaded_specs)
270
+ Gem.loaded_specs.each_pair { |k, v|
271
+ platform_info["Ruby.#{k}.Version"] = v.version.to_s
272
+ }
273
+ else
274
+ platform_info.merge!(legacy_build_init_report)
275
+ end
276
+
277
+ # Report the server in use (if possible)
278
+ if defined?(::Unicorn::Const::UNICORN_VERSION)
279
+ platform_info['Ruby.AppContainer.Version'] = "Unicorn-#{::Unicorn::Const::UNICORN_VERSION}"
280
+ elsif defined?(::Puma::Const::PUMA_VERSION)
281
+ platform_info['Ruby.AppContainer.Version'] = "Puma-#{::Puma::Const::PUMA_VERSION} (#{::Puma::Const::CODE_NAME})"
282
+ elsif defined?(::PhusionPassenger::PACKAGE_NAME)
283
+ platform_info['Ruby.AppContainer.Version'] = "#{::PhusionPassenger::PACKAGE_NAME}-#{::PhusionPassenger::VERSION_STRING}"
284
+ elsif defined?(::Thin::VERSION::STRING)
285
+ platform_info['Ruby.AppContainer.Version'] = "Thin-#{::Thin::VERSION::STRING} (#{::Thin::VERSION::CODENAME})"
286
+ elsif defined?(::Mongrel::Const::MONGREL_VERSION)
287
+ platform_info['Ruby.AppContainer.Version'] = "Mongrel-#{::Mongrel::Const::MONGREL_VERSION}"
288
+ elsif defined?(::Mongrel2::VERSION)
289
+ platform_info['Ruby.AppContainer.Version'] = "Mongrel2-#{::Mongrel2::VERSION}"
290
+ elsif defined?(::Trinidad::VERSION)
291
+ platform_info['Ruby.AppContainer.Version'] = "Trinidad-#{::Trinidad::VERSION}"
292
+ elsif defined?(::WEBrick::VERSION)
293
+ platform_info['Ruby.AppContainer.Version'] = "WEBrick-#{::WEBrick::VERSION}"
294
+ else
295
+ platform_info['Ruby.AppContainer.Version'] = File.basename($PROGRAM_NAME)
296
+ end
297
+
298
+ rescue StandardError, ScriptError => e
299
+ # Also rescue ScriptError (aka SyntaxError) in case one of the expected
300
+ # version defines don't exist
301
+
302
+ platform_info['Error'] = "Error in build_report: #{e.message}"
303
+
304
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Error in build_init_report: #{e.message}"
305
+ AppOpticsAPM.logger.debug e.backtrace
306
+ end
307
+ platform_info
308
+ end
309
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
310
+ end
311
+ end
312
+ end
@@ -0,0 +1,15 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ ##
6
+ # The current version of the gem. Used mainly by
7
+ # appoptics_apm.gemspec during gem build process
8
+ module Version
9
+ MAJOR = 4
10
+ MINOR = 0
11
+ PATCH = 2
12
+
13
+ STRING = [MAJOR, MINOR, PATCH].compact.join('.')
14
+ end
15
+ end
@@ -0,0 +1,103 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ ##
6
+ # Methods to act on, manipulate or investigate an X-Trace
7
+ # value
8
+ module XTrace
9
+ class << self
10
+ ##
11
+ # AppOpticsAPM::XTrace.valid?
12
+ #
13
+ # Perform basic validation on a potential X-Trace ID
14
+ #
15
+ def valid?(xtrace)
16
+ # Shouldn't be nil
17
+ return false unless xtrace
18
+
19
+ # The X-Trace ID shouldn't be an initialized empty ID
20
+ return false if (xtrace =~ /^2b0000000/i) == 0
21
+
22
+ # Valid X-Trace IDs have a length of 60 bytes and start with '2b'
23
+ return false unless xtrace.length == 60 && (xtrace =~ /^2b/i) == 0
24
+
25
+ true
26
+ rescue StandardError => e
27
+ AppOpticsAPM.logger.debug e.message
28
+ AppOpticsAPM.logger.debug e.backtrace
29
+ false
30
+ end
31
+
32
+ def sampled?(xtrace)
33
+ xtrace[59].to_i & 1 == 1
34
+ end
35
+
36
+ def set_sampled(xtrace)
37
+ xtrace[59] = (xtrace[59].hex | 1).to_s(16).upcase
38
+ end
39
+
40
+ def unset_sampled(xtrace)
41
+ xtrace[59] = (~(~xtrace[59].hex | 1)).to_s(16).upcase
42
+ end
43
+
44
+ ##
45
+ # AppOpticsAPM::XTrace.task_id
46
+ #
47
+ # Extract and return the task_id portion of an X-Trace ID
48
+ #
49
+ def task_id(xtrace)
50
+ return nil unless AppOpticsAPM::XTrace.valid?(xtrace)
51
+
52
+ xtrace[2..41]
53
+ rescue StandardError => e
54
+ AppOpticsAPM.logger.debug e.message
55
+ AppOpticsAPM.logger.debug e.backtrace
56
+ return nil
57
+ end
58
+
59
+ ##
60
+ # AppOpticsAPM::XTrace.edge_id
61
+ #
62
+ # Extract and return the edge_id portion of an X-Trace ID
63
+ #
64
+ def edge_id(xtrace)
65
+ return nil unless AppOpticsAPM::XTrace.valid?(xtrace)
66
+
67
+ xtrace[42..57]
68
+ rescue StandardError => e
69
+ AppOpticsAPM.logger.debug e.message
70
+ AppOpticsAPM.logger.debug e.backtrace
71
+ return nil
72
+ end
73
+
74
+ ##
75
+ # continue_service_context
76
+ #
77
+ # In the case of service calls such as external HTTP requests, we
78
+ # pass along X-Trace headers so that request context can be maintained
79
+ # across servers and applications.
80
+ #
81
+ # Remote requests can return a X-Trace header in which case we want
82
+ # to pickup on and continue the context in most cases.
83
+ #
84
+ # @start is the context just before the outgoing request
85
+ #
86
+ # @finish is the context returned to us (as an HTTP response header
87
+ # if that be the case)
88
+ #
89
+ def continue_service_context(start, finish)
90
+ if AppOpticsAPM::XTrace.valid?(finish) && AppOpticsAPM.tracing?
91
+
92
+ # Assure that we received back a valid X-Trace with the same task_id
93
+ # and the sampling bit is set, otherwise it is a response from a non-sampling service
94
+ if AppOpticsAPM::XTrace.task_id(start) == AppOpticsAPM::XTrace.task_id(finish) && AppOpticsAPM::XTrace.sampled?(finish)
95
+ AppOpticsAPM::Context.fromString(finish)
96
+ else
97
+ AppOpticsAPM.logger.debug "[XTrace] Sampling flag unset or mismatched start and finish ids:\n#{start}\n#{finish}"
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,72 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ # Backward compatibility for supported environment variables
5
+ ENV['APPOPTICS_GEM_VERBOSE'] = ENV['OBOE_GEM_VERBOSE'] if ENV.key?('OBOE_GEM_VERBOSE')
6
+ ENV['APPOPTICS_GEM_TEST'] = ENV['OBOE_GEM_TEST'] if ENV.key?('OBOE_GEM_TEST')
7
+
8
+ begin
9
+ require 'openssl'
10
+ require 'appoptics_apm/version'
11
+ require 'appoptics_apm/thread_local'
12
+ require 'appoptics_apm/logger'
13
+ require 'appoptics_apm/util'
14
+ require 'appoptics_apm/xtrace'
15
+ require 'appoptics_apm/support'
16
+
17
+ # If OboeHeroku is already defined then we are in a PaaS environment
18
+ # with an alternate metal (see the oboe-heroku gem)
19
+ unless defined?(OboeHeroku)
20
+ require 'appoptics_apm/base'
21
+ AppOpticsAPM.loaded = false
22
+
23
+ begin
24
+ if RUBY_PLATFORM == 'java'
25
+ require '/usr/local/tracelytics/tracelyticsagent.jar'
26
+ require 'joboe_metal'
27
+ elsif RUBY_PLATFORM =~ /linux/
28
+ require "oboe_metal.so"
29
+ require "oboe_metal.rb" # sets AppOpticsAPM.loaded = true if successful
30
+ else
31
+ $stderr.puts '==================================================================='
32
+ $stderr.puts "AppOptics warning: Platform #{RUBY_PLATFORM} not yet supported."
33
+ $stderr.puts 'see: https://docs.appoptics.com/kb/apm_tracing/supported_platforms/'
34
+ $stderr.puts 'Tracing disabled.'
35
+ $stderr.puts 'Contact support@appoptics.com if this is unexpected.'
36
+ $stderr.puts '==================================================================='
37
+ end
38
+ rescue LoadError
39
+ unless ENV['RAILS_GROUP'] == 'assets' or ENV['IGNORE_APPOPTICS_WARNING']
40
+ $stderr.puts '=============================================================='
41
+ $stderr.puts 'Missing AppOpticsAPM libraries. Tracing disabled.'
42
+ $stderr.puts 'See: https://docs.appoptics.com/kb/apm_tracing/ruby/'
43
+ $stderr.puts '=============================================================='
44
+ end
45
+ end
46
+ end
47
+
48
+ require 'appoptics_apm/config'
49
+ require 'appoptics_apm/loading'
50
+ require 'appoptics_apm/legacy_method_profiling'
51
+ require 'appoptics_apm/method_profiling'
52
+
53
+ if AppOpticsAPM.loaded
54
+ require 'appoptics_apm/instrumentation'
55
+
56
+ # Frameworks
57
+ require 'appoptics_apm/frameworks/rails'
58
+ require 'appoptics_apm/frameworks/sinatra'
59
+ require 'appoptics_apm/frameworks/padrino'
60
+ require 'appoptics_apm/frameworks/grape'
61
+ end
62
+
63
+ # Load Ruby module last. If there is no framework detected,
64
+ # it will load all of the Ruby instrumentation
65
+ require 'appoptics_apm/ruby'
66
+ require 'oboe/backward_compatibility'
67
+
68
+ require 'appoptics_apm/test' if ENV['APPOPTICS_GEM_TEST']
69
+ rescue => e
70
+ $stderr.puts "[appoptics_apm/error] Problem loading: #{e.inspect}"
71
+ $stderr.puts e.backtrace
72
+ end