Skip to content

Commit 5b82c79

Browse files
committed
Add support for dalli
1 parent 29653ea commit 5b82c79

File tree

15 files changed

+238
-14
lines changed

15 files changed

+238
-14
lines changed

.env

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ TEST_MYSQL_PASSWORD=mysql
88
TEST_MYSQL_USER=mysql
99
TEST_ELASTICSEARCH_REST_PORT=49200
1010
TEST_ELASTICSEARCH_NATIVE_PORT=49300
11-
TEST_REDIS_PORT=46379
11+
TEST_REDIS_PORT=46379
12+
TEST_MEMCACHED_PORT=41121

Appraisals

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ if RUBY_VERSION >= '2.2.2' && RUBY_PLATFORM != 'java'
122122
gem 'sidekiq'
123123
gem 'aws-sdk'
124124
gem 'sucker_punch'
125+
gem 'dalli'
125126
end
126127
else
127128
appraise 'contrib-old' do
@@ -136,5 +137,6 @@ else
136137
gem 'sidekiq', '4.0.0'
137138
gem 'aws-sdk', '~> 2.0'
138139
gem 'sucker_punch'
140+
gem 'dalli'
139141
end
140142
end

Rakefile

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,19 @@ namespace :test do
5151
t.test_files = FileList['test/contrib/rails/**/*disable_env*_test.rb']
5252
end
5353

54-
[:elasticsearch, :http, :redis, :sinatra, :sidekiq, :rack, :faraday, :grape, :aws, :sucker_punch].each do |contrib|
54+
[
55+
:elasticsearch,
56+
:http,
57+
:redis,
58+
:sinatra,
59+
:sidekiq,
60+
:rack,
61+
:faraday,
62+
:grape,
63+
:aws,
64+
:sucker_punch,
65+
:dalli
66+
].each do |contrib|
5567
Rake::TestTask.new(contrib) do |t|
5668
t.libs << %w[test lib]
5769
t.test_files = FileList["test/contrib/#{contrib}/*_test.rb"]

docker-compose.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ redis:
3232
ports:
3333
- "127.0.0.1:${TEST_REDIS_PORT}:6379"
3434

35+
memcached:
36+
image: memcached:1.5-alpine
37+
ports:
38+
- "127.0.0.1:${TEST_MEMCACHED_PORT}:11211"
39+
3540
ddagent:
3641
image: datadog/docker-dd-agent
3742
environment:

docs/GettingStarted.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,16 @@ services (S3, ElastiCache etc.).
333333

334334
Aws::S3::Client.new.list_buckets # traced call
335335

336+
### Dalli
337+
338+
Dalli integration will trace all calls to your `memcached` server:
339+
340+
require 'dalli'
341+
require 'ddtrace'
342+
343+
client = Dalli::Client.new('localhost:11211', options)
344+
client.set('abc', 123)
345+
336346
### Redis
337347

338348
The Redis integration will trace simple calls as well as pipelines.

gemfiles/contrib.gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ gem "activerecord"
1414
gem "sidekiq"
1515
gem "aws-sdk"
1616
gem "sucker_punch"
17+
gem "dalli"
1718

1819
gemspec path: "../"
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
require_relative 'quantize'
2+
require 'ddtrace/ext/net'
3+
4+
module Datadog
5+
module Contrib
6+
module Dalli
7+
# Instruments every interaction with the memcached server
8+
module Instrumentation
9+
module_function
10+
11+
def patch!
12+
::Dalli::Server.class_eval do
13+
alias_method :__request, :request
14+
15+
def request(op, *args)
16+
pin = Datadog::Pin.get_from(::Dalli)
17+
18+
pin.tracer.trace(Datadog::Contrib::Dalli::NAME) do |span|
19+
span.resource = op.to_s.upcase
20+
span.service = pin.service
21+
span.span_type = pin.app_type
22+
span.set_tag(Datadog::Ext::NET::TARGET_HOST, hostname)
23+
span.set_tag(Datadog::Ext::NET::TARGET_PORT, port)
24+
cmd = Datadog::Contrib::Dalli::Quantize.format_command(op, args)
25+
span.set_tag(Datadog::Contrib::Dalli::CMD_TAG, cmd)
26+
27+
__request(op, *args)
28+
end
29+
end
30+
end
31+
end
32+
end
33+
end
34+
end
35+
end
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
module Datadog
2+
module Contrib
3+
module Dalli
4+
COMPATIBLE_WITH = Gem::Version.new('2.0.0')
5+
SERVICE = 'memcached'.freeze
6+
NAME = 'memcached.command'.freeze
7+
CMD_TAG = 'memcached.command'.freeze
8+
9+
# Responsible for hooking the instrumentation into `dalli`
10+
module Patcher
11+
@patched = false
12+
13+
class << self
14+
def patch
15+
return @patched if patched? || !compatible?
16+
17+
require 'ddtrace/ext/app_types'
18+
require_relative 'instrumentation'
19+
20+
add_pin!
21+
Instrumentation.patch!
22+
23+
@patched = true
24+
rescue => e
25+
Tracer.log.error("Unable to apply Dalli integration: #{e}")
26+
@patched
27+
end
28+
29+
def patched?
30+
@patched
31+
end
32+
33+
private
34+
35+
def compatible?
36+
return unless defined?(::Dalli::VERSION)
37+
38+
Gem::Version.new(::Dalli::VERSION) > COMPATIBLE_WITH
39+
end
40+
41+
def add_pin!
42+
Pin.new(SERVICE, app_type: Ext::AppTypes::DB).tap do |pin|
43+
pin.onto(::Dalli)
44+
end
45+
end
46+
end
47+
end
48+
end
49+
end
50+
end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module Datadog
2+
module Contrib
3+
module Dalli
4+
# Quantize contains dalli-specic quantization tools.
5+
module Quantize
6+
MAX_CMD_LENGTH = 100
7+
8+
module_function
9+
10+
def format_command(operation, args)
11+
command = [operation, *args].join(' ').strip
12+
Utils.truncate(command, MAX_CMD_LENGTH)
13+
end
14+
end
15+
end
16+
end
17+
end

lib/ddtrace/contrib/redis/quantize.rb

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,16 @@ module Quantize
1111
module_function
1212

1313
def format_arg(arg)
14-
a = arg.to_s
15-
a = a[0..(VALUE_MAX_LEN - TOO_LONG_MARK.length - 1)] + TOO_LONG_MARK if a.length > VALUE_MAX_LEN
16-
a
14+
str = arg.to_s
15+
Utils.truncate(str, VALUE_MAX_LEN, TOO_LONG_MARK)
1716
rescue StandardError => e
18-
Datadog::Tracer.log.debug("non formattable Redis arg #{a}: #{e}")
17+
Datadog::Tracer.log.debug("non formattable Redis arg #{str}: #{e}")
1918
PLACEHOLDER
2019
end
2120

2221
def format_command_args(command_args)
2322
cmd = command_args.map { |x| format_arg(x) }.join(' ')
24-
cmd = cmd[0..(CMD_MAX_LEN - TOO_LONG_MARK.length - 1)] + TOO_LONG_MARK if cmd.length > CMD_MAX_LEN
25-
cmd
23+
Utils.truncate(cmd, CMD_MAX_LEN, TOO_LONG_MARK)
2624
end
2725
end
2826
end

0 commit comments

Comments
 (0)