summaryrefslogtreecommitdiff
path: root/config/initializers/zz_metrics.rb
blob: 25e4ec0d48307e1219fc1c89600bff0bf17cf50c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# frozen_string_literal: true

# This file was prefixed with zz_ because we want to load it the last!
# See: https://gitlab.com/gitlab-org/gitlab-foss/issues/55611

# Autoload all classes that we want to instrument, and instrument the methods we
# need. This takes the Gitlab::Metrics::Instrumentation module as an argument so
# that we can stub it for testing, as it is only called when metrics are
# enabled.
#
# rubocop:disable Metrics/AbcSize
def instrument_classes(instrumentation)
  return if ENV['STATIC_VERIFICATION']

  instrumentation.instrument_instance_methods(Gitlab::Shell)

  instrumentation.instrument_methods(Gitlab::Git)

  Gitlab::Git.constants.each do |name|
    const = Gitlab::Git.const_get(name, false)

    next unless const.is_a?(Module)

    instrumentation.instrument_methods(const)
    instrumentation.instrument_instance_methods(const)
  end

  # Path to search => prefix to strip from constant
  paths_to_instrument = {
    %w(app finders)                => %w(app finders),
    %w(app mailers emails)         => %w(app mailers),
    # Don't instrument `app/services/concerns`
    # It contains modules that are included in the services.
    # The services themselves are instrumented so the methods from the modules
    # are included.
    %w(app services [^concerns]**) => %w(app services),
    %w(lib gitlab conflicts)       => ['lib'],
    %w(lib gitlab email message)   => ['lib'],
    %w(lib gitlab checks)          => ['lib']
  }

  paths_to_instrument.each do |(path, prefix)|
    prefix = Rails.root.join(*prefix)

    Dir[Rails.root.join(*path + ['*.rb'])].each do |file_path|
      path = Pathname.new(file_path).relative_path_from(prefix)
      const = path.to_s.sub('.rb', '').camelize.constantize

      instrumentation.instrument_methods(const)
      instrumentation.instrument_instance_methods(const)
    end
  end

  instrumentation.instrument_methods(Premailer::Adapter::Nokogiri)
  instrumentation.instrument_instance_methods(Premailer::Adapter::Nokogiri)

  instrumentation.instrument_methods(Banzai::Renderer)
  instrumentation.instrument_methods(Banzai::Querying)

  instrumentation.instrument_instance_methods(Banzai::ObjectRenderer)
  instrumentation.instrument_instance_methods(Banzai::ReferenceRedactor)

  [Issuable, Mentionable, Participable].each do |klass|
    instrumentation.instrument_instance_methods(klass)
    instrumentation.instrument_instance_methods(klass::ClassMethods)
  end

  instrumentation.instrument_methods(Gitlab::ReferenceExtractor)
  instrumentation.instrument_instance_methods(Gitlab::ReferenceExtractor)

  # Instrument the classes used for checking if somebody has push access.
  instrumentation.instrument_instance_methods(Gitlab::GitAccess)
  instrumentation.instrument_instance_methods(Gitlab::GitAccessWiki)

  instrumentation.instrument_instance_methods(API::Helpers)

  instrumentation.instrument_instance_methods(RepositoryCheck::SingleRepositoryWorker)

  instrumentation.instrument_instance_methods(Rouge::Formatters::HTMLGitlab)

  [:XML, :HTML].each do |namespace|
    namespace_mod = Nokogiri.const_get(namespace, false)

    instrumentation.instrument_methods(namespace_mod)
    instrumentation.instrument_methods(namespace_mod::Document)
  end

  instrumentation.instrument_methods(Rinku)
  instrumentation.instrument_instance_methods(Repository)

  instrumentation.instrument_methods(Gitlab::Highlight)
  instrumentation.instrument_instance_methods(Gitlab::Highlight)
  instrumentation.instrument_instance_method(Gitlab::Ci::Config::Yaml::Tags::Resolver, :to_hash)

  Gitlab.ee do
    instrumentation.instrument_instance_methods(Elastic::Latest::GitInstanceProxy)
    instrumentation.instrument_instance_methods(Elastic::Latest::GitClassProxy)

    instrumentation.instrument_instance_methods(Search::GlobalService)
    instrumentation.instrument_instance_methods(Search::ProjectService)

    instrumentation.instrument_instance_methods(Gitlab::Elastic::SearchResults)
    instrumentation.instrument_instance_methods(Gitlab::Elastic::ProjectSearchResults)
    instrumentation.instrument_instance_methods(Gitlab::Elastic::Indexer)
    instrumentation.instrument_instance_methods(Gitlab::Elastic::SnippetSearchResults)
    instrumentation.instrument_instance_methods(Gitlab::Elastic::Helper)

    instrumentation.instrument_instance_methods(Elastic::ApplicationVersionedSearch)
    instrumentation.instrument_instance_methods(Elastic::ProjectsSearch)
    instrumentation.instrument_instance_methods(Elastic::RepositoriesSearch)
    instrumentation.instrument_instance_methods(Elastic::SnippetsSearch)
    instrumentation.instrument_instance_methods(Elastic::WikiRepositoriesSearch)

    instrumentation.instrument_instance_methods(Gitlab::BitbucketImport::Importer)
    instrumentation.instrument_instance_methods(Bitbucket::Connection)

    instrumentation.instrument_instance_methods(Geo::RepositorySyncWorker)
  end

  # This is a Rails scope so we have to instrument it manually.
  instrumentation.instrument_method(Project, :visible_to_user)

  # Needed for https://gitlab.com/gitlab-org/gitlab-foss/issues/30224#note_32306159
  instrumentation.instrument_instance_method(MergeRequestDiff, :load_commits)
