Skip to content

Commit 9a84011

Browse files
committed
feat: redis metrics [wip]
1 parent 6338eda commit 9a84011

File tree

5 files changed

+104
-1
lines changed

5 files changed

+104
-1
lines changed

instrumentation/redis/Appraisals

+18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
# frozen_string_literal: true
22

3+
appraise 'redis-4.x-metrics-sdk' do
4+
gem 'redis-client', '~> 0.22'
5+
gem 'redis', '~> 4.8'
6+
gem 'opentelemetry-metrics-sdk', github: "zvkemp/opentelemetry-ruby", glob: 'metrics_sdk/*.gemspec', ref: "metrics-kwargs"
7+
gem 'opentelemetry-metrics-api', github: "zvkemp/opentelemetry-ruby", glob: 'metrics_api/*.gemspec', ref: "metrics-kwargs"
8+
end
9+
10+
appraise 'redis-5.x-metrics-sdk' do
11+
gem 'redis', '~> 5.0'
12+
gem 'opentelemetry-metrics-sdk', github: "zvkemp/opentelemetry-ruby", glob: 'metrics_sdk/*.gemspec', ref: "metrics-kwargs"
13+
gem 'opentelemetry-metrics-api', github: "zvkemp/opentelemetry-ruby", glob: 'metrics_api/*.gemspec', ref: "metrics-kwargs"
14+
end
15+
16+
appraise 'redis-5.x-metrics-api' do
17+
gem 'redis', '~> 5.0'
18+
gem 'opentelemetry-metrics-api', github: "zvkemp/opentelemetry-ruby", glob: 'metrics_api/*.gemspec', ref: "metrics-kwargs"
19+
end
20+
321
appraise 'redis-4.x' do
422
gem 'redis-client', '~> 0.22'
523
gem 'redis', '~> 4.8'

instrumentation/redis/Gemfile

+2
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ gemspec
1111
group :test do
1212
gem 'opentelemetry-instrumentation-base', path: '../base'
1313
end
14+
15+
gem 'pry-byebug'

instrumentation/redis/lib/opentelemetry/instrumentation/redis/instrumentation.rb

+17-1
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,32 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base
2222
option :peer_service, default: nil, validate: :string
2323
option :trace_root_spans, default: true, validate: :boolean
2424
option :db_statement, default: :obfuscate, validate: %I[omit include obfuscate]
25+
option :metrics, default: false, validate: :boolean
26+
27+
# https://opentelemetry.io/docs/specs/semconv/database/database-metrics/#metric-dbclientoperationduration
28+
histogram 'db.client.operation.duration',
29+
attributes: { 'db.system.name' => 'redis' },
30+
unit: 's',
31+
boundaries: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10]
32+
33+
def client_operation_duration_histogram
34+
histogram('db.client.operation.duration')
35+
end
2536

2637
private
2738

2839
def require_dependencies
2940
require_relative 'patches/redis_v4_client' if defined?(::Redis) && ::Redis::VERSION < '5'
30-
require_relative 'middlewares/redis_client' if defined?(::RedisClient)
41+
42+
return unless defined?(::RedisClient)
43+
44+
require_relative 'middlewares/redis_client'
45+
require_relative 'middlewares/redis_client_metrics'
3146
end
3247

3348
def patch_client
3449
::RedisClient.register(Middlewares::RedisClientInstrumentation) if defined?(::RedisClient)
50+
::RedisClient.register(Middlewares::RedisClientMetrics) if defined?(::RedisClient)
3551
::Redis::Client.prepend(Patches::RedisV4Client) if defined?(::Redis) && ::Redis::VERSION < '5'
3652
end
3753
end

instrumentation/redis/lib/opentelemetry/instrumentation/redis/middlewares/redis_client.rb

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ def span_attributes(redis_config)
4949

5050
attributes['db.redis.database_index'] = redis_config.db unless redis_config.db.zero?
5151
attributes['peer.service'] = instrumentation.config[:peer_service] if instrumentation.config[:peer_service]
52+
5253
attributes.merge!(OpenTelemetry::Instrumentation::Redis.attributes)
5354
attributes
5455
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# frozen_string_literal: true
2+
3+
# Copyright The OpenTelemetry Authors
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
module OpenTelemetry
8+
module Instrumentation
9+
module Redis
10+
module Middlewares
11+
# Adapter for redis-client instrumentation interface
12+
module RedisClientMetrics
13+
def call(command, redis_config)
14+
return super unless (histogram = instrumentation.client_operation_duration_histogram)
15+
16+
timed(histogram, command.first, redis_config) do
17+
super
18+
end
19+
end
20+
21+
def call_pipelined(commands, redis_config)
22+
return super unless (histogram = instrumentation.client_operation_duration_histogram)
23+
24+
timed(histogram, 'PIPELINE', redis_config) do
25+
super
26+
end
27+
end
28+
29+
private
30+
31+
def timed(histogram, operation_name, redis_config)
32+
t0 = monotonic_now
33+
34+
yield.tap do
35+
duration = monotonic_now - t0
36+
37+
histogram.record(duration, attributes: metric_attributes(redis_config, operation_name))
38+
end
39+
end
40+
41+
def monotonic_now
42+
Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second)
43+
end
44+
45+
def metric_attributes(redis_config, operation_name)
46+
attributes = {
47+
'db.system' => 'redis',
48+
'db.operation.name' => operation_name,
49+
'net.peer.name' => redis_config.host,
50+
'net.peer.port' => redis_config.port
51+
}
52+
53+
attributes['db.redis.database_index'] = redis_config.db unless redis_config.db.zero?
54+
attributes['peer.service'] = instrumentation.config[:peer_service] if instrumentation.config[:peer_service]
55+
attributes.merge!(OpenTelemetry::Instrumentation::Redis.attributes)
56+
attributes
57+
end
58+
59+
def instrumentation
60+
Redis::Instrumentation.instance
61+
end
62+
end
63+
end
64+
end
65+
end
66+
end

0 commit comments

Comments
 (0)