PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/config/initializers/zz_metrics.rb

https://gitlab.com/markglenfletcher/gitlab-ee
Ruby | 213 lines | 128 code | 47 blank | 38 comment | 9 complexity | 1b11218ee4861550a66e5a343301c78b MD5 | raw file
  1. # This file was prefixed with zz_ because we want to load it the last!
  2. # See: https://gitlab.com/gitlab-org/gitlab-foss/issues/55611
  3. # Autoload all classes that we want to instrument, and instrument the methods we
  4. # need. This takes the Gitlab::Metrics::Instrumentation module as an argument so
  5. # that we can stub it for testing, as it is only called when metrics are
  6. # enabled.
  7. #
  8. # rubocop:disable Metrics/AbcSize
  9. def instrument_classes(instrumentation)
  10. instrumentation.instrument_instance_methods(Gitlab::Shell)
  11. instrumentation.instrument_methods(Gitlab::Git)
  12. Gitlab::Git.constants.each do |name|
  13. const = Gitlab::Git.const_get(name, false)
  14. next unless const.is_a?(Module)
  15. instrumentation.instrument_methods(const)
  16. instrumentation.instrument_instance_methods(const)
  17. end
  18. # Path to search => prefix to strip from constant
  19. paths_to_instrument = {
  20. %w(app finders) => %w(app finders),
  21. %w(app mailers emails) => %w(app mailers),
  22. # Don't instrument `app/services/concerns`
  23. # It contains modules that are included in the services.
  24. # The services themselves are instrumented so the methods from the modules
  25. # are included.
  26. %w(app services [^concerns]**) => %w(app services),
  27. %w(lib gitlab conflicts) => ['lib'],
  28. %w(lib gitlab email message) => ['lib'],
  29. %w(lib gitlab checks) => ['lib']
  30. }
  31. paths_to_instrument.each do |(path, prefix)|
  32. prefix = Rails.root.join(*prefix)
  33. Dir[Rails.root.join(*path + ['*.rb'])].each do |file_path|
  34. path = Pathname.new(file_path).relative_path_from(prefix)
  35. const = path.to_s.sub('.rb', '').camelize.constantize
  36. instrumentation.instrument_methods(const)
  37. instrumentation.instrument_instance_methods(const)
  38. end
  39. end
  40. instrumentation.instrument_methods(Premailer::Adapter::Nokogiri)
  41. instrumentation.instrument_instance_methods(Premailer::Adapter::Nokogiri)
  42. instrumentation.instrument_methods(Banzai::Renderer)
  43. instrumentation.instrument_methods(Banzai::Querying)
  44. instrumentation.instrument_instance_methods(Banzai::ObjectRenderer)
  45. instrumentation.instrument_instance_methods(Banzai::ReferenceRedactor)
  46. [Issuable, Mentionable, Participable].each do |klass|
  47. instrumentation.instrument_instance_methods(klass)
  48. instrumentation.instrument_instance_methods(klass::ClassMethods)
  49. end
  50. instrumentation.instrument_methods(Gitlab::ReferenceExtractor)
  51. instrumentation.instrument_instance_methods(Gitlab::ReferenceExtractor)
  52. # Instrument the classes used for checking if somebody has push access.
  53. instrumentation.instrument_instance_methods(Gitlab::GitAccess)
  54. instrumentation.instrument_instance_methods(Gitlab::GitAccessWiki)
  55. instrumentation.instrument_instance_methods(API::Helpers)
  56. instrumentation.instrument_instance_methods(RepositoryCheck::SingleRepositoryWorker)
  57. instrumentation.instrument_instance_methods(Rouge::Formatters::HTMLGitlab)
  58. [:XML, :HTML].each do |namespace|
  59. namespace_mod = Nokogiri.const_get(namespace, false)
  60. instrumentation.instrument_methods(namespace_mod)
  61. instrumentation.instrument_methods(namespace_mod::Document)
  62. end
  63. instrumentation.instrument_methods(Rinku)
  64. instrumentation.instrument_instance_methods(Repository)
  65. instrumentation.instrument_methods(Gitlab::Highlight)
  66. instrumentation.instrument_instance_methods(Gitlab::Highlight)
  67. Gitlab.ee do
  68. instrumentation.instrument_methods(Elasticsearch::Git::Repository)
  69. instrumentation.instrument_instance_methods(Elasticsearch::Git::Repository)
  70. instrumentation.instrument_instance_methods(Search::GlobalService)
  71. instrumentation.instrument_instance_methods(Search::ProjectService)
  72. instrumentation.instrument_instance_methods(Gitlab::Elastic::SearchResults)
  73. instrumentation.instrument_instance_methods(Gitlab::Elastic::ProjectSearchResults)
  74. instrumentation.instrument_instance_methods(Gitlab::Elastic::Indexer)
  75. instrumentation.instrument_instance_methods(Gitlab::Elastic::SnippetSearchResults)
  76. instrumentation.instrument_methods(Gitlab::Elastic::Helper)
  77. instrumentation.instrument_instance_methods(Elastic::ApplicationVersionedSearch)
  78. instrumentation.instrument_instance_methods(Elastic::ProjectsSearch)
  79. instrumentation.instrument_instance_methods(Elastic::RepositoriesSearch)
  80. instrumentation.instrument_instance_methods(Elastic::SnippetsSearch)
  81. instrumentation.instrument_instance_methods(Elastic::WikiRepositoriesSearch)
  82. instrumentation.instrument_instance_methods(Gitlab::BitbucketImport::Importer)
  83. instrumentation.instrument_instance_methods(Bitbucket::Connection)
  84. instrumentation.instrument_instance_methods(Geo::RepositorySyncWorker)
  85. end
  86. # This is a Rails scope so we have to instrument it manually.
  87. instrumentation.instrument_method(Project, :visible_to_user)
  88. # Needed for https://gitlab.com/gitlab-org/gitlab-foss/issues/30224#note_32306159
  89. instrumentation.instrument_instance_method(MergeRequestDiff, :load_commits)
  90. end
  91. # rubocop:enable Metrics/AbcSize
  92. # With prometheus enabled by default this breaks all specs
  93. # that stubs methods using `any_instance_of` for the models reloaded here.
  94. #
  95. # We should deprecate the usage of `any_instance_of` in the future
  96. # check: https://github.com/rspec/rspec-mocks#settings-mocks-or-stubs-on-any-instance-of-a-class
  97. #
  98. # Related issue: https://gitlab.com/gitlab-org/gitlab-foss/issues/33587
  99. #
  100. # In development mode, we turn off eager loading when we're running
  101. # `rails generate migration` because eager loading short-circuits the
  102. # loading of our custom migration templates.
  103. if Gitlab::Metrics.enabled? && !Rails.env.test? && !(Rails.env.development? && defined?(Rails::Generators))
  104. require 'pathname'
  105. require 'influxdb'
  106. require 'connection_pool'
  107. require 'method_source'
  108. # These are manually require'd so the classes are registered properly with
  109. # ActiveSupport.
  110. require_dependency 'gitlab/metrics/subscribers/action_view'
  111. require_dependency 'gitlab/metrics/subscribers/active_record'
  112. require_dependency 'gitlab/metrics/subscribers/rails_cache'
  113. Gitlab::Application.configure do |config|
  114. config.middleware.use(Gitlab::Metrics::RackMiddleware)
  115. config.middleware.use(Gitlab::Middleware::RailsQueueDuration)
  116. end
  117. Sidekiq.configure_server do |config|
  118. config.server_middleware do |chain|
  119. chain.add Gitlab::Metrics::SidekiqMiddleware
  120. end
  121. end
  122. # This instruments all methods residing in app/models that (appear to) use any
  123. # of the ActiveRecord methods. This has to take place _after_ initializing as
  124. # for some unknown reason calling eager_load! earlier breaks Devise.
  125. Gitlab::Application.config.after_initialize do
  126. Rails.application.eager_load!
  127. models = Rails.root.join('app', 'models').to_s
  128. regex = Regexp.union(
  129. ActiveRecord::Querying.public_instance_methods(false).map(&:to_s)
  130. )
  131. Gitlab::Metrics::Instrumentation
  132. .instrument_class_hierarchy(ActiveRecord::Base) do |klass, method|
  133. # Instrumenting the ApplicationSetting class can lead to an infinite
  134. # loop. Since the data is cached any way we don't really need to
  135. # instrument it.
  136. if klass == ApplicationSetting
  137. false
  138. else
  139. loc = method.source_location
  140. loc && loc[0].start_with?(models) && method.source =~ regex
  141. end
  142. end
  143. # Ability is in app/models, is not an ActiveRecord model, but should still
  144. # be instrumented.
  145. Gitlab::Metrics::Instrumentation.instrument_methods(Ability)
  146. end
  147. Gitlab::Metrics::Instrumentation.configure do |config|
  148. instrument_classes(config)
  149. end
  150. GC::Profiler.enable
  151. Gitlab::Cluster::LifecycleEvents.on_worker_start do
  152. Gitlab::Metrics::Samplers::InfluxSampler.initialize_instance.start
  153. end
  154. module TrackNewRedisConnections
  155. def connect(*args)
  156. val = super
  157. if current_transaction = ::Gitlab::Metrics::Transaction.current
  158. current_transaction.increment(:new_redis_connections, 1)
  159. end
  160. val
  161. end
  162. end
  163. class ::Redis::Client
  164. prepend TrackNewRedisConnections
  165. end
  166. end