Software /
code /
prosody
Comparison
plugins/mod_admin_shell.lua @ 10887:3debe04a6162
mod_admin_shell: Format stats with util.human.units
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Wed, 03 Jun 2020 19:27:44 +0200 |
parent | 10878:b37dc3776f69 |
child | 10902:5d113332855c |
comparison
equal
deleted
inserted
replaced
10886:994c4a333199 | 10887:3debe04a6162 |
---|---|
33 local has_pposix, pposix = pcall(require, "util.pposix"); | 33 local has_pposix, pposix = pcall(require, "util.pposix"); |
34 local async = require "util.async"; | 34 local async = require "util.async"; |
35 local serialization = require "util.serialization"; | 35 local serialization = require "util.serialization"; |
36 local serialize_config = serialization.new ({ fatal = false, unquoted = true}); | 36 local serialize_config = serialization.new ({ fatal = false, unquoted = true}); |
37 local time = require "util.time"; | 37 local time = require "util.time"; |
38 | |
39 local format_number = require "util.human.units".format; | |
38 | 40 |
39 local commands = module:shared("commands") | 41 local commands = module:shared("commands") |
40 local def_env = module:shared("env"); | 42 local def_env = module:shared("env"); |
41 local default_env_mt = { __index = def_env }; | 43 local default_env_mt = { __index = def_env }; |
42 | 44 |
317 prosody.shutdown(reason); | 319 prosody.shutdown(reason); |
318 return true, "Shutdown initiated"; | 320 return true, "Shutdown initiated"; |
319 end | 321 end |
320 | 322 |
321 local function human(kb) | 323 local function human(kb) |
322 local unit = "K"; | 324 return format_number(kb*1024, "B", "b"); |
323 if kb > 1024 then | |
324 kb, unit = kb/1024, "M"; | |
325 end | |
326 return ("%0.2f%sB"):format(kb, unit); | |
327 end | 325 end |
328 | 326 |
329 function def_env.server:memory() | 327 function def_env.server:memory() |
330 if not has_pposix or not pposix.meminfo then | 328 if not has_pposix or not pposix.meminfo then |
331 return true, "Lua is using "..human(collectgarbage("count")); | 329 return true, "Lua is using "..human(collectgarbage("count")); |
1302 -- COMPAT: debug:timers() was timer:info() for some time in trunk | 1300 -- COMPAT: debug:timers() was timer:info() for some time in trunk |
1303 def_env.timer = { info = def_env.debug.timers }; | 1301 def_env.timer = { info = def_env.debug.timers }; |
1304 | 1302 |
1305 def_env.stats = {}; | 1303 def_env.stats = {}; |
1306 | 1304 |
1307 local function format_stat(type, value, ref_value) | 1305 local short_units = { |
1306 seconds = "s", | |
1307 bytes = "B", | |
1308 }; | |
1309 | |
1310 local function format_stat(type, unit, value, ref_value) | |
1308 ref_value = ref_value or value; | 1311 ref_value = ref_value or value; |
1309 --do return tostring(value) end | 1312 --do return tostring(value) end |
1310 if type == "duration" then | 1313 if not unit then |
1311 if ref_value < 0.001 then | 1314 if type == "duration" then |
1312 return ("%g µs"):format(value*1000000); | 1315 unit = "seconds" |
1313 elseif ref_value < 0.9 then | 1316 elseif type == "size" then |
1314 return ("%0.2f ms"):format(value*1000); | 1317 unit = "bytes"; |
1315 end | 1318 elseif type == "rate" then |
1316 return ("%0.2f"):format(value); | 1319 unit = " events/sec" |
1317 elseif type == "size" then | 1320 if ref_value < 0.9 then |
1318 if ref_value > 1048576 then | 1321 unit = " events/min" |
1319 return ("%d MB"):format(value/1048576); | 1322 value = value*60; |
1320 elseif ref_value > 1024 then | 1323 if ref_value < 0.6/60 then |
1321 return ("%d KB"):format(value/1024); | 1324 unit = " events/h" |
1322 end | 1325 value = value*60; |
1323 return ("%d bytes"):format(value); | 1326 end |
1324 elseif type == "rate" then | 1327 end |
1325 if ref_value < 0.9 then | 1328 end |
1326 return ("%0.2f/min"):format(value*60); | 1329 end |
1327 end | 1330 return format_number(value, short_units[unit] or unit or "", unit == "bytes" and 'b' or nil); |
1328 return ("%0.2f/sec"):format(value); | |
1329 end | |
1330 return tostring(value); | |
1331 end | 1331 end |
1332 | 1332 |
1333 local stats_methods = {}; | 1333 local stats_methods = {}; |
1334 function stats_methods:bounds(_lower, _upper) | 1334 function stats_methods:bounds(_lower, _upper) |
1335 for _, stat_info in ipairs(self) do | 1335 for _, stat_info in ipairs(self) do |
1410 table.insert(stat_info.output, string.format("Count: %d (%d captured)", | 1410 table.insert(stat_info.output, string.format("Count: %d (%d captured)", |
1411 data.count, | 1411 data.count, |
1412 data.sample_count | 1412 data.sample_count |
1413 )); | 1413 )); |
1414 table.insert(stat_info.output, string.format("Min: %s Mean: %s Max: %s", | 1414 table.insert(stat_info.output, string.format("Min: %s Mean: %s Max: %s", |
1415 format_stat(type, data.min), | 1415 format_stat(type, data.units, data.min), |
1416 format_stat(type, value), | 1416 format_stat(type, data.units, value), |
1417 format_stat(type, data.max) | 1417 format_stat(type, data.units, data.max) |
1418 )); | 1418 )); |
1419 table.insert(stat_info.output, string.format("Q1: %s Median: %s Q3: %s", | 1419 table.insert(stat_info.output, string.format("Q1: %s Median: %s Q3: %s", |
1420 format_stat(type, statistics.get_percentile(data, 25)), | 1420 format_stat(type, data.units, statistics.get_percentile(data, 25)), |
1421 format_stat(type, statistics.get_percentile(data, 50)), | 1421 format_stat(type, data.units, statistics.get_percentile(data, 50)), |
1422 format_stat(type, statistics.get_percentile(data, 75)) | 1422 format_stat(type, data.units, statistics.get_percentile(data, 75)) |
1423 )); | 1423 )); |
1424 end | 1424 end |
1425 end | 1425 end |
1426 return self; | 1426 return self; |
1427 end | 1427 end |
1447 for i = 1, graph_width do | 1447 for i = 1, graph_width do |
1448 histogram[i] = math.max(raw_histogram[i*x_scaling-1] or 0, raw_histogram[i*x_scaling] or 0); | 1448 histogram[i] = math.max(raw_histogram[i*x_scaling-1] or 0, raw_histogram[i*x_scaling] or 0); |
1449 end | 1449 end |
1450 | 1450 |
1451 print(""); | 1451 print(""); |
1452 print(("_"):rep(52)..format_stat(type, data.max)); | 1452 print(("_"):rep(52)..format_stat(type, data.units, data.max)); |
1453 for row = graph_height, 1, -1 do | 1453 for row = graph_height, 1, -1 do |
1454 local row_chars = {}; | 1454 local row_chars = {}; |
1455 local min_eighths, max_eighths = 8, 0; | 1455 local min_eighths, max_eighths = 8, 0; |
1456 for i = 1, #histogram do | 1456 for i = 1, #histogram do |
1457 local char_eighths = math.ceil(math.max(math.min((graph_height/(data.max/histogram[i]))-(row-1), 1), 0)*8); | 1457 local char_eighths = math.ceil(math.max(math.min((graph_height/(data.max/histogram[i]))-(row-1), 1), 0)*8); |
1466 else | 1466 else |
1467 local char = eighth_chars:sub(char_eighths*3+1, char_eighths*3+3); | 1467 local char = eighth_chars:sub(char_eighths*3+1, char_eighths*3+3); |
1468 row_chars[i] = char; | 1468 row_chars[i] = char; |
1469 end | 1469 end |
1470 end | 1470 end |
1471 print(table.concat(row_chars).."|-"..format_stat(type, data.max/(graph_height/(row-0.5)))); | 1471 print(table.concat(row_chars).."|-"..format_stat(type, data.units, data.max/(graph_height/(row-0.5)))); |
1472 end | 1472 end |
1473 print(("\\ "):rep(11)); | 1473 print(("\\ "):rep(11)); |
1474 local x_labels = {}; | 1474 local x_labels = {}; |
1475 for i = 1, 11 do | 1475 for i = 1, 11 do |
1476 local s = ("%-4s"):format((i-1)*10); | 1476 local s = ("%-4s"):format((i-1)*10); |
1551 print(table.concat(row_chars).."|-"..math.ceil((max_bin_samples/graph_height)*(row-0.5))); | 1551 print(table.concat(row_chars).."|-"..math.ceil((max_bin_samples/graph_height)*(row-0.5))); |
1552 end | 1552 end |
1553 print(("\\ "):rep(11)); | 1553 print(("\\ "):rep(11)); |
1554 local x_labels = {}; | 1554 local x_labels = {}; |
1555 for i = 1, 11 do | 1555 for i = 1, 11 do |
1556 local s = ("%-4s"):format(format_stat(type, data.min+range*i/11, data.min):match("^%S+")); | 1556 local s = ("%-4s"):format(format_stat(type, data.units, data.min+range*i/11, data.min):match("^%S+")); |
1557 if #s > 4 then | 1557 if #s > 4 then |
1558 s = s:sub(1, 3).."…"; | 1558 s = s:sub(1, 3).."…"; |
1559 end | 1559 end |
1560 x_labels[i] = s; | 1560 x_labels[i] = s; |
1561 end | 1561 end |
1562 print(" "..table.concat(x_labels, " ")); | 1562 print(" "..table.concat(x_labels, " ")); |
1563 local units = format_stat(type, data.min):match("%s+(.+)$") or data.units or ""; | 1563 local units = format_stat(type, data.units, data.min):match("%s+(.+)$") or data.units or ""; |
1564 local margin = math.floor((graph_width-#units)/2); | 1564 local margin = math.floor((graph_width-#units)/2); |
1565 print((" "):rep(margin)..units); | 1565 print((" "):rep(margin)..units); |
1566 else | 1566 else |
1567 print("[range too small to graph]"); | 1567 print("[range too small to graph]"); |
1568 end | 1568 end |
1580 for _, v in ipairs(stat_info.output) do | 1580 for _, v in ipairs(stat_info.output) do |
1581 print(v); | 1581 print(v); |
1582 end | 1582 end |
1583 print(""); | 1583 print(""); |
1584 else | 1584 else |
1585 print(("%-50s %s"):format(stat_info[1], format_stat(stat_info[2], stat_info[3]))); | 1585 print(("%-50s %s"):format(stat_info[1], format_stat(stat_info[2], (stat_info[4] or {}).unit, stat_info[3]))); |
1586 end | 1586 end |
1587 end | 1587 end |
1588 return #stats.." statistics displayed"; | 1588 return #stats.." statistics displayed"; |
1589 end | 1589 end |
1590 | 1590 |