diff --git a/config/initializers/prometheus.rb b/config/initializers/prometheus.rb index 4b842d841..7c2d42743 100644 --- a/config/initializers/prometheus.rb +++ b/config/initializers/prometheus.rb @@ -1,2 +1,4 @@ require "govuk_app_config/govuk_prometheus_exporter" -GovukPrometheusExporter.configure +require "collectors/global_prometheus_collector" + +GovukPrometheusExporter.configure(collectors: [Collectors::GlobalPrometheusCollector]) diff --git a/lib/collectors/global_prometheus_collector.rb b/lib/collectors/global_prometheus_collector.rb new file mode 100644 index 000000000..ff2f9065a --- /dev/null +++ b/lib/collectors/global_prometheus_collector.rb @@ -0,0 +1,40 @@ +require "prometheus_exporter" +require "prometheus_exporter/server" + +# Load Rails models as not automatically included for Prometheus Exporter +require File.expand_path("../../config/environment", __dir__) unless defined? Rails + +module Collectors + class GlobalPrometheusCollector < PrometheusExporter::Server::TypeCollector + def type + "signon_global" + end + + def metrics + token_expiry_timestamp = PrometheusExporter::Metric::Gauge.new("signon_api_user_token_expiry_timestamp_seconds", "Timestamp when API User token expires") + + token_expiry_info.each do |token| + token_expiry_timestamp.observe(token[:expires_at], api_user: token[:api_user], application: token[:application_name]) + end + + [token_expiry_timestamp] + end + + private + + def token_expiry_info + # Cache metric to prevent needless expensive calls to the database + Rails.cache.fetch("token_expiry_info", expires_in: 1.hour) do + ApiUser.all.flat_map do |user| + user.authorisations.where(revoked_at: nil).map do |token| + { + expires_at: token.expires_at.to_i, + api_user: user.email, + application_name: token.application.name.parameterize, + } + end + end + end + end + end +end diff --git a/test/lib/collectors/global_prometheus_collector_test.rb b/test/lib/collectors/global_prometheus_collector_test.rb new file mode 100644 index 000000000..d53a0282e --- /dev/null +++ b/test/lib/collectors/global_prometheus_collector_test.rb @@ -0,0 +1,27 @@ +require "test_helper" + +class GlobalPrometheusCollectorTest < ActiveSupport::TestCase + def setup + @collector = Collectors::GlobalPrometheusCollector.new + @api_user = api_user_with_token("user1", token_count: 3) + end + + context "#metrics" do + should "list all non-revoked token expiry timestamps" do + @api_user.authorisations[2].revoke + + metrics = @collector.metrics + + assert_equal metrics.first.data, { + { + api_user: @api_user.email, + application: @api_user.authorisations.first.application.name.parameterize, + } => @api_user.authorisations.first.expires_at.to_i, + { + api_user: @api_user.email, + application: @api_user.authorisations.second.application.name.parameterize, + } => @api_user.authorisations.second.expires_at.to_i, + } + end + end +end