Add optional IPv6 support #38

Closed
wants to merge 2 commits into
from
View
@@ -12,6 +12,9 @@ Bundler:
# Set up a global Statsd client for a server on localhost:9125
$statsd = Statsd.new 'localhost', 9125
+ # Set up a global Statsd client for a server on IPv6 port 9125
+ $statsd = Statsd.new '::1', 9125, true
+
# Send some stats
$statsd.increment 'garets'
$statsd.timing 'glork', 320
View
@@ -3,8 +3,10 @@
# = Statsd: A Statsd client (https://github.com/etsy/statsd)
#
-# @example Set up a global Statsd client for a server on localhost:9125
+# @example Set up a global Statsd client for a server on localhost:8125
# $statsd = Statsd.new 'localhost', 8125
+# @example Set up a global Statsd client for a server on IPv6 port 8125
+# $statsd = Statsd.new '::1', 8125, true
# @example Send some stats
# $statsd.increment 'garets'
# $statsd.timing 'glork', 320
@@ -46,6 +48,7 @@ class Batch < Statsd
:namespace, :namespace=,
:host, :host=,
:port, :port=,
+ :ipv6, :ipv6=,
:prefix,
:postfix
@@ -97,6 +100,9 @@ def send_to_socket(message)
# StatsD port. Defaults to 8125.
attr_reader :port
+ # StatsD ipv6. Defaults to false.
+ attr_reader :ipv6
+
# StatsD namespace prefix, generated from #namespace
attr_reader :prefix
@@ -113,8 +119,9 @@ class << self
# @param [String] host your statsd host
# @param [Integer] port your statsd port
- def initialize(host = '127.0.0.1', port = 8125)
- self.host, self.port = host, port
+ # @param [Bool] ipv6 can be 'true' or 'false'
+ def initialize(host = '127.0.0.1', port = 8125, ipv6 = false)
+ self.host, self.port, self.ipv6 = host, port, ipv6
@prefix = nil
@batch_size = 10
@postfix = nil
@@ -149,6 +156,12 @@ def port=(port)
@port = port || 8125
end
+ # @attribute [w] ipv6
+ # Writes are not thread safe.
+ def ipv6=(ipv6)
+ @ipv6 = ipv6 || false
+ end
+
# Sends an increment (count = 1) for the given stat to the statsd server.
#
# @param [String] stat stat name
@@ -270,6 +283,10 @@ def send_stats(stat, delta, type, sample_rate=1)
end
def socket
- Thread.current[:statsd_socket] ||= UDPSocket.new
+ Thread.current[:statsd_socket] ||= UDPSocket.new addr_family
+ end
+
+ def addr_family
+ @ipv6 ? Socket::AF_INET6 : Socket::AF_INET
end
end
View
@@ -18,19 +18,22 @@ class Statsd
@statsd.port.must_equal 1234
end
- it "should default the host to 127.0.0.1 and port to 8125" do
+ it "should default the host to 127.0.0.1, port to 8125, and ipv6 to false" do
statsd = Statsd.new
statsd.host.must_equal '127.0.0.1'
statsd.port.must_equal 8125
+ statsd.ipv6.must_equal false
end
end
describe "#host and #port" do
- it "should set host and port" do
+ it "should set host, port and ipv6" do
@statsd.host = '1.2.3.4'
@statsd.port = 5678
+ @statsd.ipv6 = true
@statsd.host.must_equal '1.2.3.4'
@statsd.port.must_equal 5678
+ @statsd.ipv6.must_equal true
end
it "should not resolve hostnames to IPs" do
@@ -47,6 +50,16 @@ class Statsd
@statsd.port = nil
@statsd.port.must_equal 8125
end
+
+ it "should set nil ipv6 to default" do
+ @statsd.ipv6 = nil
+ @statsd.ipv6.must_equal false
+ end
+
+ it "should allow an IPv6 address" do
+ @statsd.host = '::1'
+ @statsd.host.must_equal '::1'
+ end
end
describe "#increment" do
@@ -351,6 +364,12 @@ class Statsd::SomeClass; end
@statsd.port.must_equal 42
end
+ it "should support setting ipv6 for the underlying instance" do
+ batch = Statsd::Batch.new(@statsd)
+ batch.ipv6 = true
+ @statsd.ipv6.must_equal true
+ end
+
end
describe "thread safety" do
@@ -370,7 +389,9 @@ class Statsd::SomeClass; end
describe Statsd do
describe "with a real UDP socket" do
+
it "should actually send stuff over the socket" do
+ Thread.current[:statsd_socket] = nil
socket = UDPSocket.new
host, port = 'localhost', 12345
socket.bind(host, port)
@@ -380,5 +401,29 @@ class Statsd::SomeClass; end
message = socket.recvfrom(16).first
message.must_equal 'foobar:1|c'
end
+
+ it "should send stuff over an IPv4 socket" do
+ Thread.current[:statsd_socket] = nil
+ socket = UDPSocket.new Socket::AF_INET
+ host, port = '127.0.0.1', 12346
+ socket.bind(host, port)
+
+ statsd = Statsd.new(host, port, false)
+ statsd.increment('foobar')
+ message = socket.recvfrom(16).first
+ message.must_equal 'foobar:1|c'
+ end
+
+ it "should send stuff over an IPv6 socket" do
+ Thread.current[:statsd_socket] = nil
+ socket = UDPSocket.new Socket::AF_INET6
+ host, port = '::1', 12347
+ socket.bind(host, port)
+
+ statsd = Statsd.new(host, port, true)
+ statsd.increment('foobar')
+ message = socket.recvfrom(16).first
+ message.must_equal 'foobar:1|c'
+ end
end
end if ENV['LIVE']