diff --git a/CHANGES b/CHANGES index 4a55a06ff2c3c5b17d307bce95824e08a345bb28..348927b1d89c77edddfa40e8c662e1bbad7cb729 100644 --- a/CHANGES +++ b/CHANGES @@ -36,10 +36,19 @@ Dialplan Functions res_pjsip_outbound_registration ------------------------------- -* A new 'fatal_retry_interval' option has been added to outbound registration. - When set (default is zero), and upon receiving a failure response to an - outbound registration, registration is retried at the given interval up to - 'max_retries'. + * A new 'fatal_retry_interval' option has been added to outbound registration. + When set (default is zero), and upon receiving a failure response to an + outbound registration, registration is retried at the given interval up to + 'max_retries'. + + * If res_statsd is loaded and a StatsD server is configured, basic statistics + regarding the state of outbound registrations will now be emitted. This + includes: + - A GUAGE statistic for the overall number of outbound registrations, i.e.: + PJSIP.registrations.count + - A GUAGE statistic for the overall number of outbound registrations in a + particular state, e.g.: + PJSIP.registrations.state.Registered res_pjsip ------------------ diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 9795a5971a053f4c1188d65893d7340206b3d6a1..6f3155d8b7c0ebee67dbb1ae4f866f20b5ac8682 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -35,6 +35,7 @@ #include "asterisk/stasis_system.h" #include "asterisk/threadstorage.h" #include "asterisk/threadpool.h" +#include "asterisk/statsd.h" #include "res_pjsip/include/res_pjsip_private.h" /*** DOCUMENTATION @@ -612,6 +613,19 @@ static void schedule_registration(struct sip_outbound_registration_client_state } } +static void update_client_state_status(struct sip_outbound_registration_client_state *client_state, enum sip_outbound_registration_status status) +{ + if (client_state->status == status) { + return; + } + + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GUAGE, "-1", 1.0, + sip_outbound_registration_status_str(client_state->status)); + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GUAGE, "+1", 1.0, + sip_outbound_registration_status_str(status)); + client_state->status = status; +} + /*! \brief Callback function for unregistering (potentially) and destroying state */ static int handle_client_state_destruction(void *data) { @@ -645,7 +659,7 @@ static int handle_client_state_destruction(void *data) (int) info.server_uri.slen, info.server_uri.ptr, (int) info.client_uri.slen, info.client_uri.ptr); - client_state->status = SIP_REGISTRATION_STOPPING; + update_client_state_status(client_state, SIP_REGISTRATION_STOPPING); client_state->destroy = 1; if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS && registration_client_send(client_state, tdata) == PJ_SUCCESS) { @@ -664,7 +678,7 @@ static int handle_client_state_destruction(void *data) client_state->client = NULL; } - client_state->status = SIP_REGISTRATION_STOPPED; + update_client_state_status(client_state, SIP_REGISTRATION_STOPPED); ast_sip_auth_vector_destroy(&client_state->outbound_auths); ao2_ref(client_state, -1); @@ -726,7 +740,7 @@ static int sip_outbound_registration_is_temporal(unsigned int code, static void schedule_retry(struct registration_response *response, unsigned int interval, const char *server_uri, const char *client_uri) { - response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY; + update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY); schedule_registration(response->client_state, interval); if (response->rdata) { @@ -800,7 +814,7 @@ static int handle_registration_response(void *data) /* If the registration went fine simply reschedule registration for the future */ ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri); - response->client_state->status = SIP_REGISTRATION_REGISTERED; + update_client_state_status(response->client_state, SIP_REGISTRATION_REGISTERED); response->client_state->retries = 0; next_registration_round = response->expiration - REREGISTER_BUFFER_TIME; if (next_registration_round < 0) { @@ -810,7 +824,7 @@ static int handle_registration_response(void *data) schedule_registration(response->client_state, next_registration_round); } else { ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri); - response->client_state->status = SIP_REGISTRATION_UNREGISTERED; + update_client_state_status(response->client_state, SIP_REGISTRATION_UNREGISTERED); } } else if (response->client_state->destroy) { /* We need to deal with the pending destruction instead. */ @@ -821,7 +835,7 @@ static int handle_registration_response(void *data) && sip_outbound_registration_is_temporal(response->code, response->client_state)) { if (response->client_state->retries == response->client_state->max_retries) { /* If we received enough temporal responses to exceed our maximum give up permanently */ - response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT; + update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_PERMANENT); ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n", server_uri, client_uri); } else { @@ -834,7 +848,7 @@ static int handle_registration_response(void *data) && response->client_state->forbidden_retry_interval && response->client_state->retries < response->client_state->max_retries) { /* A forbidden response retry interval is configured and there are retries remaining */ - response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY; + update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY); response->client_state->retries++; schedule_registration(response->client_state, response->client_state->forbidden_retry_interval); ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n", @@ -842,14 +856,14 @@ static int handle_registration_response(void *data) } else if (response->client_state->fatal_retry_interval && response->client_state->retries < response->client_state->max_retries) { /* Some kind of fatal failure response received, so retry according to configured interval */ - response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY; + update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY); response->client_state->retries++; schedule_registration(response->client_state, response->client_state->fatal_retry_interval); ast_log(LOG_WARNING, "'%d' fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n", response->code, server_uri, client_uri, response->client_state->fatal_retry_interval); } else { /* Finally if there's no hope of registering give up */ - response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT; + update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_PERMANENT); if (response->rdata) { ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n", response->code, server_uri, client_uri); @@ -934,7 +948,6 @@ static void sip_outbound_registration_state_destroy(void *obj) ast_debug(3, "Destroying registration state for registration to server '%s' from client '%s'\n", state->registration->server_uri, state->registration->client_uri); - ao2_cleanup(state->registration); if (!state->client_state) { @@ -953,6 +966,10 @@ static void sip_outbound_registration_client_state_destroy(void *obj) { struct sip_outbound_registration_client_state *client_state = obj; + ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GUAGE, "-1", 1.0); + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GUAGE, "-1", 1.0, + sip_outbound_registration_status_str(client_state->status)); + ast_taskprocessor_unreference(client_state->serializer); } @@ -981,6 +998,10 @@ static struct sip_outbound_registration_state *sip_outbound_registration_state_a state->client_state->timer.user_data = state->client_state; state->client_state->timer.cb = sip_outbound_registration_timer_cb; + ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GUAGE, "+1", 1.0); + ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GUAGE, "+1", 1.0, + sip_outbound_registration_status_str(state->client_state->status)); + state->registration = ao2_bump(registration); return state; } @@ -2013,6 +2034,12 @@ static int load_module(void) ast_manager_register_xml("PJSIPRegister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_register); ast_manager_register_xml("PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_show_outbound_registrations); + /* Clear any previous statsd gauges in case we weren't shutdown cleanly */ + ast_statsd_log("PJSIP.registrations.count", AST_STATSD_GUAGE, 0); + ast_statsd_log("PJSIP.registrations.state.Registered", AST_STATSD_GUAGE, 0); + ast_statsd_log("PJSIP.registrations.state.Unregistered", AST_STATSD_GUAGE, 0); + ast_statsd_log("PJSIP.registrations.state.Rejected", AST_STATSD_GUAGE, 0); + /* Load configuration objects */ ast_sorcery_load_object(ast_sip_get_sorcery(), "registration");