From bf997d79d1eec1415671028e0c51da62e6819212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Thu, 11 Jul 2019 10:20:35 +0200 Subject: Add WebMetricsExporter --- config/gitlab.yml.example | 7 ++ config/initializers/1_settings.rb | 8 +- config/initializers/7_prometheus_metrics.rb | 8 +- lib/gitlab/daemon.rb | 1 + lib/gitlab/metrics/metrics_exporter.rb | 51 ++++++++++ lib/gitlab/metrics/sidekiq_metrics_exporter.rb | 38 +------ lib/gitlab/metrics/web_metrics_exporter.rb | 42 +------- spec/lib/gitlab/metrics/metrics_exporter_spec.rb | 109 +++++++++++++++++++++ .../metrics/sidekiq_metrics_exporter_spec.rb | 103 ------------------- 9 files changed, 184 insertions(+), 183 deletions(-) create mode 100644 lib/gitlab/metrics/metrics_exporter.rb create mode 100644 spec/lib/gitlab/metrics/metrics_exporter_spec.rb delete mode 100644 spec/lib/gitlab/metrics/sidekiq_metrics_exporter_spec.rb diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 334c241bcaa..f03fe61ead4 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -952,6 +952,13 @@ production: &base # address: localhost # port: 3807 + # Web exporter is webserver built in to Unicorn/Puma to expose Prometheus metrics + # It runs alongside the `/metrics` endpoints to ease the publish of metrics + web_exporter: + # enabled: true + # address: localhost + # port: 3808 + # # 5. Extra customization # ========================== diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 1b447744032..091b130cfa3 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -643,14 +643,14 @@ Settings.monitoring['ip_whitelist'] ||= ['127.0.0.1/8'] Settings.monitoring['unicorn_sampler_interval'] ||= 10 Settings.monitoring['puma_sampler_interval'] ||= 5 Settings.monitoring['ruby_sampler_interval'] ||= 60 -Settings.monitoring['web_exporter'] ||= Settingslogic.new({}) -Settings.monitoring.web_exporter['enabled'] ||= true -Settings.monitoring.web_exporter['address'] ||= '0.0.0.0' -Settings.monitoring.web_exporter['port'] ||= 3808 Settings.monitoring['sidekiq_exporter'] ||= Settingslogic.new({}) Settings.monitoring.sidekiq_exporter['enabled'] ||= false Settings.monitoring.sidekiq_exporter['address'] ||= 'localhost' Settings.monitoring.sidekiq_exporter['port'] ||= 3807 +Settings.monitoring['web_exporter'] ||= Settingslogic.new({}) +Settings.monitoring.web_exporter['enabled'] ||= false +Settings.monitoring.web_exporter['address'] ||= 'localhost' +Settings.monitoring.web_exporter['port'] ||= 3808 # # Testing settings diff --git a/config/initializers/7_prometheus_metrics.rb b/config/initializers/7_prometheus_metrics.rb index 13dcc585fcb..b8507f89c44 100644 --- a/config/initializers/7_prometheus_metrics.rb +++ b/config/initializers/7_prometheus_metrics.rb @@ -67,11 +67,15 @@ end Gitlab::Cluster::LifecycleEvents.on_master_start do cleanup_prometheus_multiproc_dir - Gitlab::Metrics::WebMetricsExporter.instance.start + if defined?(::Unicorn) || defined?(::Puma) + Gitlab::Metrics::WebMetricsExporter.instance.start + end end Gitlab::Cluster::LifecycleEvents.on_master_restart do cleanup_prometheus_multiproc_dir - Gitlab::Metrics::WebMetricsExporter.instance.start + if defined?(::Unicorn) || defined?(::Puma) + Gitlab::Metrics::WebMetricsExporter.instance.start + end end diff --git a/lib/gitlab/daemon.rb b/lib/gitlab/daemon.rb index 6d5fc4219fb..52784966c03 100644 --- a/lib/gitlab/daemon.rb +++ b/lib/gitlab/daemon.rb @@ -55,6 +55,7 @@ module Gitlab private def start_working + puts "FAILURE: #{self.class}" raise NotImplementedError end diff --git a/lib/gitlab/metrics/metrics_exporter.rb b/lib/gitlab/metrics/metrics_exporter.rb new file mode 100644 index 00000000000..2598e5225f8 --- /dev/null +++ b/lib/gitlab/metrics/metrics_exporter.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'webrick' +require 'prometheus/client/rack/exporter' + +module Gitlab + module Metrics + class MetricsExporter < Daemon + def enabled? + ::Gitlab::Metrics.metrics_folder_present? && settings.enabled + end + + def settings + throw NotImplementedError + end + + def log_filename + throw NotImplementedError + end + + private + + attr_reader :server + + def start_working + logger = WEBrick::Log.new(log_filename) + access_log = [ + [logger, WEBrick::AccessLog::COMBINED_LOG_FORMAT] + ] + + @server = ::WEBrick::HTTPServer.new(Port: settings.port, BindAddress: settings.address, + Logger: logger, AccessLog: access_log) + server.mount "/", Rack::Handler::WEBrick, rack_app + server.start + end + + def stop_working + server.shutdown if server + @server = nil + end + + def rack_app + Rack::Builder.app do + use Rack::Deflater + use ::Prometheus::Client::Rack::Exporter + run -> (env) { [404, {}, ['']] } + end + end + end + end +end diff --git a/lib/gitlab/metrics/sidekiq_metrics_exporter.rb b/lib/gitlab/metrics/sidekiq_metrics_exporter.rb index 71a5406815f..898cb5a483c 100644 --- a/lib/gitlab/metrics/sidekiq_metrics_exporter.rb +++ b/lib/gitlab/metrics/sidekiq_metrics_exporter.rb @@ -1,48 +1,14 @@ -# frozen_string_literal: true - -require 'webrick' -require 'prometheus/client/rack/exporter' - module Gitlab module Metrics class SidekiqMetricsExporter < Daemon LOG_FILENAME = File.join(Rails.root, 'log', 'sidekiq_exporter.log') - def enabled? - ::Gitlab::Metrics.metrics_folder_present? && settings.enabled - end - def settings Settings.monitoring.sidekiq_exporter end - private - - attr_reader :server - - def start_working - logger = WEBrick::Log.new(LOG_FILENAME) - access_log = [ - [logger, WEBrick::AccessLog::COMBINED_LOG_FORMAT] - ] - - @server = ::WEBrick::HTTPServer.new(Port: settings.port, BindAddress: settings.address, - Logger: logger, AccessLog: access_log) - server.mount "/", Rack::Handler::WEBrick, rack_app - server.start - end - - def stop_working - server.shutdown if server - @server = nil - end - - def rack_app - Rack::Builder.app do - use Rack::Deflater - use ::Prometheus::Client::Rack::Exporter - run -> (env) { [404, {}, ['']] } - end + def log_filename + LOG_FILENAME end end end diff --git a/lib/gitlab/metrics/web_metrics_exporter.rb b/lib/gitlab/metrics/web_metrics_exporter.rb index 328bd07abda..275734a351e 100644 --- a/lib/gitlab/metrics/web_metrics_exporter.rb +++ b/lib/gitlab/metrics/web_metrics_exporter.rb @@ -1,48 +1,14 @@ -# frozen_string_literal: true - -require 'webrick' -require 'prometheus/client/rack/exporter' - module Gitlab module Metrics - class WebMetricsExporter < Daemon - LOG_FILENAME = File.join(Rails.root, 'log', 'sidekiq_exporter.log') - - def enabled? - ::Gitlab::Metrics.metrics_folder_present? && settings.enabled - end + class WebMetricsExporter < MetricsExporter + LOG_FILENAME = File.join(Rails.root, 'log', 'web_exporter.log') def settings Settings.monitoring.web_exporter end - private - - attr_reader :server - - def start_working - logger = WEBrick::Log.new(LOG_FILENAME) - access_log = [ - [logger, WEBrick::AccessLog::COMBINED_LOG_FORMAT] - ] - - @server = ::WEBrick::HTTPServer.new(Port: settings.port, BindAddress: settings.address, - Logger: logger, AccessLog: access_log) - server.mount "/", Rack::Handler::WEBrick, rack_app - server.start - end - - def stop_working - server.shutdown if server - @server = nil - end - - def rack_app - Rack::Builder.app do - use Rack::Deflater - use ::Prometheus::Client::Rack::Exporter - run -> (env) { [404, {}, ['']] } - end + def log_filename + LOG_FILENAME end end end diff --git a/spec/lib/gitlab/metrics/metrics_exporter_spec.rb b/spec/lib/gitlab/metrics/metrics_exporter_spec.rb new file mode 100644 index 00000000000..b03f918afaf --- /dev/null +++ b/spec/lib/gitlab/metrics/metrics_exporter_spec.rb @@ -0,0 +1,109 @@ +require 'spec_helper' + +describe Gitlab::Metrics::MetricsExporter do + let(:exporter) { described_class.new } + let(:server) { double('server') } + let(:log_filename) { File.join(Rails.root, 'log', 'sidekiq_exporter.log') } + let(:settings) { double('settings') } + + before do + allow(::WEBrick::HTTPServer).to receive(:new).and_return(server) + allow(server).to receive(:mount) + allow(server).to receive(:start) + allow(server).to receive(:shutdown) + allow_any_instance_of(described_class).to receive(:log_filename).and_return(log_filename) + allow_any_instance_of(described_class).to receive(:settings).and_return(settings) + end + + describe 'when exporter is enabled' do + before do + allow(settings).to receive(:enabled).and_return(true) + allow(settings).to receive(:port).and_return(3707) + allow(settings).to receive(:address).and_return('localhost') + end + + describe 'when exporter is stopped' do + describe '#start' do + it 'starts the exporter' do + expect { exporter.start.join }.to change { exporter.thread? }.from(false).to(true) + + expect(server).to have_received(:start) + end + + describe 'with custom settings' do + let(:port) { 99999 } + let(:address) { 'sidekiq_exporter_address' } + + before do + allow(settings).to receive(:port).and_return(port) + allow(settings).to receive(:address).and_return(address) + end + + it 'starts server with port and address from settings' do + exporter.start.join + + expect(::WEBrick::HTTPServer).to have_received(:new).with( + Port: port, + BindAddress: address, + Logger: anything, + AccessLog: anything + ) + end + end + end + + describe '#stop' do + it "doesn't shutdown stopped server" do + expect { exporter.stop }.not_to change { exporter.thread? } + + expect(server).not_to have_received(:shutdown) + end + end + end + + describe 'when exporter is running' do + before do + exporter.start.join + end + + describe '#start' do + it "doesn't start running server" do + expect { exporter.start.join }.not_to change { exporter.thread? } + + expect(server).to have_received(:start).once + end + end + + describe '#stop' do + it 'shutdowns server' do + expect { exporter.stop }.to change { exporter.thread? }.from(true).to(false) + + expect(server).to have_received(:shutdown) + end + end + end + end + + describe 'when exporter is disabled' do + before do + allow(settings).to receive(:enabled).and_return(false) + end + + describe '#start' do + it "doesn't start" do + expect(exporter.start).to be_nil + expect { exporter.start }.not_to change { exporter.thread? } + + expect(server).not_to have_received(:start) + end + end + + describe '#stop' do + it "doesn't shutdown" do + expect { exporter.stop }.not_to change { exporter.thread? } + + expect(server).not_to have_received(:shutdown) + end + end + end +end diff --git a/spec/lib/gitlab/metrics/sidekiq_metrics_exporter_spec.rb b/spec/lib/gitlab/metrics/sidekiq_metrics_exporter_spec.rb deleted file mode 100644 index 61eb059a731..00000000000 --- a/spec/lib/gitlab/metrics/sidekiq_metrics_exporter_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Metrics::SidekiqMetricsExporter do - let(:exporter) { described_class.new } - let(:server) { double('server') } - - before do - allow(::WEBrick::HTTPServer).to receive(:new).and_return(server) - allow(server).to receive(:mount) - allow(server).to receive(:start) - allow(server).to receive(:shutdown) - end - - describe 'when exporter is enabled' do - before do - allow(Settings.monitoring.sidekiq_exporter).to receive(:enabled).and_return(true) - end - - describe 'when exporter is stopped' do - describe '#start' do - it 'starts the exporter' do - expect { exporter.start.join }.to change { exporter.thread? }.from(false).to(true) - - expect(server).to have_received(:start) - end - - describe 'with custom settings' do - let(:port) { 99999 } - let(:address) { 'sidekiq_exporter_address' } - - before do - allow(Settings.monitoring.sidekiq_exporter).to receive(:port).and_return(port) - allow(Settings.monitoring.sidekiq_exporter).to receive(:address).and_return(address) - end - - it 'starts server with port and address from settings' do - exporter.start.join - - expect(::WEBrick::HTTPServer).to have_received(:new).with( - Port: port, - BindAddress: address, - Logger: anything, - AccessLog: anything - ) - end - end - end - - describe '#stop' do - it "doesn't shutdown stopped server" do - expect { exporter.stop }.not_to change { exporter.thread? } - - expect(server).not_to have_received(:shutdown) - end - end - end - - describe 'when exporter is running' do - before do - exporter.start.join - end - - describe '#start' do - it "doesn't start running server" do - expect { exporter.start.join }.not_to change { exporter.thread? } - - expect(server).to have_received(:start).once - end - end - - describe '#stop' do - it 'shutdowns server' do - expect { exporter.stop }.to change { exporter.thread? }.from(true).to(false) - - expect(server).to have_received(:shutdown) - end - end - end - end - - describe 'when exporter is disabled' do - before do - allow(Settings.monitoring.sidekiq_exporter).to receive(:enabled).and_return(false) - end - - describe '#start' do - it "doesn't start" do - expect(exporter.start).to be_nil - expect { exporter.start }.not_to change { exporter.thread? } - - expect(server).not_to have_received(:start) - end - end - - describe '#stop' do - it "doesn't shutdown" do - expect { exporter.stop }.not_to change { exporter.thread? } - - expect(server).not_to have_received(:shutdown) - end - end - end -end -- cgit v1.2.1