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