Commit ae94c880 authored by Matthias Käppler's avatar Matthias Käppler Committed by Mayra Cabrera

Allow metrics_server to target Puma

So far we had only tested this with Sidekiq.
This change makes sure that WebExporter and
the puma metrics directory can be used.

This is a prerequisite for extracting WebExporter
into a separate process.
parent abaace64
...@@ -20,6 +20,8 @@ module Gitlab ...@@ -20,6 +20,8 @@ module Gitlab
!thread.nil? !thread.nil?
end end
# Possible options:
# - synchronous [Boolean] if true, turns `start` into a blocking call
def initialize(**options) def initialize(**options)
@synchronous = options[:synchronous] @synchronous = options[:synchronous]
@mutex = Mutex.new @mutex = Mutex.new
......
...@@ -9,6 +9,10 @@ module Gitlab ...@@ -9,6 +9,10 @@ module Gitlab
class BaseExporter < Daemon class BaseExporter < Daemon
attr_reader :server attr_reader :server
# @param settings [Hash] SettingsLogic hash containing the `*_exporter` config
# @param log_enabled [Boolean] whether to log HTTP requests
# @param log_file [String] path to where the server log should be located
# @param gc_requests [Boolean] whether to run a major GC after each scraper request
def initialize(settings, log_enabled:, log_file:, gc_requests: false, **options) def initialize(settings, log_enabled:, log_file:, gc_requests: false, **options)
super(**options) super(**options)
......
...@@ -23,6 +23,7 @@ require_relative '../lib/gitlab/metrics/system' ...@@ -23,6 +23,7 @@ require_relative '../lib/gitlab/metrics/system'
require_relative '../lib/gitlab/metrics/samplers/base_sampler' require_relative '../lib/gitlab/metrics/samplers/base_sampler'
require_relative '../lib/gitlab/metrics/samplers/ruby_sampler' require_relative '../lib/gitlab/metrics/samplers/ruby_sampler'
require_relative '../lib/gitlab/metrics/exporter/base_exporter' require_relative '../lib/gitlab/metrics/exporter/base_exporter'
require_relative '../lib/gitlab/metrics/exporter/web_exporter'
require_relative '../lib/gitlab/metrics/exporter/sidekiq_exporter' require_relative '../lib/gitlab/metrics/exporter/sidekiq_exporter'
require_relative '../lib/gitlab/metrics/exporter/metrics_middleware' require_relative '../lib/gitlab/metrics/exporter/metrics_middleware'
require_relative '../lib/gitlab/metrics/exporter/health_checks_middleware' require_relative '../lib/gitlab/metrics/exporter/health_checks_middleware'
......
...@@ -7,7 +7,7 @@ require_relative 'dependencies' ...@@ -7,7 +7,7 @@ require_relative 'dependencies'
class MetricsServer # rubocop:disable Gitlab/NamespacedClass class MetricsServer # rubocop:disable Gitlab/NamespacedClass
class << self class << self
def spawn(target, metrics_dir:, wipe_metrics_dir: false, trapped_signals: []) def spawn(target, metrics_dir:, wipe_metrics_dir: false, trapped_signals: [])
raise "The only valid target is 'sidekiq' currently" unless target == 'sidekiq' raise "Target must be one of [puma,sidekiq]" unless %w(puma sidekiq).include?(target)
pid = Process.fork pid = Process.fork
...@@ -52,11 +52,18 @@ class MetricsServer # rubocop:disable Gitlab/NamespacedClass ...@@ -52,11 +52,18 @@ class MetricsServer # rubocop:disable Gitlab/NamespacedClass
# Warming up ensures that these files exist prior to the exporter starting up. # Warming up ensures that these files exist prior to the exporter starting up.
Gitlab::Metrics::Samplers::RubySampler.initialize_instance(prefix: name, warmup: true).start Gitlab::Metrics::Samplers::RubySampler.initialize_instance(prefix: name, warmup: true).start
default_opts = { gc_requests: true, synchronous: true }
exporter =
case @target
when 'puma'
Gitlab::Metrics::Exporter::WebExporter.instance(**default_opts)
else
exporter_class = "Gitlab::Metrics::Exporter::#{@target.camelize}Exporter".constantize exporter_class = "Gitlab::Metrics::Exporter::#{@target.camelize}Exporter".constantize
settings = Settings.new(Settings.monitoring[name]) settings = Settings.new(Settings.monitoring[name])
server = exporter_class.instance(settings, gc_requests: true, synchronous: true) exporter_class.instance(settings, **default_opts)
end
server.start exporter.start
end end
def name def name
......
...@@ -12,6 +12,11 @@ RSpec.describe 'bin/metrics-server', :aggregate_failures do ...@@ -12,6 +12,11 @@ RSpec.describe 'bin/metrics-server', :aggregate_failures do
{ {
'test' => { 'test' => {
'monitoring' => { 'monitoring' => {
'web_exporter' => {
'address' => 'localhost',
'enabled' => true,
'port' => 3807
},
'sidekiq_exporter' => { 'sidekiq_exporter' => {
'address' => 'localhost', 'address' => 'localhost',
'enabled' => true, 'enabled' => true,
...@@ -22,7 +27,8 @@ RSpec.describe 'bin/metrics-server', :aggregate_failures do ...@@ -22,7 +27,8 @@ RSpec.describe 'bin/metrics-server', :aggregate_failures do
} }
end end
context 'with a running server' do %w(puma sidekiq).each do |target|
context "with a running server targeting #{target}" do
let(:metrics_dir) { Dir.mktmpdir } let(:metrics_dir) { Dir.mktmpdir }
before do before do
...@@ -34,7 +40,7 @@ RSpec.describe 'bin/metrics-server', :aggregate_failures do ...@@ -34,7 +40,7 @@ RSpec.describe 'bin/metrics-server', :aggregate_failures do
env = { env = {
'GITLAB_CONFIG' => config_file.path, 'GITLAB_CONFIG' => config_file.path,
'METRICS_SERVER_TARGET' => 'sidekiq', 'METRICS_SERVER_TARGET' => target,
'WIPE_METRICS_DIR' => '1', 'WIPE_METRICS_DIR' => '1',
'prometheus_multiproc_dir' => metrics_dir 'prometheus_multiproc_dir' => metrics_dir
} }
...@@ -74,4 +80,5 @@ RSpec.describe 'bin/metrics-server', :aggregate_failures do ...@@ -74,4 +80,5 @@ RSpec.describe 'bin/metrics-server', :aggregate_failures do
end.not_to raise_error end.not_to raise_error
end end
end end
end
end end
...@@ -15,9 +15,16 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath ...@@ -15,9 +15,16 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
# we need to reset it after testing. # we need to reset it after testing.
let!(:old_multiprocess_files_dir) { prometheus_config.multiprocess_files_dir } let!(:old_multiprocess_files_dir) { prometheus_config.multiprocess_files_dir }
let(:ruby_sampler_double) { double(Gitlab::Metrics::Samplers::RubySampler) }
before do before do
# We do not want this to have knock-on effects on the test process. # We do not want this to have knock-on effects on the test process.
allow(Gitlab::ProcessManagement).to receive(:modify_signals) allow(Gitlab::ProcessManagement).to receive(:modify_signals)
# This being a singleton, we stub it out because only one instance is allowed
# to exist per process.
allow(Gitlab::Metrics::Samplers::RubySampler).to receive(:initialize_instance).and_return(ruby_sampler_double)
allow(ruby_sampler_double).to receive(:start)
end end
after do after do
...@@ -27,13 +34,15 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath ...@@ -27,13 +34,15 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
FileUtils.rm_rf(metrics_dir, secure: true) FileUtils.rm_rf(metrics_dir, secure: true)
end end
%w(puma sidekiq).each do |target|
context "when targeting #{target}" do
describe '.spawn' do describe '.spawn' do
context 'when in parent process' do context 'when in parent process' do
it 'forks into a new process and detaches it' do it 'forks into a new process and detaches it' do
expect(Process).to receive(:fork).and_return(99) expect(Process).to receive(:fork).and_return(99)
expect(Process).to receive(:detach).with(99) expect(Process).to receive(:detach).with(99)
described_class.spawn('sidekiq', metrics_dir: metrics_dir) described_class.spawn(target, metrics_dir: metrics_dir)
end end
end end
...@@ -49,13 +58,25 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath ...@@ -49,13 +58,25 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
expect(server).to receive(:start) expect(server).to receive(:start)
end end
described_class.spawn('sidekiq', metrics_dir: metrics_dir) described_class.spawn(target, metrics_dir: metrics_dir)
end end
it 'resets signal handlers from parent process' do it 'resets signal handlers from parent process' do
expect(Gitlab::ProcessManagement).to receive(:modify_signals).with(%i[A B], 'DEFAULT') expect(Gitlab::ProcessManagement).to receive(:modify_signals).with(%i[A B], 'DEFAULT')
described_class.spawn('sidekiq', metrics_dir: metrics_dir, trapped_signals: %i[A B]) described_class.spawn(target, metrics_dir: metrics_dir, trapped_signals: %i[A B])
end
end
end
end
end
context 'when targeting invalid target' do
describe '.spawn' do
it 'raises an error' do
expect { described_class.spawn('unsupported', metrics_dir: metrics_dir) }.to(
raise_error('Target must be one of [puma,sidekiq]')
)
end end
end end
end end
...@@ -64,7 +85,6 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath ...@@ -64,7 +85,6 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
let(:exporter_class) { Class.new(Gitlab::Metrics::Exporter::BaseExporter) } let(:exporter_class) { Class.new(Gitlab::Metrics::Exporter::BaseExporter) }
let(:exporter_double) { double('fake_exporter', start: true) } let(:exporter_double) { double('fake_exporter', start: true) }
let(:settings) { { "fake_exporter" => { "enabled" => true } } } let(:settings) { { "fake_exporter" => { "enabled" => true } } }
let(:ruby_sampler_double) { double(Gitlab::Metrics::Samplers::RubySampler) }
subject(:metrics_server) { described_class.new('fake', metrics_dir, true)} subject(:metrics_server) { described_class.new('fake', metrics_dir, true)}
...@@ -74,9 +94,6 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath ...@@ -74,9 +94,6 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
settings['fake_exporter'], gc_requests: true, synchronous: true settings['fake_exporter'], gc_requests: true, synchronous: true
).and_return(exporter_double) ).and_return(exporter_double)
expect(Settings).to receive(:monitoring).and_return(settings) expect(Settings).to receive(:monitoring).and_return(settings)
allow(Gitlab::Metrics::Samplers::RubySampler).to receive(:initialize_instance).and_return(ruby_sampler_double)
allow(ruby_sampler_double).to receive(:start)
end end
it 'configures ::Prometheus::Client' do it 'configures ::Prometheus::Client' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment