Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add Dalli::Client memcache metrics for web_collector #307

Merged
merged 3 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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