res_resolver_unbound: Fix config documentation.
[asterisk/asterisk.git] / res / res_endpoint_stats.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2015, Digium, Inc.
5  *
6  * Matthew Jordan <mjordan@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \brief Statsd Endpoint stats.
21  *
22  * This module subscribes to Stasis endpoints and send statistics
23  * based on their state.
24  *
25  * \author Matthew Jordan <mjordan@digium.com>
26  * \since 13.7.0
27  */
28
29 /*** MODULEINFO
30         <depend>res_statsd</depend>
31         <defaultenabled>no</defaultenabled>
32         <support_level>extended</support_level>
33  ***/
34
35 #include "asterisk.h"
36
37 ASTERISK_REGISTER_FILE()
38
39 #include "asterisk/module.h"
40 #include "asterisk/stasis_endpoints.h"
41 #include "asterisk/stasis_message_router.h"
42 #include "asterisk/statsd.h"
43
44 /*! Stasis message router */
45 static struct stasis_message_router *router;
46
47 static void update_endpoint_state(struct ast_endpoint_snapshot *snapshot, const char *delta)
48 {
49         switch (snapshot->state) {
50         case AST_ENDPOINT_UNKNOWN:
51                 ast_statsd_log_string("endpoints.state.unknown", AST_STATSD_GAUGE, delta, 1.0);
52                 break;
53         case AST_ENDPOINT_OFFLINE:
54                 ast_statsd_log_string("endpoints.state.offline", AST_STATSD_GAUGE, delta, 1.0);
55                 break;
56         case AST_ENDPOINT_ONLINE:
57                 ast_statsd_log_string("endpoints.state.online", AST_STATSD_GAUGE, delta, 1.0);
58                 break;
59         }
60 }
61
62 static void handle_endpoint_update(struct ast_endpoint_snapshot *old_snapshot, struct ast_endpoint_snapshot *new_snapshot)
63 {
64         if (!old_snapshot && new_snapshot) {
65                 ast_statsd_log_string("endpoints.count", AST_STATSD_GAUGE, "+1", 1.0);
66                 update_endpoint_state(new_snapshot, "+1");
67         } else if (old_snapshot && !new_snapshot) {
68                 ast_statsd_log_string("endpoints.count", AST_STATSD_GAUGE, "-1", 1.0);
69                 update_endpoint_state(old_snapshot, "-1");
70         } else {
71                 if (old_snapshot->state != new_snapshot->state) {
72                         update_endpoint_state(old_snapshot, "-1");
73                         update_endpoint_state(new_snapshot, "+1");
74                 }
75                 ast_statsd_log_full_va("endpoints.%s.%s.channels", AST_STATSD_GAUGE, new_snapshot->num_channels, 1.0,
76                         new_snapshot->tech, new_snapshot->resource);
77         }
78 }
79
80 static void cache_update_cb(void *data, struct stasis_subscription *sub,
81         struct stasis_message *message)
82 {
83         struct stasis_cache_update *update = stasis_message_data(message);
84         struct ast_endpoint_snapshot *old_snapshot;
85         struct ast_endpoint_snapshot *new_snapshot;
86
87         if (ast_endpoint_snapshot_type() != update->type) {
88                 return;
89         }
90
91         old_snapshot = stasis_message_data(update->old_snapshot);
92         new_snapshot = stasis_message_data(update->new_snapshot);
93
94         handle_endpoint_update(old_snapshot, new_snapshot);
95 }
96
97 static int dump_cache_load(void *obj, void *arg, int flags)
98 {
99         struct stasis_message *msg = obj;
100         struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
101
102         handle_endpoint_update(NULL, snapshot);
103
104         return 0;
105 }
106
107 static int dump_cache_unload(void *obj, void *arg, int flags)
108 {
109         struct stasis_message *msg = obj;
110         struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
111
112         handle_endpoint_update(snapshot, NULL);
113
114         return 0;
115 }
116
117 static int load_module(void)
118 {
119         struct ao2_container *endpoints;
120
121         router = stasis_message_router_create(ast_endpoint_topic_all_cached());
122         if (!router) {
123                 return AST_MODULE_LOAD_FAILURE;
124         }
125         stasis_message_router_add(router, stasis_cache_update_type(), cache_update_cb, NULL);
126
127         endpoints = stasis_cache_dump(ast_endpoint_cache(), ast_endpoint_snapshot_type());
128         if (endpoints) {
129                 ao2_callback(endpoints, OBJ_MULTIPLE | OBJ_NODATA | OBJ_NOLOCK, dump_cache_load, NULL);
130                 ao2_ref(endpoints, -1);
131         }
132
133         return AST_MODULE_LOAD_SUCCESS;
134 }
135
136 static int unload_module(void)
137 {
138         struct ao2_container *endpoints;
139
140         endpoints = stasis_cache_dump(ast_endpoint_cache(), ast_endpoint_snapshot_type());
141         if (endpoints) {
142                 ao2_callback(endpoints, OBJ_MULTIPLE | OBJ_NODATA | OBJ_NOLOCK, dump_cache_unload, NULL);
143                 ao2_ref(endpoints, -1);
144         }
145
146         stasis_message_router_unsubscribe_and_join(router);
147         router = NULL;
148
149         return 0;
150 }
151
152 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Endpoint statistics",
153         .support_level = AST_MODULE_SUPPORT_EXTENDED,
154         .load = load_module,
155         .unload = unload_module,
156         .nonoptreq = "res_statsd"
157         );