Mercurial > prosody-modules
comparison mod_xml_status/mod_xml_status.lua @ 524:ff3ea8735d61
mod_xml_status: initial commit. Expose server status in xml format to be used on external webapps.
author | Marco Cirillo <maranda@lightwitch.org> |
---|---|
date | Fri, 06 Jan 2012 23:15:51 +0000 |
parents | |
children | a9cd75cc9563 |
comparison
equal
deleted
inserted
replaced
523:eff140d53b83 | 524:ff3ea8735d61 |
---|---|
1 -- (C) 2011, Marco Cirillo (LW.Org) | |
2 -- Display server stats in readable XML format | |
3 | |
4 module:set_global() | |
5 | |
6 local ports = module:get_option_array("xml_status_http_ports", {{ port = 5280 }}) | |
7 local show_hosts = module:get_option_array("xml_status_show_hosts", nil) | |
8 local show_comps = module:get_option_array("xml_status_show_comps", nil) | |
9 | |
10 local httpserver = require "net.httpserver" | |
11 | |
12 -- code begin | |
13 | |
14 if not prosody.stanza_counter and not show_hosts and not show_comps then | |
15 module:log ("error", "mod_xml_status requires at least one of the following things:") | |
16 module:log ("error", "mod_stanza_counter loaded, or either xml_status_show_hosts or xml_status_show_comps configuration values set.") | |
17 module:log ("error", "check the module wiki at: http://code.google.com/p/prosody-modules/wiki/mod_xml_status") | |
18 return false | |
19 end | |
20 | |
21 local r_err = "\n<html>\n<head>\n<title>Prosody's XML Status - Error %s</title>\n<meta name=\"robots\" content=\"noindex, nofollow\" />\n</head>\n\n<body>\n<h3>%s</h3>\n</body>\n\n</html>\n" | |
22 | |
23 local response_table = {} | |
24 response_table.header = '<?xml version="1.0" encoding="UTF-8" ?>' | |
25 response_table.doc_header = '<document>' | |
26 response_table.doc_closure = '</document>' | |
27 response_table.stanzas = { | |
28 elem_header = ' <stanzas>', elem_closure = ' </stanzas>', | |
29 incoming = ' <incoming iq="%d" message="%d" presence="%d" />', | |
30 outgoing = ' <outgoing iq="%d" message="%d" presence="%d" />' | |
31 } | |
32 response_table.hosts = { | |
33 elem_header = ' <hosts>', elem_closure = ' </hosts>', | |
34 status = ' <status name="%s" current="%s" />' | |
35 } | |
36 response_table.comps = { | |
37 elem_header = ' <components>', elem_closure = ' </components>', | |
38 status = ' <status name="%s" current="%s" />' | |
39 } | |
40 | |
41 local function forge_response() | |
42 local hosts_s = {}; local components = {}; local stats = {}; local hosts_stats = {}; local comps_stats = {} | |
43 | |
44 -- add headers | |
45 local result = {}; result[#result+1] = response_table.header; result[#result+1] = response_table.doc_header | |
46 | |
47 if show_hosts then for _, name in ipairs(show_hosts) do hosts_s[#hosts_s+1] = name end end | |
48 if show_comps then for _, name in ipairs(show_comps) do components[#components+1] = name end end | |
49 | |
50 -- build stanza stats if there | |
51 if prosody.stanza_counter then | |
52 stats[1] = response_table.stanzas.elem_header | |
53 stats[2] = response_table.stanzas.incoming:format(prosody.stanza_counter.iq["incoming"], | |
54 prosody.stanza_counter.message["incoming"], | |
55 prosody.stanza_counter.presence["incoming"]) | |
56 stats[3] = response_table.stanzas.outgoing:format(prosody.stanza_counter.iq["outgoing"], | |
57 prosody.stanza_counter.message["outgoing"], | |
58 prosody.stanza_counter.presence["outgoing"]) | |
59 stats[4] = response_table.stanzas.elem_closure | |
60 end | |
61 | |
62 -- build hosts stats if there | |
63 if hosts_s[1] then | |
64 hosts_stats[1] = response_table.hosts.elem_header | |
65 for _, name in ipairs(hosts_s) do | |
66 hosts_stats[#hosts_stats+1] = response_table.hosts.status:format( | |
67 name, hosts[name] and "online" or "offline") | |
68 end | |
69 hosts_stats[#hosts_stats+1] = response_table.hosts.elem_closure | |
70 end | |
71 | |
72 -- build components stats if there | |
73 if components[1] then | |
74 comps_stats[1] = response_table.comps.elem_header | |
75 for _, name in ipairs(components) do | |
76 comps_stats[#comps_stats+1] = response_table.comps.status:format( | |
77 name, hosts[name].modules.component and hosts[name].modules.component.connected and "online" or | |
78 hosts[name] and hosts[name].modules.component == nil and "online" or "offline") | |
79 end | |
80 comps_stats[#comps_stats+1] = response_table.comps.elem_closure | |
81 end | |
82 | |
83 -- finish building xml stats document | |
84 for _, bstring in ipairs(stats) do result[#result+1] = bstring end | |
85 for _, bstring in ipairs(hosts_stats) do result[#result+1] = bstring end | |
86 for _, bstring in ipairs(comps_stats) do result[#result+1] = bstring end | |
87 result[#result+1] = response_table.doc_closure | |
88 | |
89 return table.concat(result, "\n") | |
90 end | |
91 | |
92 -- http handlers | |
93 | |
94 local function response(code, r, h) | |
95 local response = { | |
96 status = code; | |
97 body = r; | |
98 } | |
99 | |
100 if h then response.headers = h; end | |
101 return response | |
102 end | |
103 | |
104 local function request(method, body, request) | |
105 if not prosody.stanza_counter then | |
106 local err500 = r_err:format("500", "Internal server error") | |
107 return response(500, err500) end | |
108 if method == "GET" then | |
109 return response(200, forge_response()) | |
110 else | |
111 local err405 = r_err:format("405", "Only GET is supported") | |
112 return response(405, err405, {["Allow"] = "GET"}) | |
113 end | |
114 end | |
115 | |
116 -- initialization. | |
117 -- init http interface | |
118 local function setup() | |
119 httpserver.new_from_config(ports, request, { base = "xml-status" }) | |
120 end | |
121 | |
122 if prosody.start_time then | |
123 setup(); | |
124 else | |
125 module:hook("server-started", setup); | |
126 end |