Skip to content

Commit

Permalink
Push fact check metrics to prometheus
Browse files Browse the repository at this point in the history
Inspired by alphagov/search-api-v2#209

This adds the prometheus-client gem, and then uses it to send fact check emails metrics to prometheus via the pushgateway.

We can't use the conventional prometheus collector, because this code runs as a script, rather than a web process.

This should not be merged until we've set the PROMETHEUS_PUSHGATEWAY_URL environment variable.
  • Loading branch information
richardTowers committed Aug 1, 2024
1 parent 1227bd3 commit eca7d59
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 8 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ gem "mousetrap-rails"
gem "nested_form", git: "https://github.com/alphagov/nested_form.git", branch: "add-wrapper-class"
gem "null_logger"
gem "plek"
gem "prometheus-client"
gem "rails_autolink"
gem "rest-client", require: false
gem "sassc-rails"
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,8 @@ GEM
ast (~> 2.4.1)
racc
plek (5.2.0)
prometheus-client (4.2.3)
base64
prometheus_exporter (2.1.1)
webrick
pry (0.14.1)
Expand Down Expand Up @@ -850,6 +852,7 @@ DEPENDENCIES
nested_form!
null_logger
plek
prometheus-client
pry-byebug
rack
rails (= 7.0.8.3)
Expand Down
5 changes: 3 additions & 2 deletions app/lib/fact_check_email_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
class FactCheckEmailHandler
attr_accessor :fact_check_config

def initialize(fact_check_config)
def initialize(fact_check_config, unprocessed_emails_gauge)
@fact_check_config = fact_check_config
@unprocessed_emails_gauge = unprocessed_emails_gauge
end

def process_message(message)
Expand All @@ -35,7 +36,7 @@ def process
unprocessed_emails_count += 1
end

GovukStatsd.gauge("unprocessed_emails.count", unprocessed_emails_count)
@unprocessed_emails_gauge.set(unprocessed_emails_count)
rescue StandardError => e
# Occasionally, there is an error when connecting to the mailbox in production.
# It seems a very transient error, and since the job is run every few minutes isn't really a problem, but if the
Expand Down
11 changes: 10 additions & 1 deletion script/mail_fetcher
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ end

Rails.logger.info "Running MailFetcher in #{Rails.env} mode - #{Time.zone.now.utc}"

handler = FactCheckEmailHandler.new(Publisher::Application.fact_check_config)
registry = Prometheus::Client.registry
gauge = registry.gauge(
:publisher_fact_check_unprocessed_emails_total,
docstring: "Number of unprocessed fact check emails"

Check failure on line 26 in script/mail_fetcher

View workflow job for this annotation

GitHub Actions / Lint Ruby / Run RuboCop

Style/TrailingCommaInArguments: Put a comma after the last parameter of a multiline method call. (https://rubystyle.guide#no-trailing-params-comma)
)
handler = FactCheckEmailHandler.new(Publisher::Application.fact_check_config, gauge)

# The lock is created and belongs to this process for as long as the `life`.
# When the block has finished executing, the lock is explicitly released.
Expand Down Expand Up @@ -50,3 +55,7 @@ rescue StandardError => e
end

Rails.logger.info "Finished running MailFetcher in #{Rails.env} mode - #{Time.zone.now.utc}"
Prometheus::Client::Push.new(
job: "publisher_fact_check_emails",
gateway: ENV.fetch("PROMETHEUS_PUSHGATEWAY_URL"),
).add(registry)
15 changes: 10 additions & 5 deletions test/unit/lib/fact_check_email_handler_test.rb
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
require "test_helper"

class FactCheckEmailHandlerTest < ActiveSupport::TestCase
setup do
@gauge = stub()

Check failure on line 5 in test/unit/lib/fact_check_email_handler_test.rb

View workflow job for this annotation

GitHub Actions / Lint Ruby / Run RuboCop

Style/MethodCallWithoutArgsParentheses: Do not use parentheses for method calls with no arguments. (https://rubystyle.guide#method-invocation-parens)
end

def handler
FactCheckEmailHandler.new(Publisher::Application.fact_check_config)
FactCheckEmailHandler.new(Publisher::Application.fact_check_config, @gauge)
end

test "#process ignores 'out of office' emails" do
out_of_office_message = Mail.new { subject("Automatic reply: out of office") }
Mail.stubs(:all).yields(out_of_office_message)
@gauge.expects(:set).with(0)
handler.process
assert out_of_office_message.is_marked_for_delete?
end

test "#process sends count of unprocessed emails to Graphite" do
test "#process sends count of unprocessed emails to Prometheus" do
processed_message = Mail.new { subject("Automatic reply: out of office") }
unprocessed_message = Mail.new { subject("Any other subject") }
GovukStatsd.expects(:gauge).with("unprocessed_emails.count", 1)
@gauge.expects(:set).with(1)
Mail.stubs(:all).multiple_yields(processed_message, unprocessed_message)

handler.process
end

test "#process does not send count of unprocessed emails to Graphite when emails cannot be retrieved" do
test "#process does not send count of unprocessed emails to Prometheus when emails cannot be retrieved" do
Mail.stubs(:all).raises(StandardError)
GovukStatsd.expects(:gauge).never
@gauge.expects(:set).never

handler.process
end
Expand Down

0 comments on commit eca7d59

Please sign in to comment.