Last caller information / MCI

This commit is contained in:
Bryan Ashby 2020-11-26 19:51:00 -07:00
parent 3a7f7750ab
commit 9c7fb16196
No known key found for this signature in database
GPG Key ID: B49EB437951D2542
6 changed files with 120 additions and 25 deletions

View File

@ -236,6 +236,8 @@ function initialize(cb) {
//
const User = require('./user.js');
// :TODO: use User.getUserInfo() for this!
const propLoadOpts = {
names : [
UserProps.RealName, UserProps.Sex, UserProps.EmailAddress,
@ -246,7 +248,7 @@ function initialize(cb) {
async.waterfall(
[
function getOpUserName(next) {
return User.getUserName(1, next);
return User.getUserName(User.RootUserID, next);
},
function getOpProps(opUserName, next) {
User.loadProperties(User.RootUserID, propLoadOpts, (err, opProps) => {
@ -273,8 +275,9 @@ function initialize(cb) {
}
);
},
function initCallsToday(callback) {
function initSystemLogStats(callback) {
const StatLog = require('./stat_log.js');
const filter = {
logName : SysLogKeys.UserLoginHistory,
resultType : 'count',
@ -288,7 +291,7 @@ function initialize(cb) {
return callback(null);
});
},
function initUserTransferStats(callback) {
function initUserLogStats(callback) {
const StatLog = require('./stat_log');
const entries = [
@ -324,6 +327,33 @@ function initialize(cb) {
return callback(null);
});
},
function initLastLogin(callback) {
const StatLog = require('./stat_log');
StatLog.getSystemLogEntries(SysLogKeys.UserLoginHistory, 'timestamp_desc', 1, (err, lastLogin) => {
if (err) {
return callback(null);
}
let loginObj;
try
{
loginObj = JSON.parse(lastLogin[0].log_value);
loginObj.timestamp = moment(lastLogin[0].timestamp);
}
catch (e)
{
return callback(null);
}
// For live stats we want to resolve user ID -> name, etc.
const User = require('./user');
User.getUserInfo(loginObj.userId, (err, props) => {
const stat = Object.assign({}, props, loginObj);
StatLog.setNonPersistentSystemStat(SysProps.LastLogin, stat);
return callback(null);
});
});
},
function initMessageStats(callback) {
return require('./message_area.js').startup(callback);
},

View File

@ -98,7 +98,6 @@ const PREDEFINED_MCI_GENERATORS = {
SA : function opAffils() { return StatLog.getSystemStat(SysProps.SysOpAffiliations); },
SS : function opSex() { return StatLog.getSystemStat(SysProps.SysOpSex); },
SE : function opEmail() { return StatLog.getSystemStat(SysProps.SysOpEmailAddress); },
// :TODO: op age, web, ?????
//
// Current user / session
@ -243,10 +242,6 @@ const PREDEFINED_MCI_GENERATORS = {
UU : function systemUptime() {
return moment.duration(process.uptime(), 'seconds').humanize();
},
// :TODO: MCI for core count, e.g. os.cpus().length
// :TODO: cpu load average (over N seconds): http://stackoverflow.com/questions/9565912/convert-the-output-of-os-cpus-in-node-js-to-percentage
NV : function nodeVersion() { return process.version; },
AN : function activeNodes() { return clientConnections.getActiveConnections().length.toString(); },
@ -265,8 +260,6 @@ const PREDEFINED_MCI_GENERATORS = {
//
// System File Base, Up/Download Info
//
// :TODO: DD - Today's # of downloads (iNiQUiTY)
//
SD : function systemNumDownloads() { return StatLog.getFriendlySystemStat(SysProps.FileDlTotalCount, 0); },
SO : function systemByteDownload() {
const byteSize = StatLog.getSystemStatNum(SysProps.FileDlTotalBytes);
@ -308,10 +301,27 @@ const PREDEFINED_MCI_GENERATORS = {
},
// :TODO: NT - New users today (Obv/2)
// :TODO: LC - name of last caller to system (Obv/2)
// :TODO: TZ - Average *system* post/call ratio (iNiQUiTY)
// :TODO: ?? - Total users on system
LC : function lastCallerUserName() { // Obv/2
const lastLogin = StatLog.getSystemStat(SysProps.LastLogin) || {};
return lastLogin.userName || 'N/A';
},
LD : function lastCallerDate(client) {
const lastLogin = StatLog.getSystemStat(SysProps.LastLogin) || {};
if (!lastLogin.timestamp) {
return 'N/A';
}
return lastLogin.timestamp.format(client.currentTheme.helpers.getDateFormat());
},
LT : function lastCallerTime(client) {
const lastLogin = StatLog.getSystemStat(SysProps.LastLogin) || {};
if (!lastLogin.timestamp) {
return 'N/A';
}
return lastLogin.timestamp.format(client.currentTheme.helpers.getTimeFormat());
},
//
// Special handling for XY

View File

@ -10,6 +10,7 @@
module.exports = {
LoginCount : 'login_count',
LoginsToday : 'logins_today', // non-persistent
LastLogin : 'last_login', // object { userId, sessionId, userName, userRealName, timestamp }; non-persistent
FileBaseAreaStats : 'file_base_area_stats', // object - see file_base_area.js::getAreaStats
FileUlTotalCount : 'ul_total_count',
@ -25,19 +26,15 @@ module.exports = {
MessageTotalCount : 'message_post_total_count', // total non-private messages on the system; non-persistent
MessagesToday : 'message_post_today', // non-private messages posted/imported today; non-persistent
// begin +op non-persistent...
SysOpUsername : 'sysop_username',
SysOpRealName : 'sysop_real_name',
SysOpLocation : 'sysop_location',
SysOpAffiliations : 'sysop_affiliation',
SysOpSex : 'sysop_sex',
SysOpEmailAddress : 'sysop_email_address',
// end +op non-persistent
SysOpUsername : 'sysop_username', // non-persistent
SysOpRealName : 'sysop_real_name', // non-persistent
SysOpLocation : 'sysop_location', // non-persistent
SysOpAffiliations : 'sysop_affiliation', // non-persistent
SysOpSex : 'sysop_sex', // non-persistent
SysOpEmailAddress : 'sysop_email_address', // non-persistent
NextRandomRumor : 'random_rumor',
// begin system stat non-persistent...
SystemMemoryStats : 'system_memory_stats', // object { totalBytes, freeBytes }
SystemLoadStats : 'system_load_stats', // object { average, current }
// end system stat non persistent
SystemMemoryStats : 'system_memory_stats', // object { totalBytes, freeBytes }; non-persistent
SystemLoadStats : 'system_load_stats', // object { average, current }; non-persistent
};

View File

@ -630,6 +630,41 @@ module.exports = class User {
);
}
static getUserInfo(userId, propsList, cb) {
if (!cb && _.isFunction(propsList)) {
cb = propsList;
propsList = [
UserProps.RealName, UserProps.Sex, UserProps.EmailAddress,
UserProps.Location, UserProps.Affiliations,
];
}
async.waterfall(
[
(callback) => {
return User.getUserName(userId, callback);
},
(userName, callback) => {
User.loadProperties(userId, { names : propsList }, (err, props) => {
return callback(err, Object.assign({}, props, { user_name : userName }));
});
}
],
(err, userProps) => {
if (err) {
return cb(err);
}
const userInfo = {};
Object.keys(userProps).forEach(key => {
userInfo[_.camelCase(key)] = userProps[key] || 'N/A';
});
return cb(null, userInfo);
}
);
}
static isRootUserId(userId) {
return (User.RootUserID === userId);
}

View File

@ -30,6 +30,7 @@ const {
const async = require('async');
const _ = require('lodash');
const assert = require('assert');
const moment = require('moment');
exports.userLogin = userLogin;
exports.recordLogin = recordLogin;
@ -176,6 +177,8 @@ function recordLogin(client, cb) {
assert(client.user.authenticated); // don't get in situations where this isn't true
const user = client.user;
const loginTimestamp = StatLog.now;
async.parallel(
[
(callback) => {
@ -183,7 +186,7 @@ function recordLogin(client, cb) {
return StatLog.incrementSystemStat(SysProps.LoginCount, 1, callback);
},
(callback) => {
return StatLog.setUserStat(user, UserProps.LastLoginTs, StatLog.now, callback);
return StatLog.setUserStat(user, UserProps.LastLoginTs, loginTimestamp, callback);
},
(callback) => {
return StatLog.incrementUserStat(user, UserProps.LoginCount, 1, callback);
@ -202,6 +205,24 @@ function recordLogin(client, cb) {
StatLog.KeepType.Max,
callback
);
},
(callback) => {
// Update live last login information which includes additional
// (pre-resolved) information such as user name/etc.
const lastLogin = {
userId : user.userId,
sessionId : user.sessionId,
userName : user.username,
realName : user.getProperty(UserProps.RealName),
affiliation : user.getProperty(UserProps.Affiliations),
emailAddress : user.getProperty(UserProps.EmailAddress),
sex : user.getProperty(UserProps.Sex),
location : user.getProperty(UserProps.Location),
timestamp : moment(loginTimestamp),
};
StatLog.setNonPersistentSystemStat(SysProps.LastLogin, lastLogin);
return callback(null);
}
],
err => {

View File

@ -100,7 +100,9 @@ There are many predefined MCI codes that can be used anywhere on the system (pla
| `LA` | System load average (e.g. 0.25)<br>(Not available for all platforms) |
| `CL` | System current load percentage<br>(Not available for all platforms) |
| `UU` | System uptime in friendly format |
| `LC` | Last caller to the system (username) |
| `LT` | Time of last caller |
| `LD` | Date of last caller |
Some additional special case codes also exist: