mod_muc_webchat_url: Fix default url
[prosody-modules.git] / mod_statistics_statsman / mod_statistics_statsman.lua
blob65de7ab1f7d068cf4e7a6937a066439aef45c805
1 module:set_global();
3 local statsman = require "core.statsmanager";
4 local time_now = require "util.time".now;
5 local filters = require "util.filters";
6 local serialize = require "util.serialization".serialize;
8 local statistics_interval = module:context("*"):get_option_number("statistics_interval", 60);
9 if module:context("*"):get_option("statistics", "internal") ~= "internal" then
10 module:log("error", "Not using internal statistics, can't do anyting");
11 return;
12 end
14 local sessions = {};
16 local name_map = {
17 ["start_time"] = "up_since";
18 ["cpu.percent:amount"] = "cpu";
19 ["cpu.clock:amount"] = "cpu_total";
20 ["memory.allocated_mmap:amount"] = "memory_allocated_mmap";
21 ["memory.allocated:amount"] = "memory_allocated";
22 ["memory.lua:amount"] = "memory_lua";
23 ["memory.returnable:amount"] = "memory_returnable";
24 ["memory.rss:amount"] = "memory_rss";
25 ["memory.total:amount"] = "memory_total";
26 ["memory.unused:amount"] = "memory_unused";
27 ["memory.used:amount"] = "memory_used";
28 ["/*/mod_c2s/connections:amount"] = "total_c2s";
29 ["/*/mod_s2s/connections:amount"] = "total_s2s";
32 local function push_stat(conn, name, value)
33 local value_str = serialize(value);
34 name = name_map[name] or name;
35 return conn:write((("STAT %q (%s)\n"):format(name, value_str):gsub("\\\n", "\\n")));
36 end
38 local function push_stat_to_all(name, value)
39 for conn in pairs(sessions) do
40 push_stat(conn, name, value);
41 end
42 end
44 local session_stats_tpl = ([[{
45 message_in = %d, message_out = %d;
46 presence_in = %d, presence_out = %d;
47 iq_in = %d, iq_out = %d;
48 bytes_in = %d, bytes_out = %d;
49 }]]):gsub("%s", "");
52 local jid_fields = {
53 c2s = "full_jid";
54 s2sin = "from_host";
55 s2sout = "to_host";
56 component = "host";
59 local function push_session_to_all(session, stats)
60 local id = tostring(session):match("[a-f0-9]+$"); -- FIXME: Better id? :/
61 local stanzas_in, stanzas_out = stats.stanzas_in, stats.stanzas_out;
62 local s = (session_stats_tpl):format(
63 stanzas_in.message, stanzas_out.message,
64 stanzas_in.presence, stanzas_out.presence,
65 stanzas_in.iq, stanzas_out.iq,
66 stats.bytes_in, stats.bytes_out);
67 local jid = session[jid_fields[session.type]] or "";
68 for conn in pairs(sessions) do
69 conn:write(("SESS %q %q %s\n"):format(id, jid, s));
70 end
71 end
73 local active_sessions = {};
75 -- Network listener
76 local listener = {};
78 function listener.onconnect(conn)
79 sessions[conn] = true;
80 push_stat(conn, "version", prosody.version);
81 push_stat(conn, "start_time", prosody.start_time);
82 push_stat(conn, "statistics_interval", statistics_interval);
83 push_stat(conn, "time", time_now());
84 local stats = statsman.get_stats();
85 for name, value in pairs(stats) do
86 push_stat(conn, name, value);
87 end
88 conn:write("\n"); -- Signal end of first batch (for non-streaming clients)
89 end
91 function listener.onincoming(conn, data) -- luacheck: ignore 212
92 -- Discarded
93 end
95 function listener.ondisconnect(conn)
96 sessions[conn] = nil;
97 end
99 function listener.onreadtimeout()
100 return true;
103 local add_statistics_filter; -- forward decl
104 if prosody and prosody.arg then -- ensures we aren't in prosodyctl
105 setmetatable(active_sessions, {
106 __index = function ( t, k )
107 local v = {
108 bytes_in = 0, bytes_out = 0;
109 stanzas_in = {
110 message = 0, presence = 0, iq = 0;
112 stanzas_out = {
113 message = 0, presence = 0, iq = 0;
116 rawset(t, k, v);
117 return v;
120 local function handle_stanza_in(stanza, session)
121 local s = active_sessions[session].stanzas_in;
122 local n = s[stanza.name];
123 if n then
124 s[stanza.name] = n + 1;
126 return stanza;
128 local function handle_stanza_out(stanza, session)
129 local s = active_sessions[session].stanzas_out;
130 local n = s[stanza.name];
131 if n then
132 s[stanza.name] = n + 1;
134 return stanza;
136 local function handle_bytes_in(bytes, session)
137 local s = active_sessions[session];
138 s.bytes_in = s.bytes_in + #bytes;
139 return bytes;
141 local function handle_bytes_out(bytes, session)
142 local s = active_sessions[session];
143 s.bytes_out = s.bytes_out + #bytes;
144 return bytes;
146 function add_statistics_filter(session)
147 filters.add_filter(session, "stanzas/in", handle_stanza_in);
148 filters.add_filter(session, "stanzas/out", handle_stanza_out);
149 filters.add_filter(session, "bytes/in", handle_bytes_in);
150 filters.add_filter(session, "bytes/out", handle_bytes_out);
155 function module.load()
156 if not(prosody and prosody.arg) then
157 return;
159 filters.add_filter_hook(add_statistics_filter);
161 module:add_timer(1, function ()
162 for session, session_stats in pairs(active_sessions) do
163 active_sessions[session] = nil;
164 push_session_to_all(session, session_stats);
166 return 1;
167 end);
169 module:hook("stats-updated", function (event)
170 local stats = event.changed_stats;
171 push_stat_to_all("time", time_now());
172 for name, value in pairs(stats) do
173 push_stat_to_all(name, value);
175 end);
177 module:hook("server-stopping", function ()
178 push_stat_to_all("stop_time", time_now());
179 end);
181 function module.unload()
182 filters.remove_filter_hook(add_statistics_filter);
185 if prosody and prosody.arg then
186 module:provides("net", {
187 default_port = 5782;
188 listener = listener;
189 private = true;