diff options
Diffstat (limited to 'src/mod_metrics.erl')
-rw-r--r-- | src/mod_metrics.erl | 151 |
1 files changed, 103 insertions, 48 deletions
diff --git a/src/mod_metrics.erl b/src/mod_metrics.erl index f1d487e0e..297f3eeb5 100644 --- a/src/mod_metrics.erl +++ b/src/mod_metrics.erl @@ -5,7 +5,7 @@ %%% Created : 22 Oct 2015 by Christophe Romain <christophe.romain@process-one.net> %%% %%% -%%% ejabberd, Copyright (C) 2002-2016 ProcessOne +%%% ejabberd, Copyright (C) 2002-2019 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -25,40 +25,53 @@ -module(mod_metrics). --behaviour(ejabberd_config). -author('christophe.romain@process-one.net'). -behaviour(gen_mod). --include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). --define(HOOKS, [offline_message_hook, - sm_register_connection_hook, sm_remove_connection_hook, - user_send_packet, user_receive_packet, - s2s_send_packet, s2s_receive_packet, - remove_user, register_user]). - --export([start/2, stop/1, send_metrics/4, opt_type/1, mod_opt_type/1, - depends/2]). - --export([offline_message_hook/3, +-export([start/2, stop/1, mod_opt_type/1, mod_options/1, depends/2, reload/3]). +-export([push/2]). +-export([offline_message_hook/1, sm_register_connection_hook/3, sm_remove_connection_hook/3, - user_send_packet/4, user_receive_packet/5, - s2s_send_packet/3, s2s_receive_packet/3, + user_send_packet/1, user_receive_packet/1, + s2s_send_packet/1, s2s_receive_packet/1, remove_user/2, register_user/2]). +-define(SOCKET_NAME, mod_metrics_udp_socket). +-define(SOCKET_REGISTER_RETRIES, 10). + +-type probe() :: atom() | {atom(), integer()}. + %%==================================================================== %% API %%==================================================================== start(Host, _Opts) -> - [ejabberd_hooks:add(Hook, Host, ?MODULE, Hook, 20) - || Hook <- ?HOOKS]. + ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, offline_message_hook, 20), + ejabberd_hooks:add(sm_register_connection_hook, Host, ?MODULE, sm_register_connection_hook, 20), + ejabberd_hooks:add(sm_remove_connection_hook, Host, ?MODULE, sm_remove_connection_hook, 20), + ejabberd_hooks:add(user_send_packet, Host, ?MODULE, user_send_packet, 20), + ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, user_receive_packet, 20), + ejabberd_hooks:add(s2s_send_packet, Host, ?MODULE, s2s_send_packet, 20), + ejabberd_hooks:add(s2s_receive_packet, Host, ?MODULE, s2s_receive_packet, 20), + ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 20), + ejabberd_hooks:add(register_user, Host, ?MODULE, register_user, 20). stop(Host) -> - [ejabberd_hooks:delete(Hook, Host, ?MODULE, Hook, 20) - || Hook <- ?HOOKS]. + ejabberd_hooks:delete(offline_message_hook, Host, ?MODULE, offline_message_hook, 20), + ejabberd_hooks:delete(sm_register_connection_hook, Host, ?MODULE, sm_register_connection_hook, 20), + ejabberd_hooks:delete(sm_remove_connection_hook, Host, ?MODULE, sm_remove_connection_hook, 20), + ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, user_send_packet, 20), + ejabberd_hooks:delete(user_receive_packet, Host, ?MODULE, user_receive_packet, 20), + ejabberd_hooks:delete(s2s_send_packet, Host, ?MODULE, s2s_send_packet, 20), + ejabberd_hooks:delete(s2s_receive_packet, Host, ?MODULE, s2s_receive_packet, 20), + ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 20), + ejabberd_hooks:delete(register_user, Host, ?MODULE, register_user, 20). + +reload(_Host, _NewOpts, _OldOpts) -> + ok. depends(_Host, _Opts) -> []. @@ -66,70 +79,112 @@ depends(_Host, _Opts) -> %%==================================================================== %% Hooks handlers %%==================================================================== +-spec offline_message_hook({any(), message()}) -> {any(), message()}. +offline_message_hook({_Action, #message{to = #jid{lserver = LServer}}} = Acc) -> + push(LServer, offline_message), + Acc. -offline_message_hook(_From, #jid{lserver=LServer}, _Packet) -> - push(LServer, offline_message). - +-spec sm_register_connection_hook(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> any(). sm_register_connection_hook(_SID, #jid{lserver=LServer}, _Info) -> push(LServer, sm_register_connection). + +-spec sm_remove_connection_hook(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> any(). sm_remove_connection_hook(_SID, #jid{lserver=LServer}, _Info) -> push(LServer, sm_remove_connection). -user_send_packet(Packet, _C2SState, #jid{lserver=LServer}, _To) -> +-spec user_send_packet({stanza(), ejabberd_c2s:state()}) -> {stanza(), ejabberd_c2s:state()}. +user_send_packet({Packet, #{jid := #jid{lserver = LServer}} = C2SState}) -> push(LServer, user_send_packet), - Packet. -user_receive_packet(Packet, _C2SState, _JID, _From, #jid{lserver=LServer}) -> + {Packet, C2SState}. + +-spec user_receive_packet({stanza(), ejabberd_c2s:state()}) -> {stanza(), ejabberd_c2s:state()}. +user_receive_packet({Packet, #{jid := #jid{lserver = LServer}} = C2SState}) -> push(LServer, user_receive_packet), - Packet. + {Packet, C2SState}. -s2s_send_packet(#jid{lserver=LServer}, _To, _Packet) -> +-spec s2s_send_packet(stanza()) -> any(). +s2s_send_packet(Packet) -> + #jid{lserver = LServer} = xmpp:get_from(Packet), push(LServer, s2s_send_packet). -s2s_receive_packet(_From, #jid{lserver=LServer}, _Packet) -> - push(LServer, s2s_receive_packet). +-spec s2s_receive_packet({stanza(), ejabberd_s2s_in:state()}) -> + {stanza(), ejabberd_s2s_in:state()}. +s2s_receive_packet({Packet, S2SState}) -> + To = xmpp:get_to(Packet), + LServer = ejabberd_router:host_of_route(To#jid.lserver), + push(LServer, s2s_receive_packet), + {Packet, S2SState}. + +-spec remove_user(binary(), binary()) -> any(). remove_user(_User, Server) -> push(jid:nameprep(Server), remove_user). + +-spec register_user(binary(), binary()) -> any(). register_user(_User, Server) -> push(jid:nameprep(Server), register_user). %%==================================================================== %% metrics push handler %%==================================================================== - +-spec push(binary(), probe()) -> ok | {error, not_owner | inet:posix()}. push(Host, Probe) -> - spawn(?MODULE, send_metrics, [Host, Probe, {127,0,0,1}, 11111]). + IP = mod_metrics_opt:ip(Host), + Port = mod_metrics_opt:port(Host), + send_metrics(Host, Probe, IP, Port). +-spec send_metrics(binary(), probe(), inet:ip4_address(), inet:port_number()) -> + ok | {error, not_owner | inet:posix()}. send_metrics(Host, Probe, Peer, Port) -> % our default metrics handler is https://github.com/processone/grapherl % grapherl metrics are named first with service domain, then nodename % and name of the data itself, followed by type timestamp and value % example => process-one.net/xmpp-1.user_receive_packet:c/1441784958:1 - [_, NodeId] = str:tokens(jlib:atom_to_binary(node()), <<"@">>), - [Node | _] = str:tokens(NodeId, <<".">>), + [_, FQDN] = binary:split(misc:atom_to_binary(node()), <<"@">>), + [Node|_] = binary:split(FQDN, <<".">>), BaseId = <<Host/binary, "/", Node/binary, ".">>, - DateTime = erlang:universaltime(), - UnixTime = calendar:datetime_to_gregorian_seconds(DateTime) - 62167219200, - TS = integer_to_binary(UnixTime), - case gen_udp:open(0) of + TS = integer_to_binary(erlang:system_time(second)), + case get_socket(?SOCKET_REGISTER_RETRIES) of {ok, Socket} -> case Probe of {Key, Val} -> BVal = integer_to_binary(Val), - Data = <<BaseId/binary, (jlib:atom_to_binary(Key))/binary, + Data = <<BaseId/binary, (misc:atom_to_binary(Key))/binary, ":g/", TS/binary, ":", BVal/binary>>, gen_udp:send(Socket, Peer, Port, Data); Key -> - Data = <<BaseId/binary, (jlib:atom_to_binary(Key))/binary, + Data = <<BaseId/binary, (misc:atom_to_binary(Key))/binary, ":c/", TS/binary, ":1">>, gen_udp:send(Socket, Peer, Port, Data) - end, - gen_udp:close(Socket); - Error -> - ?WARNING_MSG("can not open udp socket to grapherl: ~p", [Error]) + end; + Err -> + Err end. -opt_type(_) -> - []. +-spec get_socket(integer()) -> {ok, gen_udp:socket()} | {error, inet:posix()}. +get_socket(N) -> + case whereis(?SOCKET_NAME) of + undefined -> + case gen_udp:open(0) of + {ok, Socket} -> + try register(?SOCKET_NAME, Socket) of + true -> {ok, Socket} + catch _:badarg when N > 1 -> + gen_udp:close(Socket), + get_socket(N-1) + end; + {error, Reason} = Err -> + ?ERROR_MSG("Can not open udp socket to grapherl: ~ts", + [inet:format_error(Reason)]), + Err + end; + Socket -> + {ok, Socket} + end. -mod_opt_type(_) -> - []. +mod_opt_type(ip) -> + econf:ipv4(); +mod_opt_type(port) -> + econf:port(). + +mod_options(_) -> + [{ip, {127,0,0,1}}, {port, 11111}]. |