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