diff --git a/README.md b/README.md
index ebff90a..4076a3d 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ High Performance Erlang StatsD Client
hostname |
- inet:ip_address() | inet:hostname() | binary() |
+ inet:ip_address() | inet:hostname() | binary() | [{inet:ip_address() | inet:hostname() | binary(), inet:port_number()}] |
{127,0,0,1} |
server hostname |
@@ -41,7 +41,7 @@ High Performance Erlang StatsD Client
port |
inet:port_number() |
8125 |
- server port |
+ server port. Not needed when using the list syntax in the hostname variable |
diff --git a/src/statsderl.erl b/src/statsderl.erl
index 6a6037d..6db35b2 100644
--- a/src/statsderl.erl
+++ b/src/statsderl.erl
@@ -71,8 +71,9 @@ cast(OpCode, Key, Value, SampleRate) ->
cast(OpCode, Key, Value, SampleRate, ServerName).
cast(OpCode, Key, Value, SampleRate, ServerName) ->
+ KeyHash = erlang:phash2(iolist_to_binary(Key)),
Packet = statsderl_protocol:encode(OpCode, Key, Value, SampleRate),
- send(ServerName, {cast, Packet}).
+ send(ServerName, {cast, KeyHash, Packet}).
maybe_cast(OpCode, Key, Value, 1) ->
cast(OpCode, Key, Value, 1);
diff --git a/src/statsderl_server.erl b/src/statsderl_server.erl
index 63f5fca..ef07569 100644
--- a/src/statsderl_server.erl
+++ b/src/statsderl_server.erl
@@ -7,7 +7,7 @@
]).
-record(state, {
- header :: iodata(),
+ headers :: tuple(),
socket :: inet:socket()
}).
@@ -17,22 +17,26 @@
init(Parent, Name) ->
BaseKey = ?ENV(?ENV_BASEKEY, ?DEFAULT_BASEKEY),
Hostname = ?ENV(?ENV_HOSTNAME, ?DEFAULT_HOSTNAME),
- Port = ?ENV(?ENV_PORT, ?DEFAULT_PORT),
+ {ok, Headers} = case is_list(Hostname)
+ andalso Hostname /= []
+ andalso is_tuple(hd(Hostname)) of
+ true ->
+ generate_udp_headers(Hostname, BaseKey, []);
+ false ->
+ Port = ?ENV(?ENV_PORT, ?DEFAULT_PORT),
+ generate_udp_headers([{Hostname, Port}],
+ BaseKey, [])
+ end,
- case udp_header(Hostname, Port, BaseKey) of
- {ok, Header} ->
- case gen_udp:open(0, [{active, false}]) of
- {ok, Socket} ->
- register(Name, self()),
- proc_lib:init_ack(Parent, {ok, self()}),
+ case gen_udp:open(0, [{active, false}]) of
+ {ok, Socket} ->
+ register(Name, self()),
+ proc_lib:init_ack(Parent, {ok, self()}),
- loop(#state {
- socket = Socket,
- header = Header
- });
- {error, Reason} ->
- exit(Reason)
- end;
+ loop(#state {
+ socket = Socket,
+ headers = list_to_tuple(Headers)
+ });
{error, Reason} ->
exit(Reason)
end.
@@ -43,11 +47,12 @@ start_link(Name) ->
proc_lib:start_link(?MODULE, init, [self(), Name]).
%% private
-handle_msg({cast, Packet}, #state {
- header = Header,
+handle_msg({cast, KeyHash, Packet}, #state {
+ headers = Headers,
socket = Socket
} = State) ->
+ Header = element((KeyHash rem tuple_size(Headers)) + 1, Headers),
statsderl_udp:send(Socket, Header, Packet),
{ok, State};
handle_msg({inet_reply, _Socket, ok}, State) ->
@@ -62,6 +67,16 @@ loop(State) ->
loop(State2)
end.
+generate_udp_headers([], _BaseKey, Acc) ->
+ {ok, lists:reverse(Acc)};
+generate_udp_headers([{Hostname, Port} | Rest], BaseKey, Acc) ->
+ case udp_header(Hostname, Port, BaseKey) of
+ {ok, Header} ->
+ generate_udp_headers(Rest, BaseKey, [Header | Acc]);
+ Error ->
+ Error
+ end.
+
udp_header(Hostname, Port, BaseKey) ->
case statsderl_utils:getaddrs(Hostname) of
{ok, {A, B, C, D}} ->
diff --git a/test/statsderl_tests.erl b/test/statsderl_tests.erl
index 0dc6d85..b5bd2a1 100644
--- a/test/statsderl_tests.erl
+++ b/test/statsderl_tests.erl
@@ -20,6 +20,19 @@ statsderl_hostname_test() ->
meck:unload(statsderl_utils),
cleanup(Socket).
+statsderl_multiple_hostname_test() ->
+ meck:new(statsderl_utils, [passthrough, no_history]),
+ meck:expect(statsderl_utils, getaddrs, fun (_) ->
+ {ok, {127, 0, 0, 1}}
+ end),
+ Socket = setup([{?ENV_HOSTNAME,
+ [{<<"adgear.com">>, ?DEFAULT_PORT}, {"whatever.com", ?DEFAULT_PORT}]}]),
+ statsderl:counter("test", 1, 1),
+ {ok, {_Address, _Port, Packet}} = gen_udp:recv(Socket, 0),
+ ?assertEqual(<<"test:1|c">>, Packet),
+ meck:unload(statsderl_utils),
+ cleanup(Socket).
+
statsderl_test_() ->
{setup,
fun () -> setup() end,