Mercurial > prosody-modules
comparison mod_statistics/mod_statistics.lua @ 1072:4dbdb1b465e8
mod_statistics: Initial version, and a rough 'prosodyctl mod_statistics top'
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Sat, 15 Jun 2013 19:08:34 +0100 |
| parents | |
| children | cccd9f6a628d |
comparison
equal
deleted
inserted
replaced
| 1071:8f59b45fe6a7 | 1072:4dbdb1b465e8 |
|---|---|
| 1 module:set_global(); | |
| 2 | |
| 3 local stats = module:require("mod_statistics/stats"); | |
| 4 local filters = require "util.filters"; | |
| 5 local serialize = require "util.serialization".serialize; | |
| 6 | |
| 7 local cached_values = {}; | |
| 8 | |
| 9 local sessions = {}; | |
| 10 | |
| 11 local function push_stat(conn, name, value) | |
| 12 local value_str = serialize(value); | |
| 13 return conn:write((("STAT %q (%s)\n"):format(name, value_str):gsub("\\\n", "\\n"))); | |
| 14 end | |
| 15 | |
| 16 local function push_stat_to_all(name, value) | |
| 17 for conn in pairs(sessions) do | |
| 18 push_stat(conn, name, value); | |
| 19 end | |
| 20 end | |
| 21 | |
| 22 local session_stats_tpl = ([[{ | |
| 23 message_in = %d, message_out = %d; | |
| 24 presence_in = %d, presence_out = %d; | |
| 25 iq_in = %d, iq_out = %d; | |
| 26 bytes_in = %d, bytes_out = %d; | |
| 27 }]]):gsub("%s", ""); | |
| 28 | |
| 29 | |
| 30 local jid_fields = { | |
| 31 c2s = "full_jid"; | |
| 32 s2sin = "from_host"; | |
| 33 s2sout = "to_host"; | |
| 34 component = "host"; | |
| 35 }; | |
| 36 | |
| 37 local function push_session_to_all(session, stats) | |
| 38 local id = tostring(session):match("[a-f0-9]+$"); -- FIXME: Better id? :/ | |
| 39 local stanzas_in, stanzas_out = stats.stanzas_in, stats.stanzas_out; | |
| 40 local s = (session_stats_tpl):format( | |
| 41 stanzas_in.message, stanzas_out.message, | |
| 42 stanzas_in.presence, stanzas_out.presence, | |
| 43 stanzas_in.iq, stanzas_out.iq, | |
| 44 stats.bytes_in, stats.bytes_out); | |
| 45 local jid = session[jid_fields[session.type]] or ""; | |
| 46 for conn in pairs(sessions) do | |
| 47 return conn:write(("SESS %q %q %s\n"):format(id, jid, s)); | |
| 48 end | |
| 49 end | |
| 50 | |
| 51 local available_stats = stats.stats; | |
| 52 local active_sessions = stats.active_sessions; | |
| 53 | |
| 54 -- Handle statistics provided by other modules | |
| 55 local function item_handlers(host) | |
| 56 host = host and (host.."/") or ""; | |
| 57 | |
| 58 return function (event) -- Added | |
| 59 local stats = event.item.statistics; | |
| 60 local group = host..(stats.name and (stats.name.."::") or ""); | |
| 61 for name, stat in pairs(stats) do | |
| 62 available_stats[group..name] = stat; | |
| 63 end | |
| 64 end, function (event) -- Removed | |
| 65 local stats = event.item.statistics; | |
| 66 local group = host..(stats.name and (stats.name.."::") or ""); | |
| 67 for name, stat in pairs(stats) do | |
| 68 available_stats[group..name] = nil; | |
| 69 end | |
| 70 end; | |
| 71 end | |
| 72 | |
| 73 module:handle_items("statistics-provider", item_handlers()); | |
| 74 function module.add_host(module) | |
| 75 module:handle_items("statistics-provider", item_handlers(module.host)); | |
| 76 end | |
| 77 | |
| 78 -- Network listener | |
| 79 local listener = {}; | |
| 80 | |
| 81 function listener.onconnect(conn) | |
| 82 sessions[conn] = {}; | |
| 83 push_stat(conn, "version", prosody.version); | |
| 84 for name, value in pairs(cached_values) do | |
| 85 push_stat(conn, name, value); | |
| 86 end | |
| 87 conn:write("\n"); -- Signal end of first batch (for non-streaming clients) | |
| 88 end | |
| 89 | |
| 90 function listener.onincoming(conn, data) | |
| 91 end | |
| 92 | |
| 93 function listener.ondisconnect(conn) | |
| 94 sessions[conn] = nil; | |
| 95 end | |
| 96 | |
| 97 function module.load() | |
| 98 if not(prosody and prosody.full_sessions) then return; end --FIXME: hack, need a proper flag | |
| 99 filters.add_filter_hook(stats.filter_hook); | |
| 100 | |
| 101 module:add_timer(1, function () | |
| 102 for stat_name, stat in pairs(available_stats) do | |
| 103 if stat.get then | |
| 104 local cached = cached_values[stat_name]; | |
| 105 local new_value = stat.get(); | |
| 106 if new_value ~= cached then | |
| 107 push_stat_to_all(stat_name, new_value); | |
| 108 cached_values[stat_name] = new_value; | |
| 109 end | |
| 110 end | |
| 111 end | |
| 112 for session, session_stats in pairs(active_sessions) do | |
| 113 active_sessions[session] = nil; | |
| 114 push_session_to_all(session, session_stats); | |
| 115 end | |
| 116 return 1; | |
| 117 end); | |
| 118 module:provides("net", { | |
| 119 default_port = 5782; | |
| 120 listener = listener; | |
| 121 }); | |
| 122 end | |
| 123 function module.unload() | |
| 124 filters.remove_filter_hook(stats.filter_hook); | |
| 125 end | |
| 126 function module.command( args ) | |
| 127 local command = args[1]; | |
| 128 if command == "top" then | |
| 129 local dir = module:get_directory(); | |
| 130 package.path = dir.."/?.lua;"..dir.."/?.lib.lua;"..package.path; | |
| 131 local prosodytop = require "prosodytop"; | |
| 132 prosodytop.run(); | |
| 133 end | |
| 134 end |
