appoptics_apm 4.0.2

Sign up to get free protection for your applications and to get access to all the features.
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,281 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ ##
6
+ # This module exposes a nested configuration hash that can be used to
7
+ # configure and/or modify the functionality of the appoptics_apm gem.
8
+ #
9
+ # Use AppOpticsAPM::Config.show to view the entire nested hash.
10
+ #
11
+ module Config
12
+ @@config = {}
13
+
14
+ @@instrumentation = [:action_controller, :action_controller_api, :action_view,
15
+ :active_record, :bunnyclient, :bunnyconsumer, :cassandra, :curb,
16
+ :dalli, :delayed_jobclient, :delayed_jobworker,
17
+ :em_http_request, :excon, :faraday, :grape,
18
+ :httpclient, :nethttp, :memcached,
19
+ :memcache, :mongo, :moped, :rack, :redis,
20
+ :resqueclient, :resqueworker, :rest_client,
21
+ :sequel, :sidekiqclient, :sidekiqworker, :typhoeus]
22
+
23
+ # Subgrouping of instrumentation
24
+ @@http_clients = [:curb, :excon, :em_http_request, :faraday, :httpclient, :nethttp, :rest_client, :typhoeus]
25
+
26
+ ##
27
+ # Return the raw nested hash.
28
+ #
29
+ def self.show
30
+ @@config
31
+ end
32
+
33
+ ##
34
+ # initialize
35
+ #
36
+ # Initializer method to set everything up with a
37
+ # default configuration.
38
+ #
39
+ # rubocop:disable Metrics/AbcSize
40
+ def self.initialize(_data = {})
41
+ # Setup default instrumentation values
42
+ @@instrumentation.each do |k|
43
+ @@config[k] = {}
44
+ @@config[k][:enabled] = true
45
+ @@config[k][:collect_backtraces] = false
46
+ @@config[k][:log_args] = true
47
+ end
48
+
49
+ # Beta instrumentation disabled by default
50
+ AppOpticsAPM::Config[:em_http_request][:enabled] = false
51
+
52
+ # Set collect_backtraces defaults
53
+ AppOpticsAPM::Config[:action_controller][:collect_backtraces] = false
54
+ AppOpticsAPM::Config[:action_controller_api][:collect_backtraces] = false
55
+ AppOpticsAPM::Config[:active_record][:collect_backtraces] = true
56
+ AppOpticsAPM::Config[:bunnyclient][:collect_backtraces] = false
57
+ AppOpticsAPM::Config[:bunnyconsumer][:collect_backtraces] = false
58
+ AppOpticsAPM::Config[:action_view][:collect_backtraces] = true
59
+ AppOpticsAPM::Config[:cassandra][:collect_backtraces] = true
60
+ AppOpticsAPM::Config[:curb][:collect_backtraces] = true
61
+ AppOpticsAPM::Config[:dalli][:collect_backtraces] = false
62
+ AppOpticsAPM::Config[:delayed_jobclient][:collect_backtraces] = false
63
+ AppOpticsAPM::Config[:delayed_jobworker][:collect_backtraces] = false
64
+ AppOpticsAPM::Config[:em_http_request][:collect_backtraces] = false
65
+ AppOpticsAPM::Config[:excon][:collect_backtraces] = true
66
+ AppOpticsAPM::Config[:faraday][:collect_backtraces] = false
67
+ AppOpticsAPM::Config[:grape][:collect_backtraces] = true
68
+ AppOpticsAPM::Config[:httpclient][:collect_backtraces] = true
69
+ AppOpticsAPM::Config[:memcache][:collect_backtraces] = false
70
+ AppOpticsAPM::Config[:memcached][:collect_backtraces] = false
71
+ AppOpticsAPM::Config[:mongo][:collect_backtraces] = true
72
+ AppOpticsAPM::Config[:moped][:collect_backtraces] = true
73
+ AppOpticsAPM::Config[:nethttp][:collect_backtraces] = true
74
+ AppOpticsAPM::Config[:rack][:collect_backtraces] = false
75
+ AppOpticsAPM::Config[:redis][:collect_backtraces] = false
76
+ AppOpticsAPM::Config[:resqueclient][:collect_backtraces] = true
77
+ AppOpticsAPM::Config[:resqueworker][:collect_backtraces] = false
78
+ AppOpticsAPM::Config[:rest_client][:collect_backtraces] = false
79
+ AppOpticsAPM::Config[:sequel][:collect_backtraces] = true
80
+ AppOpticsAPM::Config[:sidekiqclient][:collect_backtraces] = false
81
+ AppOpticsAPM::Config[:sidekiqworker][:collect_backtraces] = false
82
+ AppOpticsAPM::Config[:typhoeus][:collect_backtraces] = false
83
+
84
+ # Legacy Resque config support. To be removed in a future version
85
+ @@config[:resque] = {}
86
+
87
+ # Setup an empty host blacklist (see: AppOpticsAPM::API::Util.blacklisted?)
88
+ @@config[:blacklist] = []
89
+
90
+ # Logging of outgoing HTTP query args
91
+ #
92
+ # This optionally disables the logging of query args of outgoing
93
+ # HTTP clients such as Net::HTTP, excon, typhoeus and others.
94
+ #
95
+ # This flag is global to all HTTP client instrumentation.
96
+ #
97
+ # To configure this on a per instrumentation basis, set this
98
+ # option to true and instead disable the instrumenstation specific
99
+ # option <tt>log_args</tt>:
100
+ #
101
+ # AppOpticsAPM::Config[:nethttp][:log_args] = false
102
+ # AppOpticsAPM::Config[:excon][:log_args] = false
103
+ # AppOpticsAPM::Config[:typhoeus][:log_args] = true
104
+ #
105
+ @@config[:include_url_query_params] = true
106
+
107
+ # Logging of incoming HTTP query args
108
+ #
109
+ # This optionally disables the logging of incoming URL request
110
+ # query args.
111
+ #
112
+ # This flag is global and currently only affects the Rack
113
+ # instrumentation which reports incoming request URLs and
114
+ # query args by default.
115
+ @@config[:include_remote_url_params] = true
116
+
117
+ # The AppOpticsAPM Ruby gem has the ability to sanitize query literals
118
+ # from SQL statements. By default this is enabled to
119
+ # avoid collecting and reporting query literals to AppOpticsAPM.
120
+ @@config[:sanitize_sql] = true
121
+
122
+ # The regular expression used to sanitize SQL.
123
+ @@config[:sanitize_sql_regexp] = '(\'[\s\S][^\']*\'|\d*\.\d+|\d+|NULL)'
124
+ @@config[:sanitize_sql_opts] = Regexp::IGNORECASE
125
+
126
+ # Do Not Trace
127
+ # These two values allow you to configure specific URL patterns to
128
+ # never be traced. By default, this is set to common static file
129
+ # extensions but you may want to customize this list for your needs.
130
+ #
131
+ # dnt_regexp and dnt_opts is passed to Regexp.new to create
132
+ # a regular expression object. That is then used to match against
133
+ # the incoming request path.
134
+ #
135
+ # The path string originates from the rack layer and is retrieved
136
+ # as follows:
137
+ #
138
+ # req = ::Rack::Request.new(env)
139
+ # path = URI.unescape(req.path)
140
+ #
141
+ # Usage:
142
+ # AppOpticsAPM::Config[:dnt_regexp] = "lobster$"
143
+ # AppOpticsAPM::Config[:dnt_opts] = Regexp::IGNORECASE
144
+ #
145
+ # This will ignore all requests that end with the string lobster
146
+ # regardless of case
147
+ #
148
+ # Requests with positive matches (non nil) will not be traced.
149
+ # See lib/appoptics_apm/util.rb: AppOpticsAPM::Util.static_asset?
150
+ #
151
+ @@config[:dnt_regexp] = '\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|otf|eot|ttf|woff|woff2|svg|less)(\?.+){0,1}$'
152
+ @@config[:dnt_opts] = Regexp::IGNORECASE
153
+
154
+ # In Rails, raised exceptions with rescue handlers via
155
+ # <tt>rescue_from</tt> are not reported to the AppOptics
156
+ # dashboard by default. Setting this value to true will
157
+ # report all raised exception regardless.
158
+ #
159
+ @@config[:report_rescued_errors] = false
160
+
161
+ # The bunny (Rabbitmq) instrumentation can optionally report
162
+ # Controller and Action values to allow filtering of bunny
163
+ # message handling in # the UI. Use of Controller and Action
164
+ # for filters is temporary until the UI is updated with
165
+ # additional filters.
166
+ #
167
+ # These values identify which properties of
168
+ # Bunny::MessageProperties to report as Controller
169
+ # and Action. The defaults are to report :app_id (as
170
+ # Controller) and :type (as Action). If these values
171
+ # are not specified in the publish, then nothing
172
+ # will be reported here.
173
+ #
174
+ @@config[:bunnyconsumer][:controller] = :app_id
175
+ @@config[:bunnyconsumer][:action] = :type
176
+
177
+ @@config[:verbose] = ENV.key?('APPOPTICS_GEM_VERBOSE') && ENV['APPOPTICS_GEM_VERBOSE'] == 'true' ? true : false
178
+ end
179
+ # rubocop:enable Metrics/AbcSize
180
+
181
+ def self.update!(data)
182
+ data.each do |key, value|
183
+ self[key] = value
184
+ end
185
+ end
186
+
187
+ def self.merge!(data)
188
+ update!(data)
189
+ end
190
+
191
+ def self.[](key)
192
+ if key == :resque
193
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] :resque config is deprecated. It is now split into :resqueclient and :resqueworker.'
194
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Called from #{Kernel.caller[0]}"
195
+ end
196
+
197
+ @@config[key.to_sym]
198
+ end
199
+
200
+ ##
201
+ # []=
202
+ #
203
+ # Config variable assignment method. Here we validate and store the
204
+ # assigned value(s) and trigger any secondary action needed.
205
+ #
206
+ # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
207
+ def self.[]=(key, value)
208
+ @@config[key.to_sym] = value
209
+
210
+ if key == :sampling_rate
211
+ AppOpticsAPM.logger.warn 'sampling_rate is not a supported setting for AppOpticsAPM::Config. ' \
212
+ 'Please use :sample_rate.'
213
+
214
+ elsif key == :sample_rate
215
+ unless value.is_a?(Integer) || value.is_a?(Float)
216
+ fail 'appoptics_apm :sample_rate must be a number between 0 and 1000000 (1m)'
217
+ end
218
+
219
+ # Validate :sample_rate value
220
+ unless value.between?(0, 1e6)
221
+ fail 'appoptics_apm :sample_rate must be between 0 and 1000000 (1m)'
222
+ end
223
+
224
+ # Assure value is an integer
225
+ @@config[key.to_sym] = value.to_i
226
+ AppOpticsAPM.set_sample_rate(value) if AppOpticsAPM.loaded
227
+
228
+ elsif key == :action_blacklist
229
+ AppOpticsAPM.logger.warn "[appoptics_apm/unsupported] :action_blacklist has been deprecated and no longer functions."
230
+
231
+ elsif key == :resque
232
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] :resque config is deprecated. It is now split into :resqueclient and :resqueworker."
233
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Called from #{Kernel.caller[0]}"
234
+
235
+ elsif key == :include_url_query_params
236
+ # Obey the global flag and update all of the per instrumentation
237
+ # <tt>:log_args</tt> values.
238
+ @@config[:rack][:log_args] = value
239
+
240
+ elsif key == :include_remote_url_params
241
+ # Obey the global flag and update all of the per instrumentation
242
+ # <tt>:log_args</tt> values.
243
+ @@http_clients.each do |i|
244
+ @@config[i][:log_args] = value
245
+ end
246
+ end
247
+
248
+ # Update liboboe if updating :tracing_mode
249
+ if key == :tracing_mode
250
+ AppOpticsAPM.set_tracing_mode(value.to_sym) if AppOpticsAPM.loaded
251
+
252
+ # Make sure that the mode is stored as a symbol
253
+ @@config[key.to_sym] = value.to_sym
254
+ end
255
+ end
256
+ # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
257
+
258
+ def self.method_missing(sym, *args)
259
+ class_var_name = "@@#{sym}"
260
+
261
+ if sym.to_s =~ /(.+)=$/
262
+ self[$1] = args.first
263
+ else
264
+ # Try part of the @@config hash first
265
+ if @@config.key?(sym)
266
+ self[sym]
267
+
268
+ # Then try as a class variable
269
+ elsif self.class_variable_defined?(class_var_name.to_sym)
270
+ self.class_eval(class_var_name)
271
+
272
+ # Congrats - You've won a brand new nil...
273
+ else
274
+ nil
275
+ end
276
+ end
277
+ end
278
+ end
279
+ end
280
+
281
+ AppOpticsAPM::Config.initialize
@@ -0,0 +1,93 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Grape
6
+ module API
7
+ def self.extended(klass)
8
+ ::AppOpticsAPM::Util.class_method_alias(klass, :inherited, ::Grape::API)
9
+ end
10
+
11
+ def inherited_with_appoptics(subclass)
12
+ inherited_without_appoptics(subclass)
13
+
14
+ subclass.use ::AppOpticsAPM::Rack
15
+ end
16
+ end
17
+
18
+ module Endpoint
19
+ def self.included(klass)
20
+ ::AppOpticsAPM::Util.method_alias(klass, :run, ::Grape::Endpoint)
21
+ end
22
+
23
+ def run_with_appoptics(*args)
24
+ # Report Controller/Action and Transaction as best possible
25
+ report_kvs = {}
26
+
27
+ report_kvs[:Controller] = options[:for].name
28
+ if route && route.pattern
29
+ report_kvs[:Action] = route.pattern.origin
30
+ else
31
+ report_kvs[:Action] = args.empty? ? env['PATH_INFO'] : args[0]['PATH_INFO']
32
+ end
33
+
34
+ env['appoptics_apm.controller'] = report_kvs[:Controller]
35
+ env['appoptics_apm.action'] = report_kvs[:Action]
36
+
37
+ ::AppOpticsAPM::API.log_entry('grape', report_kvs)
38
+
39
+ run_without_appoptics(*args)
40
+ ensure
41
+ ::AppOpticsAPM::API.log_exit('grape')
42
+ end
43
+ end
44
+
45
+ module Middleware
46
+ module Error
47
+ def self.included(klass)
48
+ ::AppOpticsAPM::Util.method_alias(klass, :error_response, ::Grape::Middleware::Error)
49
+ end
50
+
51
+ def error_response_with_appoptics(error = {})
52
+ status, headers, body = error_response_without_appoptics(error)
53
+
54
+ if AppOpticsAPM.tracing?
55
+ # Since Grape uses throw/catch and not Exceptions, we manually log
56
+ # the error here.
57
+ kvs = {}
58
+ kvs[:ErrorClass] = 'GrapeError'
59
+ kvs[:ErrorMsg] = error[:message] ? error[:message] : "No message given."
60
+ kvs[:Backtrace] = ::AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:grape][:collect_backtraces]
61
+
62
+ ::AppOpticsAPM::API.log(nil, 'error', kvs)
63
+
64
+ # Since calls to error() are handled similar to abort in Grape. We
65
+ # manually log the rack exit here since the original code won't
66
+ # be returned to
67
+ xtrace = AppOpticsAPM::API.log_end('rack', :Status => status)
68
+
69
+ if headers && AppOpticsAPM::XTrace.valid?(xtrace)
70
+ unless defined?(JRUBY_VERSION) && AppOpticsAPM.is_continued_trace?
71
+ headers['X-Trace'] = xtrace if headers.is_a?(Hash)
72
+ end
73
+ end
74
+ end
75
+
76
+ [status, headers, body]
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ if AppOpticsAPM::Config[:grape][:enabled] && defined?(::Grape)
84
+ require 'appoptics_apm/inst/rack'
85
+
86
+ AppOpticsAPM.logger.info "[appoptics_apm/loading] Instrumenting Grape" if AppOpticsAPM::Config[:verbose]
87
+
88
+ AppOpticsAPM::Inst.load_instrumentation
89
+
90
+ ::AppOpticsAPM::Util.send_extend(::Grape::API, ::AppOpticsAPM::Grape::API)
91
+ ::AppOpticsAPM::Util.send_include(::Grape::Endpoint, ::AppOpticsAPM::Grape::Endpoint)
92
+ ::AppOpticsAPM::Util.send_include(::Grape::Middleware::Error, ::AppOpticsAPM::Grape::Middleware::Error)
93
+ end
@@ -0,0 +1,58 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module PadrinoInst
6
+ module Rendering
7
+ def self.included(klass)
8
+ ::AppOpticsAPM::Util.method_alias(klass, :render, ::Padrino::Rendering)
9
+ end
10
+
11
+ def render_with_appoptics(engine, data = nil, options = {}, locals = {}, &block)
12
+ if AppOpticsAPM.tracing?
13
+ report_kvs = {}
14
+
15
+ if data
16
+ report_kvs[:engine] = engine
17
+ report_kvs[:template] = data
18
+ else
19
+ report_kvs[:template] = engine
20
+ end
21
+
22
+ if AppOpticsAPM.tracing_layer_op?(:render)
23
+ # For recursive calls to :render (for sub-partials and layouts),
24
+ # use method profiling.
25
+ begin
26
+ report_kvs[:FunctionName] = :render
27
+ report_kvs[:Class] = :Rendering
28
+ report_kvs[:Module] = :Padrino
29
+ report_kvs[:File] = __FILE__
30
+ report_kvs[:LineNumber] = __LINE__
31
+ rescue StandardError => e
32
+ ::AppOpticsAPM.logger.debug e.message
33
+ ::AppOpticsAPM.logger.debug e.backtrace.join(', ')
34
+ end
35
+
36
+ AppOpticsAPM::API.profile(report_kvs[:template], report_kvs, false) do
37
+ render_without_appoptics(engine, data, options, locals, &block)
38
+ end
39
+ else
40
+ # Fall back to the raw tracing API so we can pass KVs
41
+ # back on exit (a limitation of the AppOpticsAPM::API.trace
42
+ # block method) This removes the need for an info
43
+ # event to send additonal KVs
44
+ ::AppOpticsAPM::API.log_entry(:render, {}, :render)
45
+
46
+ begin
47
+ render_without_appoptics(engine, data, options, locals, &block)
48
+ ensure
49
+ ::AppOpticsAPM::API.log_exit(:render, report_kvs)
50
+ end
51
+ end
52
+ else
53
+ render_without_appoptics(engine, data, options, locals, &block)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,52 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module PadrinoInst
6
+ module Routing
7
+ def self.included(klass)
8
+ ::AppOpticsAPM::Util.method_alias(klass, :dispatch!, ::Padrino::Routing)
9
+ end
10
+
11
+ def dispatch_with_appoptics
12
+
13
+ ::AppOpticsAPM::API.log_entry('padrino', {})
14
+
15
+ result = dispatch_without_appoptics
16
+
17
+ # Report Controller/Action and Transaction as best possible
18
+ report_kvs = {}
19
+ controller = (request.controller && !request.controller.empty?) ? request.controller : nil
20
+ report_kvs[:Controller] = controller || self.class
21
+ report_kvs[:Action] = request.route_obj ? request.route_obj.path : request.action
22
+ env['appoptics_apm.controller'] = report_kvs[:Controller]
23
+ env['appoptics_apm.action'] = report_kvs[:Action]
24
+
25
+ result
26
+ ensure
27
+ ::AppOpticsAPM::API.log_exit('padrino', report_kvs)
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ if defined?(::Padrino)
34
+ # This instrumentation is a superset of the Sinatra instrumentation similar
35
+ # to how Padrino is a superset of Sinatra itself.
36
+ ::AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting Padrino' if AppOpticsAPM::Config[:verbose]
37
+
38
+ require 'appoptics_apm/frameworks/padrino/templates'
39
+
40
+ Padrino.after_load do
41
+ ::AppOpticsAPM.logger = ::Padrino.logger if ::Padrino.respond_to?(:logger)
42
+ ::AppOpticsAPM::Inst.load_instrumentation
43
+
44
+ ::AppOpticsAPM::Util.send_include(::Padrino::Routing::InstanceMethods, ::AppOpticsAPM::PadrinoInst::Routing)
45
+ if defined?(::Padrino::Rendering)
46
+ ::AppOpticsAPM::Util.send_include(::Padrino::Rendering::InstanceMethods, ::AppOpticsAPM::PadrinoInst::Rendering)
47
+ end
48
+
49
+ # Report __Init after fork when in Heroku
50
+ AppOpticsAPM::API.report_init unless AppOpticsAPM.heroku?
51
+ end
52
+ end
@@ -0,0 +1,106 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Inst
6
+ #
7
+ # RailsBase
8
+ #
9
+ # This module contains the instrumentation code common to
10
+ # many Rails versions.
11
+ #
12
+ module RailsBase
13
+
14
+ #
15
+ # has_handler?
16
+ #
17
+ # Determins if <tt>exception</tt> has a registered
18
+ # handler via <tt>rescue_from</tt>
19
+ #
20
+ def has_handler?(exception)
21
+ # Don't log exceptions if they have a rescue handler set
22
+ has_handler = false
23
+ rescue_handlers.detect do |klass_name, _handler|
24
+ # Rescue handlers can be specified as strings or constant names
25
+ klass = self.class.const_get(klass_name) rescue nil
26
+ klass ||= klass_name.constantize rescue nil
27
+ has_handler = exception.is_a?(klass) if klass
28
+ end
29
+ has_handler
30
+ rescue => e
31
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] Error searching Rails handlers: #{e.message}"
32
+ return false
33
+ end
34
+
35
+ #
36
+ # log_rails_error?
37
+ #
38
+ # Determins whether we should log a raised exception to the
39
+ # AppOptics dashboard. This is determined by whether the exception
40
+ # has a rescue handler setup and the value of
41
+ # AppOpticsAPM::Config[:report_rescued_errors]
42
+ #
43
+ def log_rails_error?(exception)
44
+ # As it's perculating up through the layers... make sure that
45
+ # we only report it once.
46
+ return false if exception.instance_variable_get(:@appoptics_logged)
47
+
48
+ has_handler = has_handler?(exception)
49
+
50
+ if !has_handler || (has_handler && AppOpticsAPM::Config[:report_rescued_errors])
51
+ return true
52
+ end
53
+ false
54
+ end
55
+
56
+ ##
57
+ # This method does the logging if we are tracing
58
+ # it `wraps` around the call to the original method
59
+ #
60
+ def trace(layer)
61
+ return yield unless AppOpticsAPM.tracing?
62
+ begin
63
+ AppOpticsAPM::API.log_entry(layer)
64
+ yield
65
+ rescue Exception => e
66
+ AppOpticsAPM::API.log_exception(layer, e) if log_rails_error?(e)
67
+ raise
68
+ ensure
69
+ AppOpticsAPM::API.log_exit(layer)
70
+ end
71
+ end
72
+
73
+
74
+ #
75
+ # render_with_appoptics
76
+ #
77
+ # Our render wrapper that calls 'add_logging', which will log if we are tracing
78
+ #
79
+ def render_with_appoptics(*args, &blk)
80
+ trace('actionview') do
81
+ render_without_appoptics(*args, &blk)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ # ActionController::Base
89
+ if defined?(ActionController::Base) && AppOpticsAPM::Config[:action_controller][:enabled]
90
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting actioncontroller' if AppOpticsAPM::Config[:verbose]
91
+ require "appoptics_apm/frameworks/rails/inst/action_controller#{Rails::VERSION::MAJOR}"
92
+ if Rails::VERSION::MAJOR >= 5
93
+ ::ActionController::Base.send(:prepend, ::AppOpticsAPM::Inst::ActionController)
94
+ else
95
+ ::AppOpticsAPM::Util.send_include(::ActionController::Base, AppOpticsAPM::Inst::ActionController)
96
+ end
97
+ end
98
+
99
+ # ActionController::API - Rails 5+ or via the rails-api gem
100
+ if defined?(ActionController::API) && AppOpticsAPM::Config[:action_controller_api][:enabled]
101
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting actioncontroller api' if AppOpticsAPM::Config[:verbose]
102
+ require "appoptics_apm/frameworks/rails/inst/action_controller_api"
103
+ ::ActionController::API.send(:prepend, ::AppOpticsAPM::Inst::ActionControllerAPI)
104
+ end
105
+
106
+ # vim:set expandtab:tabstop=2
@@ -0,0 +1,61 @@
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 v2
11
+ #
12
+ module ActionController
13
+ include ::AppOpticsAPM::Inst::RailsBase
14
+
15
+ def self.included(klass)
16
+ ::AppOpticsAPM::Util.method_alias(klass, :perform_action)
17
+ ::AppOpticsAPM::Util.method_alias(klass, :rescue_action)
18
+ ::AppOpticsAPM::Util.method_alias(klass, :process)
19
+ ::AppOpticsAPM::Util.method_alias(klass, :render)
20
+ end
21
+
22
+ def process_with_appoptics(*args)
23
+ AppOpticsAPM::API.log_entry('rails')
24
+ process_without_appoptics(*args)
25
+
26
+ rescue Exception => e
27
+ AppOpticsAPM::API.log_exception(nil, e) if log_rails_error?(e)
28
+ raise
29
+ ensure
30
+ AppOpticsAPM::API.log_exit('rails')
31
+ end
32
+
33
+ def perform_action_with_appoptics(*arguments)
34
+ kvs = {
35
+ :Controller => @_request.path_parameters['controller'],
36
+ :Action => @_request.path_parameters['action']
37
+ }
38
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:action_controller][:collect_backtraces]
39
+
40
+ AppOpticsAPM::API.log(nil, 'info', kvs)
41
+ perform_action_without_appoptics(*arguments)
42
+ end
43
+
44
+ def rescue_action_with_appoptics(exn)
45
+ AppOpticsAPM::API.log_exception(nil, exn) if log_rails_error?(exn)
46
+ rescue_action_without_appoptics(exn)
47
+ end
48
+
49
+ def render_with_appoptics(options = nil, extra_options = {}, &block)
50
+ AppOpticsAPM::API.log_entry('actionview')
51
+ render_without_appoptics(options, extra_options, &block)
52
+
53
+ rescue Exception => e
54
+ AppOpticsAPM::API.log_exception(nil, e) if log_rails_error?(e)
55
+ raise
56
+ ensure
57
+ AppOpticsAPM::API.log_exit('actionview')
58
+ end
59
+ end
60
+ end
61
+ end