Skip to content

Commit

Permalink
Feature: Add Dalli::Client memcache metrics for web_collector (#307)
Browse files Browse the repository at this point in the history
Added Dalli::Client in middleware
Collected memcache metrics in web_collector
  • Loading branch information
Subramanya-Murugesan authored Jun 20, 2024
1 parent d631b4c commit cbb669b
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 12 deletions.
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions lib/prometheus_exporter/middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
9 changes: 9 additions & 0 deletions lib/prometheus_exporter/server/web_collector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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."
Expand All @@ -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)
Expand Down
22 changes: 22 additions & 0 deletions test/middleware_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
18 changes: 13 additions & 5 deletions test/server/web_collector_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
},
Expand All @@ -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
Expand All @@ -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

Expand All @@ -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

Expand All @@ -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,
},
Expand All @@ -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
Expand Down

0 comments on commit cbb669b

Please sign in to comment.