@tanakadigital/js-utils
Version:
Uma biblioteca utilitária com funções de erros, integração com Discord, logs e helpers genéricos.
149 lines (130 loc) • 5.9 kB
JavaScript
import {stringUtils} from "../utils/index.js";
import {discordColors, discordService} from "../discord/index.js";
import {appName, defaultAppProfilerAlertsWebhookUrl} from "../utils/constants.js";
export const profiler = {
requestThresholdMs: 1000, // Definido como uma propriedade fixa do objeto
createProfiler(processName) {
return {
uuid: stringUtils.randomUUID(),
processName,
startTime: new Date(),
steps: [],
methodsCalled: [],
hasSlowSteps: false, // Flag para indicar se algum step foi lento
requestThresholdMs: profiler.requestThresholdMs,
/**
* Inicia um novo passo no profiler.
*/
startStep(stepName, description = "", stepThresholdMs = 50) {
this.steps.push({
stepName,
description,
startTime: new Date(),
endTime: null,
durationMs: null,
stepThresholdMs, // Tempo mínimo antes de notificar
});
},
registerCallMethod(stepName) {
this.methodsCalled.push(stepName);
},
/**
* Finaliza um passo e marca se precisar notificar no finishProcess.
*/
finishStep(stepName) {
const step = this.steps.find(s => s.stepName === stepName && !s.endTime);
if (step) {
step.endTime = new Date();
step.durationMs = step.endTime.getTime() - step.startTime.getTime();
if (step.durationMs > step.stepThresholdMs) {
this.hasSlowSteps = true;
}
}
},
/**
* Obtém o threshold dinâmico com base na soma de todos os steps.
*/
getDynamicThreshold() {
const totalStepThreshold = this.steps.reduce((sum, step) => sum + step.stepThresholdMs, 0);
return Math.max(this.requestThresholdMs, totalStepThreshold);
},
/**
* Finaliza o profiler e verifica se precisa notificar o Discord.
*/
finishProcess() {
this.endTime = new Date();
this.totalDurationMs = this.endTime.getTime() - this.startTime.getTime();
const dynamicThreshold = this.getDynamicThreshold();
if (this.totalDurationMs > dynamicThreshold || this.hasSlowSteps) {
this.notifyDiscord(this.totalDurationMs, null, true)
.catch(error => console.error("Erro ao notificar Discord para requisição:", this.processName, error));
}
},
getReport() {
return {
uuid: this.uuid,
processName: this.processName,
totalDurationMs: this.totalDurationMs,
startTime: this.startTime,
endTime: this.endTime,
steps: this.steps,
methodsCalled: this.methodsCalled
};
},
/**
* Envia uma notificação ao Discord.
*/
async notifyDiscord(timeInMilis, step = null, isRequest = false) {
const traceId = stringUtils.randomUUID();
const title = isRequest
? `⚠️ REQUISIÇÃO LENTA DETECTADA ⚠️`
: `⚠️ PROCESSO LENTO DETECTADO ⚠️`;
let description = `
**App Name:** ${appName}
**Processo:** ${this.processName}
**Duração:** ${timeInMilis}ms ⏳
**TraceId:** ${traceId}
**Data:** ${new Date().toISOString()}
`.trim();
const discordMessageEmbeds = [];
if (isRequest) {
description += `\n**Limite Configurado:** ${this.getDynamicThreshold()}ms`;
this.steps.forEach(s => {
discordMessageEmbeds.push({
title: `Step: ${s.stepName}`,
description: `Duração: ${s.durationMs}ms (Limite: ${s.stepThresholdMs}ms)`,
inline: false
});
});
} else if (step) {
description += `\n**Passo:** ${step.stepName}`;
description += `\n**Limite Configurado:** ${step.stepThresholdMs}ms`;
discordMessageEmbeds.push({
title: `Step: ${step.stepName}`,
description: `Duração: ${step.durationMs}ms (Limite: ${step.stepThresholdMs}ms)`,
inline: false
});
}
let color = discordColors.green;
if (timeInMilis > 2 * this.getDynamicThreshold()) {
color = discordColors.red;
} else if (timeInMilis > this.getDynamicThreshold()) {
color = discordColors.yellow;
}
return discordService.sendDiscord(
title,
description,
discordMessageEmbeds,
[defaultAppProfilerAlertsWebhookUrl],
color
).catch(error => console.error("Erro ao enviar notificação ao Discord:", error));
},
/**
* Método para editar o requestThresholdMs
*/
setRequestThresholdMs(newThresholdMs) {
this.requestThresholdMs = newThresholdMs;
}
};
}
};