end
# rubocop:enable Metrics/AbcSize

# With prometheus enabled by default this breaks all specs
# that stubs methods using `any_instance_of` for the models reloaded here.
#
# We should deprecate the usage of `any_instance_of` in the future
# check: https://github.com/rspec/rspec-mocks#settings-mocks-or-stubs-on-any-instance-of-a-class
#
# Related issue: https://gitlab.com/gitlab-org/gitlab-foss/issues/33587
#
# In development mode, we turn off eager loading when we're running
# `rails generate migration` because eager loading short-circuits the
# loading of our custom migration templates.
if Gitlab::Metrics.enabled? && !Rails.env.test? && !(Rails.env.development? && defined?(Rails::Generators))
  require 'pathname'
  require 'connection_pool'
  require 'method_source'

  # These are manually require'd so the classes are registered properly with
  # ActiveSupport.
  require_dependency 'gitlab/metrics/subscribers/action_cable'
  require_dependency 'gitlab/metrics/subscribers/action_view'
  require_dependency 'gitlab/metrics/subscribers/active_record'
  require_dependency 'gitlab/metrics/subscribers/rails_cache'

  Gitlab::Application.configure do |config|
    # We want to track certain metrics during the Load Balancing host resolving process.
    # Because of that, we need to have metrics code available earlier for Load Balancing.
    if Gitlab::Database::LoadBalancing.enable?
      config.middleware.insert_before Gitlab::Database::LoadBalancing::RackMiddleware,
        Gitlab::Metrics::RackMiddleware
    else
      config.middleware.use(Gitlab::Metrics::RackMiddleware)
    end

    config.middleware.use(Gitlab::Middleware::RailsQueueDuration)
    config.middleware.use(Gitlab::Metrics::ElasticsearchRackMiddleware)
  end

  GC::Profiler.enable

  module TrackNewRedisConnections
    def connect(*args)
      val = super

      if current_transaction = ::Gitlab::Metrics::Transaction.current
        current_transaction.increment(:gitlab_transaction_new_redis_connections_total, 1)
      end

      val
    end
  end

  class ::Redis::Client
    prepend TrackNewRedisConnections
  end

  Labkit::NetHttpPublisher.labkit_prepend!
  Labkit::ExconPublisher.labkit_prepend!
  Labkit::HTTPClientPublisher.labkit_prepend!
end