diff --git a/README.md b/README.md index 667753e..3235f5d 100644 --- a/README.md +++ b/README.md @@ -213,13 +213,14 @@ Rails.application.middleware.unshift PrometheusExporter::Middleware, instrument: #### Metrics collected by Rails integration middleware -| Type | Name | Description | -| --- | --- | --- | -| Counter | `http_requests_total` | Total HTTP requests from web app | -| Summary | `http_request_duration_seconds` | Time spent in HTTP reqs in seconds | -| Summary | `http_request_redis_duration_seconds`¹ | Time spent in HTTP reqs in Redis, in seconds | -| Summary | `http_request_sql_duration_seconds`² | Time spent in HTTP reqs in SQL in seconds | -| Summary | `http_request_queue_duration_seconds`³ | Time spent queueing the request in load balancer in seconds | +| Type | Name | Description | +| --- | --- | --- | +| Counter | `http_requests_total` | Total HTTP requests from web app | +| Summary | `http_request_duration_seconds` | Time spent in HTTP reqs in seconds | +| Summary | `http_request_redis_duration_seconds`¹ | Time spent in HTTP reqs in Redis, in seconds | +| Summary | `http_request_sql_duration_seconds`² | Time spent in HTTP reqs in SQL in seconds | +| Summary | `http_request_queue_duration_seconds`³ | Time spent queueing the request in load balancer in seconds | +| Summary | `http_request_memcache_duration_seconds`⁴ | Time spent in HTTP reqs in Memcache in seconds | All metrics have a `controller` and an `action` label. `http_requests_total` additionally has a (HTTP response) `status` label. @@ -268,6 +269,7 @@ ruby_http_request_duration_seconds{path="/api/v1/teams/:id",method="GET",status= ¹) Only available when Redis is used. ²) Only available when Mysql or PostgreSQL are used. ³) Only available when [Instrumenting Request Queueing Time](#instrumenting-request-queueing-time) is set up. +⁴) Only available when Dalli is used. #### Activerecord Connection Pool Metrics diff --git a/lib/prometheus_exporter/middleware.rb b/lib/prometheus_exporter/middleware.rb index be60165..3595050 100644 --- a/lib/prometheus_exporter/middleware.rb +++ b/lib/prometheus_exporter/middleware.rb @@ -31,6 +31,9 @@ def initialize(app, config = { instrument: :alias_method, client: nil }) MethodProfiler.patch(Mysql2::Statement, [:execute], :sql, instrument: config[:instrument]) MethodProfiler.patch(Mysql2::Result, [:each], :sql, instrument: config[:instrument]) end + if defined? Dalli::Client + MethodProfiler.patch(Dalli::Client, %i[delete fetch get add set], :memcache, instrument: config[:instrument]) + end end end diff --git a/lib/prometheus_exporter/server/web_collector.rb b/lib/prometheus_exporter/server/web_collector.rb index b45b6b4..cb3b0ff 100644 --- a/lib/prometheus_exporter/server/web_collector.rb +++ b/lib/prometheus_exporter/server/web_collector.rb @@ -9,6 +9,7 @@ def initialize @http_request_redis_duration_seconds = nil @http_request_sql_duration_seconds = nil @http_request_queue_duration_seconds = nil + @http_request_memcache_duration_seconds = nil end def type @@ -48,6 +49,11 @@ def ensure_metrics "Time spent in HTTP reqs in SQL in seconds." ) + @metrics["http_request_memcache_duration_seconds"] = @http_request_memcache_duration_seconds = PrometheusExporter::Metric::Base.default_aggregation.new( + "http_request_memcache_duration_seconds", + "Time spent in HTTP reqs in Memcache in seconds." + ) + @metrics["http_request_queue_duration_seconds"] = @http_request_queue_duration_seconds = PrometheusExporter::Metric::Base.default_aggregation.new( "http_request_queue_duration_seconds", "Time spent queueing the request in load balancer in seconds." @@ -70,6 +76,9 @@ def observe(obj) if sql = timings["sql"] @http_request_sql_duration_seconds.observe(sql["duration"], labels) end + if memcache = timings["memcache"] + @http_request_memcache_duration_seconds.observe(memcache["duration"], labels) + end end if queue_time = obj["queue_time"] @http_request_queue_duration_seconds.observe(queue_time, labels) diff --git a/test/middleware_test.rb b/test/middleware_test.rb index c764cf5..69826cc 100644 --- a/test/middleware_test.rb +++ b/test/middleware_test.rb @@ -164,6 +164,17 @@ def test_patch_called_with_prepend_instrument mock.verify end end + + Object.stub_const(:Dalli, Module) do + ::Dalli.stub_const(:Client) do + mock = Minitest::Mock.new + mock.expect :call, nil, [Dalli::Client, Array, :memcache, { instrument: :prepend }] + ::PrometheusExporter::Instrumentation::MethodProfiler.stub(:patch, mock) do + configure_middleware(instrument: :prepend) + end + mock.verify + end + end end def test_patch_called_with_alias_method_instrument @@ -204,5 +215,16 @@ def test_patch_called_with_alias_method_instrument mock.verify end end + + Object.stub_const(:Dalli, Module) do + ::Dalli.stub_const(:Client) do + mock = Minitest::Mock.new + mock.expect :call, nil, [Dalli::Client, Array, :memcache, { instrument: :alias_method }] + ::PrometheusExporter::Instrumentation::MethodProfiler.stub(:patch, mock) do + configure_middleware(instrument: :alias_method) + end + mock.verify + end + end end end diff --git a/test/server/web_collector_test.rb b/test/server/web_collector_test.rb index 39b1815..1d20f0d 100644 --- a/test/server/web_collector_test.rb +++ b/test/server/web_collector_test.rb @@ -32,7 +32,7 @@ def test_collecting_metrics_without_specific_timings metrics = collector.metrics - assert_equal 5, metrics.size + assert_equal 6, metrics.size end def test_collecting_metrics @@ -47,6 +47,10 @@ def test_collecting_metrics duration: 0.03, count: 4 }, + "memcache" => { + duration: 0.02, + count: 1 + }, "queue" => 0.03, "total_duration" => 1.0 }, @@ -58,7 +62,7 @@ def test_collecting_metrics ) metrics = collector.metrics - assert_equal 5, metrics.size + assert_equal 6, metrics.size end def test_collecting_metrics_with_custom_labels @@ -77,7 +81,7 @@ def test_collecting_metrics_with_custom_labels metrics = collector.metrics - assert_equal 5, metrics.size + assert_equal 6, metrics.size assert(metrics.first.metric_text.include?('http_requests_total{controller="home",action="index",service="service1",status="200"} 1')) end @@ -98,7 +102,7 @@ def test_collecting_metrics_merging_custom_labels_and_status metrics = collector.metrics - assert_equal 5, metrics.size + assert_equal 6, metrics.size assert(metrics.first.metric_text.include?('http_requests_total{controller="home",action="index",service="service1",status="200"} 1')) end @@ -117,6 +121,10 @@ def test_collecting_metrics_in_histogram_mode duration: 0.03, count: 4 }, + "memcache" => { + duration: 0.02, + count: 1 + }, "queue" => 0.03, "total_duration" => 1.0, }, @@ -132,7 +140,7 @@ def test_collecting_metrics_in_histogram_mode metrics = collector.metrics metrics_lines = metrics.map(&:metric_text).flat_map(&:lines) - assert_equal 5, metrics.size + assert_equal 6, metrics.size assert_includes(metrics_lines, "http_requests_total{controller=\"home\",action=\"index\",service=\"service1\",status=\"200\"} 1") assert_includes(metrics_lines, "http_request_duration_seconds_bucket{controller=\"home\",action=\"index\",service=\"service1\",le=\"+Inf\"} 1\n") end