add reports to meshctrl
The only format that makes sense to me is CSV, node and mesh ids in the sessions report are just too big for terminal view and JSON is inefficient (too much white-space). The first field (group) derives from the groupby arguement and is "0" when no grouping is applicable (e.g. db reports). resolves #3472, resolves #3509
John Rallis committed
Mar 30, 2023 at 15:07 UTC
f3d93c882fb6405d30d07e934328c69955379cc7
1 file changed
+65
-1
meshctrl.js
+65
-1
@@ -16,7 +16,7 @@ var settings = {};
16
const crypto = require('crypto');
17
const args = require('minimist')(process.argv.slice(2));
18
const path = require('path');
19
-const possibleCommands = ['edituser', 'listusers', 'listusersessions', 'listdevicegroups', 'listdevices', 'listusersofdevicegroup', 'listevents', 'logintokens', 'serverinfo', 'userinfo', 'adduser', 'removeuser', 'adddevicegroup', 'removedevicegroup', 'editdevicegroup', 'broadcast', 'showevents', 'addusertodevicegroup', 'removeuserfromdevicegroup', 'addusertodevice', 'removeuserfromdevice', 'sendinviteemail', 'generateinvitelink', 'config', 'movetodevicegroup', 'deviceinfo', 'removedevice', 'editdevice', 'addusergroup', 'listusergroups', 'removeusergroup', 'runcommand', 'shell', 'upload', 'download', 'deviceopenurl', 'devicemessage', 'devicetoast', 'addtousergroup', 'removefromusergroup', 'removeallusersfromusergroup', 'devicesharing', 'devicepower', 'indexagenterrorlog', 'agentdownload'];
19
+const possibleCommands = ['edituser', 'listusers', 'listusersessions', 'listdevicegroups', 'listdevices', 'listusersofdevicegroup', 'listevents', 'logintokens', 'serverinfo', 'userinfo', 'adduser', 'removeuser', 'adddevicegroup', 'removedevicegroup', 'editdevicegroup', 'broadcast', 'showevents', 'addusertodevicegroup', 'removeuserfromdevicegroup', 'addusertodevice', 'removeuserfromdevice', 'sendinviteemail', 'generateinvitelink', 'config', 'movetodevicegroup', 'deviceinfo', 'removedevice', 'editdevice', 'addusergroup', 'listusergroups', 'removeusergroup', 'runcommand', 'shell', 'upload', 'download', 'deviceopenurl', 'devicemessage', 'devicetoast', 'addtousergroup', 'removefromusergroup', 'removeallusersfromusergroup', 'devicesharing', 'devicepower', 'indexagenterrorlog', 'agentdownload', 'report'];
20
if (args.proxy != null) { try { require('https-proxy-agent'); } catch (ex) { console.log('Missing module "https-proxy-agent", type "npm install https-proxy-agent" to install it.'); return; } }
21
22
if (args['_'].length == 0) {
@@ -69,6 +69,7 @@ if (args['_'].length == 0) {
69
console.log(" DevicePower - Perform wake/sleep/reset/off operations on remote devices.");
70
console.log(" DeviceSharing - View, add and remove sharing links for a given device.");
71
console.log(" AgentDownload - Download an agent of a specific type for a device group.");
72
+ console.log(" Report - Create and show a CSV report.");
73
console.log("\r\nSupported login arguments:");
74
console.log(" --url [wss://server] - Server url, wss://localhost:443 is default.");
75
console.log(" - Use wss://localhost:443?key=xxx if login key is required.");
@@ -275,6 +276,11 @@ if (args['_'].length == 0) {
276
else { ok = true; }
277
break;
278
}
279
+ case 'report': {
280
+ if (args.type == null) { console.log(winRemoveSingleQuotes("Missing report type, use --type '[reporttype]'")); }
281
+ else { ok = true; }
282
+ break;
283
+ }
284
case 'help': {
285
if (args['_'].length < 2) {
286
console.log("Get help on an action. Type:\r\n\r\n help [action]\r\n\r\nPossible actions are: " + possibleCommands.join(', ') + '.');
@@ -961,6 +967,20 @@ if (args['_'].length == 0) {
967
console.log(" --title [title] - Toast title, default is \"MeshCentral\".");
968
break;
969
}
970
+ case 'report': {
971
+ console.log("Generate a CSV report, Example usages:\r\n");
972
+ console.log(" MeshCtrl Report --type sessions --devicegroup mesh//...");
973
+ console.log(" MeshCtrl Report --type traffic --json");
974
+ console.log(" MeshCtrl Report --type logins --groupby day");
975
+ console.log(" MeshCtrl Report --type db");
976
+ console.log("\r\nOptional arguments:\r\n");
977
+ console.log(" --start [yyyy-mm-ddThh:mm:ss] - Filter the results starting at that date. Defaults to last 24h and last week when used with --groupby day. Usable with sessions, traffic and logins");
978
+ console.log(" --end [yyyy-mm-ddThh:mm:ss] - Filter the results ending at that date. Defaults to now. Usable with sessions, traffic and logins");
979
+ console.log(" --groupby [name] - How to group results. Options: user, day, device. Defaults to user. User and day usable in sessions and logins, device usable in sessions.");
980
+ console.log(" --devicegroup [devicegroupid] - Filter the results by device group. Usable in sessions");
981
+ console.log(" --showtraffic - Add traffic data in sessions report");
982
+ break;
983
+ }
984
default: {
985
console.log("Get help on an action. Type:\r\n\r\n help [action]\r\n\r\nPossible actions are: " + possibleCommands.join(', ') + '.');
986
}
@@ -1683,6 +1703,41 @@ function serverConnect() {
1703
ws.send(JSON.stringify({ action: 'toast', nodeids: [args.id], title: args.title ? args.title : "MeshCentral", msg: args.msg, responseid: 'meshctrl' }));
1704
break;
1705
}
1706
+ case 'report': {
1707
+ var reporttype = 1;
1708
+ switch(args.type) {
1709
+ case 'traffic':
1710
+ reporttype = 2;
1711
+ break;
1712
+ case 'logins':
1713
+ reporttype = 3;
1714
+ break;
1715
+ case 'db':
1716
+ reporttype = 4;
1717
+ break;
1718
+ }
1719
+
1720
+ var reportgroupby = 1;
1721
+ if(args.groupby){
1722
+ reportgroupby = args.groupby === 'device' ? 2 : args.groupby === 'day' ? 3: 1;
1723
+ }
1724
+
1725
+ var start = null, end = null;
1726
+ if (args.start) {
1727
+ start = Math.floor(Date.parse(args.start) / 1000);
1728
+ } else {
1729
+ start = reportgroupby === 3 ? Math.round(new Date().getTime() / 1000) - (168 * 3600) : Math.round(new Date().getTime() / 1000) - (24 * 3600);
1730
+ }
1731
+ if (args.end) {
1732
+ end = Math.floor(Date.parse(args.end) / 1000);
1733
+ } else {
1734
+ end = Math.round(new Date().getTime() / 1000);
1735
+ }
1736
+ if (end <= start) { console.log("End time must be ahead of start time."); process.exit(1); return; }
1737
+
1738
+ ws.send(JSON.stringify({ action: 'report', type: reporttype, groupBy: reportgroupby, devGroup: args.devicegroup || null, start, end, tz: Intl.DateTimeFormat().resolvedOptions().timeZone, tf: new Date().getTimezoneOffset(), showTraffic: args.hasOwnProperty('showtraffic'), l: 'en', responseid: 'meshctrl' }));
1739
+ break;
1740
+ }
1741
}
1742
});
1743
@@ -2249,6 +2304,15 @@ function serverConnect() {
2304
console.log(data.data);
2305
process.exit();
2306
}
2307
+ case 'report': {
2308
+ console.log('group,' + data.data.columns.flatMap(c => c.id).join(','));
2309
+ Object.keys(data.data.groups).forEach(gk => {
2310
+ data.data.groups[gk].entries.forEach(e => {
2311
+ console.log(gk + ',' + Object.values(e).join(','));
2312
+ });
2313
+ });
2314
+ process.exit();
2315
+ }
2316
default: { break; }
2317
}
2318
//console.log('Data', data);