bigbluebutton-Github/bigbluebutton-html5/imports/startup/server/metrics.js
2024-04-26 11:01:50 -03:00

141 lines
4.2 KiB
JavaScript

/* eslint-disable no-prototype-builtins */
import fs from 'fs';
import path from 'path';
import { Meteor } from 'meteor/meteor';
import Logger from './logger';
class Metrics {
constructor() {
this.metrics = {};
}
addEvent(meetingId, eventName, messageLength) {
if (!this.metrics.hasOwnProperty(meetingId)) {
this.metrics[meetingId] = {
currentlyInQueue: {},
wasInQueue: {},
};
}
const { currentlyInQueue } = this.metrics[meetingId];
if (!currentlyInQueue.hasOwnProperty(eventName)) {
currentlyInQueue[eventName] = {
count: 1,
payloadSize: messageLength,
};
} else {
currentlyInQueue[eventName].count += 1;
currentlyInQueue[eventName].payloadSize += messageLength;
}
}
processEvent(meetingId, eventName, size, processingStartTimestamp) {
const currentProcessingTimestamp = Date.now();
const processTime = currentProcessingTimestamp - processingStartTimestamp;
this.addEvent(meetingId, eventName, size);
if (!this.metrics[meetingId].wasInQueue.hasOwnProperty(eventName)) {
this.metrics[meetingId].wasInQueue[eventName] = {
count: 1,
payloadSize: {
min: size,
max: size,
last: size,
total: size,
avg: size,
},
processingTime: {
min: processTime,
max: processTime,
last: processTime,
total: processTime,
avg: processTime,
},
};
this.metrics[meetingId].currentlyInQueue[eventName].count -= 1;
if (!this.metrics[meetingId].currentlyInQueue[eventName].count) {
delete this.metrics[meetingId].currentlyInQueue[eventName];
}
} else {
const { currentlyInQueue, wasInQueue } = this.metrics[meetingId];
currentlyInQueue[eventName].count -= 1;
if (!currentlyInQueue[eventName].count) {
delete currentlyInQueue[eventName];
}
const { payloadSize, processingTime } = wasInQueue[eventName];
wasInQueue[eventName].count += 1;
payloadSize.last = size;
payloadSize.total += size;
if (payloadSize.min > size) payloadSize.min = size;
if (payloadSize.max < size) payloadSize.max = size;
payloadSize.avg = payloadSize.total / wasInQueue[eventName].count;
if (processingTime.min > processTime) processingTime.min = processTime;
if (processingTime.max < processTime) processingTime.max = processTime;
processingTime.last = processTime;
processingTime.total += processTime;
processingTime.avg = processingTime.total / wasInQueue[eventName].count;
}
}
setAnnotationQueueLength(meetingId, size) {
this.metrics[meetingId].annotationQueueLength = size;
}
startDumpFile() {
Meteor.setInterval(() => {
try {
const fileDate = new Date();
const fullYear = fileDate.getFullYear();
const month = (fileDate.getMonth() + 1).toString().padStart(2, '0');
const day = fileDate.getDate().toString().padStart(2, '0');
const hour = fileDate.getHours().toString().padStart(2, '0');
const minutes = fileDate.getMinutes().toString().padStart(2, '0');
const seconds = fileDate.getSeconds().toString().padStart(2, '0');
const folderName = `${fullYear}${month}${day}_${hour}`;
const fileName = `${folderName}${minutes}${seconds}_metrics.json`;
const folderPath = path.join(metricsFolderPath, folderName);
const fullFilePath = path.join(folderPath, fileName);
if (!fs.existsSync(folderPath)) {
Logger.debug(`Creating folder: ${folderPath}`);
fs.mkdirSync(folderPath);
}
fs.writeFileSync(fullFilePath, JSON.stringify(this.metrics));
Logger.info('Metric file successfully written');
} catch (err) {
Logger.error('Error on writing metrics to disk.', err);
}
}, metricsDumpIntervalMs);
}
removeMeeting(meetingId) {
if (removeMeetingOnEnd) {
Logger.info(`Removing meeting ${meetingId} from metrics`);
delete this.metrics[meetingId];
} else {
Logger.info(`Skipping remove of meeting ${meetingId} from metrics`);
}
}
}
const metricsSingleton = new Metrics();
export default metricsSingleton;