UNPKG

performance-monitor-logger

Version:
915 lines (905 loc) 40.9 kB
import { Component, NgModule, ɵɵdefineInjectable, Injectable } from '@angular/core'; import { HttpResponse } from '@angular/common/http'; import { tap } from 'rxjs/operators'; import { __awaiter } from 'tslib'; class PerformanceMonitorComponent { constructor() { } ngOnInit() { } } PerformanceMonitorComponent.decorators = [ { type: Component, args: [{ selector: 'lib-performanceMonitorLogger', template: ` <p>performance-monitor-logger works!</p> ` },] } ]; PerformanceMonitorComponent.ctorParameters = () => []; // performance-monitor.module.ts class PerformanceMonitorModule { } PerformanceMonitorModule.decorators = [ { type: NgModule, args: [{ declarations: [PerformanceMonitorComponent], imports: [], exports: [PerformanceMonitorComponent], },] } ]; class PerformanceMonitorService { constructor() { } } PerformanceMonitorService.ɵprov = ɵɵdefineInjectable({ factory: function PerformanceMonitorService_Factory() { return new PerformanceMonitorService(); }, token: PerformanceMonitorService, providedIn: "root" }); PerformanceMonitorService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; PerformanceMonitorService.ctorParameters = () => []; /** * 📊 SISTEMA DE LOGS DE PERFORMANCE * * Sistema completo de monitoramento de performance para aplicações Angular * com feedback visual através de emojis e relatórios automáticos. * * Características: * - 📈 Monitoramento em Tempo Real * - 🟢🟡🔴 Classificação Visual por Performance * - ⏰ Relatórios Automáticos após Inatividade * - 📊 Análise Detalhada com Recomendações * - 🛠️ API Pública para Controle Manual * * @author Pedro Henrique dos Santos Leuchs * @version 1.0.19 * @since 2025-07-11 */ class LogsPerformatico { // 🆕 Adiciona requests para registrar requisições HTTP constructor(serviceName = 'Service') { this.monitoramentoAtivo = true; // Começa ativo na primeira vez // 📊 Propriedades do Sistema this.performanceTimers = new Map(); this.performanceSummary = new Map(); this.httpRequests = new Map(); // 🆕 Stack para contexto de função monitorada this.functionContextStack = []; this.serviceName = serviceName; } /** * Registra requisição HTTP associando à função monitorada ativa (se houver) * @param payload Dados da requisição */ registerHttpRequest(authReq, tempo, error = false) { var _a, _b; const nome = ((_a = authReq.body) === null || _a === void 0 ? void 0 : _a.name) || this.extrairNomeDeSQL((_b = authReq.body) === null || _b === void 0 ? void 0 : _b.sqlInstruction) || '(desconhecido)'; const atual = this.httpRequests.get(nome) || { tempoTotal: 0, execucoes: 0, errors: 0, }; atual.tempoTotal += tempo; atual.execucoes += 1; if (error) atual.errors += 1; this.httpRequests.set(nome, atual); } // Função auxiliar para extrair nome da função de um SQL, ex: PACK_PARMGEN.CONSULTA_PARAMETRO(...) extrairNomeDeSQL(sql) { if (!sql) return null; const match = sql.match(/([A-Z0-9_]+\.[A-Z0-9_]+)/i); return match ? match[1] : null; } /** * 🚀 Mensagem de boas-vindas do sistema */ showWelcomeMessage() { console.log(`%cSISTEMA DE MONITORAMENTO DE PERFORMANCE`, 'color: #bbc7c8ff; font-size: 18px; font-weight: bold; text-shadow: 1px 1px #000; background-color: #43248bff; border-radius: 5px; padding: 10px 20px;'); } /** * ⏱️ Inicia cronômetro para uma operação * @param operationName Nome da operação a ser monitorada */ startTimer(operationName) { if (!this.monitoramentoAtivo) return; // Se for a primeira operação, abre borda visual if (this.performanceTimers.size === 0 && this.performanceSummary.size === 0) { const border = '═'.repeat(56); console.log(`%cINÍCIO DO MONITORAMENTO DE PERFORMANCE`, 'color: #bbc7c8ff; font-size: 18px; font-weight: bold; text-shadow: 1px 1px #000; background-color: #43248bff; border-radius: 5px; padding: 10px 20px;'); } this.performanceTimers.set(operationName, Date.now()); // Empilha contexto de função monitorada this.functionContextStack.push(operationName); console.log(`║ [INÍCIO] ${operationName} - ${new Date().toLocaleTimeString()}`); } /** * 🏁 Finaliza cronômetro e exibe resultado com emoji * @param operationName Nome da operação * @param customMessage Mensagem customizada opcional (ex: para erros) * @param customThresholds Thresholds customizados para esta operação específica */ endTimer(operationName, customMessage, customThresholds) { var _a, _b; if (!this.monitoramentoAtivo) return; const startTime = this.performanceTimers.get(operationName); if (!startTime) { console.warn(`⚠️ Timer não encontrado para: ${operationName}`); return; } const elapsedTime = Date.now() - startTime; this.performanceTimers.delete(operationName); // Desempilha contexto de função monitorada if (this.functionContextStack[this.functionContextStack.length - 1] === operationName) { this.functionContextStack.pop(); } // Determina status baseado no tempo (com thresholds customizados se fornecidos ou dinâmicos) const { emoji, status, color } = this.getPerformanceStatus(elapsedTime, customThresholds, operationName); // Log com emoji e cor (com mensagem customizada se fornecida) const message = customMessage ? `${operationName} - ${customMessage}` : `${operationName}`; const fixedStatus = `[${status}]`.padEnd(5); // Ex: '[OK] ' const fixedMessage = message.padEnd(10); // Nome da função const fixedTime = elapsedTime.toString().padStart(5); // 5 para " 16ms", "2193ms" console.log(`║ %c${emoji} ${fixedStatus} ${fixedMessage} - ${fixedTime}ms `, color); // Mostra thresholds customizados se estiverem sendo usados if (customThresholds && (customThresholds.ok || customThresholds.lento || customThresholds.critico)) { console.log(`⚙️ Thresholds customizados: OK<${(_a = customThresholds.ok) !== null && _a !== void 0 ? _a : 500}ms, LENTO<${(_b = customThresholds.lento) !== null && _b !== void 0 ? _b : 2000}ms`); } // Atualiza sumário (com thresholds customizados se fornecidos) this.updatePerformanceSummary(operationName, elapsedTime, customThresholds); } /** * 🎨 Determina status de performance baseado no tempo * @param elapsedTime Tempo decorrido em milissegundos * @param customThresholds Thresholds customizados para esta operação específica * @param operationName Nome da operação (para calcular thresholds dinâmicos) * @returns Objeto com emoji, status e cor */ getPerformanceStatus(elapsedTime, customThresholds, operationName) { var _a, _b, _c; let okThreshold; let lentoThreshold; let criticoThreshold; if (customThresholds && (customThresholds.ok || customThresholds.lento || customThresholds.critico)) { // Usa thresholds customizados se fornecidos okThreshold = (_a = customThresholds.ok) !== null && _a !== void 0 ? _a : 500; lentoThreshold = (_b = customThresholds.lento) !== null && _b !== void 0 ? _b : 2000; criticoThreshold = (_c = customThresholds.critico) !== null && _c !== void 0 ? _c : Number.MAX_SAFE_INTEGER; } else if (operationName) { // Calcula thresholds dinâmicos baseados na quantidade de execuções const stats = this.performanceSummary.get(operationName); // Corrige: soma +1 para considerar a execução atual const executionCount = stats ? stats.count + 1 : 1; const dynamicThresholds = this.calculateDynamicThresholds(executionCount); okThreshold = dynamicThresholds.ok; lentoThreshold = dynamicThresholds.lento; criticoThreshold = dynamicThresholds.critico; } else { // Usa thresholds padrões okThreshold = 500; lentoThreshold = 2000; criticoThreshold = Number.MAX_SAFE_INTEGER; } if (elapsedTime < okThreshold) { return { emoji: '🟢', status: 'OK', color: 'color: green; font-weight: bold;', }; } else if (elapsedTime < lentoThreshold) { return { emoji: '🟡', status: 'LENTO', color: 'color: orange; font-weight: bold;', }; } else { return { emoji: '🔴', status: 'CRÍTICO', color: 'color: red; font-weight: bold;', }; } } /** * 📈 Atualiza estatísticas de performance para o sumário * @param operationName Nome da operação * @param elapsedTime Tempo decorrido em milissegundos * @param customThresholds Thresholds customizados para armazenar (opcional) */ updatePerformanceSummary(operationName, elapsedTime, customThresholds) { const existing = this.performanceSummary.get(operationName); if (existing) { existing.count++; existing.totalTime += elapsedTime; existing.minTime = Math.min(existing.minTime, elapsedTime); existing.maxTime = Math.max(existing.maxTime, elapsedTime); // Atualiza thresholds customizados se fornecidos if (customThresholds && (customThresholds.ok || customThresholds.lento || customThresholds.critico)) { existing.customThresholds = customThresholds; } } else { this.performanceSummary.set(operationName, { count: 1, totalTime: elapsedTime, minTime: elapsedTime, maxTime: elapsedTime, customThresholds: customThresholds, }); } // Não faz mais nada aqui, relatório só manual } /** * 📊 Exibe relatório resumido de todas as operações (compactado) */ showPerformanceSummary(showFullDetails = false) { // Fecha borda do monitoramento ao gerar relatório console.log('%c RELATÓRIO DE PERFORMANCE', 'color: #bbc7c8ff; font-size: 18px; font-weight: bold; text-shadow: 1px 1px #000; background-color: #43248bff; border-radius: 5px; padding: 10px 20px;'); if (this.performanceSummary.size === 0) { console.log('%c Nenhuma operação monitorada ainda.', 'color: gray; font-style: italic;'); return; } const sortedEntries = Array.from(this.performanceSummary.entries()).sort((a, b) => b[1].maxTime - a[1].maxTime); const table = Object.fromEntries(sortedEntries.map(([operation, stats]) => { const avgTime = Math.round(stats.totalTime / stats.count); const { emoji, status } = this.getPerformanceStatus(avgTime, stats.customThresholds, operation); return [ operation, { Execuções: stats.count, Média: `${avgTime}ms (${status}) ${emoji}`.trim(), Mínimo: `${stats.minTime}ms`, Máximo: `${stats.maxTime}ms`, Total: `${stats.totalTime}ms`, }, ]; })); console.table(table); // Removido: agora a análise detalhada é chamada apenas pelo botão } /** * 📑 Exibe relatório detalhado de requisições HTTP agrupadas por função */ showHttpRequestsReport() { console.log(`%cRELATÓRIO DETALHADO DE REQUISIÇÕES HTTP`, 'color: #bbc7c8ff; font-size: 18px; font-weight: bold; text-shadow: 1px 1px #000; background-color: #43248bff; border-radius: 5px; padding: 10px 20px;'); if (this.httpRequests.size === 0) { console.log('Nenhuma requisição HTTP registrada.'); return; } const tabela = Object.fromEntries(Array.from(this.httpRequests.entries()) .sort((a, b) => b[1].tempoTotal - a[1].tempoTotal) .map(([nome, dados]) => [ nome, { Execuções: dados.execucoes, Média: `${Math.round(dados.tempoTotal / dados.execucoes)}ms`, 'Tempo Total': `${Math.round(dados.tempoTotal)}ms`, Erros: dados.errors, }, ])); console.table(tabela); } /** * 🔍 Gera análise detalhada de performance */ generateDetailedAnalysis() { // Título discreto console.log('%cANÁLISE DETALHADA DE PERFORMANCE', 'color: #bbc7c8ff; font-size: 18px; font-weight: bold; text-shadow: 1px 1px #000; background-color: #43248bff; border-radius: 5px; padding: 10px 20px;'); console.log(''); if (this.performanceSummary.size === 0) { console.log('%cNenhuma operação registrada para análise.', 'color: #bbb; font-style: italic; font-size: 14px; padding: 4px 0 4px 10px;'); return; } const { criticalOperations, slowOperations, fastOperations } = this.categorizeOperations(); // Helper para bloco discreto com texto claro const printBlock = (color, emoji, operation, avg, extra) => { const style = `border-left: 4px solid ${color}; padding: 2px 0 2px 10px; margin: 2px 0 2px 0; font-size: 14px; color: #fff; background: none; font-weight: normal;`; console.log(`%c${emoji} ${operation} - ${avg}ms (média) ${extra}`.trim(), style); }; if (criticalOperations.length > 0) { console.log('%c🔴 CRÍTICAS ( > 2000ms)', 'color: #fff; font-size: 14px; font-weight: bold; margin-top: 10px;'); criticalOperations.forEach(([operation, stats]) => { const avg = Math.round(stats.totalTime / stats.count); const { emoji } = this.getPerformanceStatus(avg, stats.customThresholds, operation); printBlock('#c53030', emoji, operation, avg, '| otimizar urgente'); }); } if (slowOperations.length > 0) { console.log('%c🟡 LENTAS (500ms - 2000ms)', 'color: #fff; font-size: 14px; font-weight: bold; margin-top: 10px;'); slowOperations.forEach(([operation, stats]) => { const avg = Math.round(stats.totalTime / stats.count); const { emoji } = this.getPerformanceStatus(avg, stats.customThresholds, operation); printBlock('#b7791f', emoji, operation, avg, '| pode ser melhorada'); }); } if (fastOperations.length > 0) { console.log('%c🟢 RÁPIDAS ( < 500ms)', 'color: #fff; font-size: 14px; font-weight: bold; margin-top: 10px;'); fastOperations.forEach(([operation, stats]) => { const avg = Math.round(stats.totalTime / stats.count); const { emoji } = this.getPerformanceStatus(avg, stats.customThresholds, operation); printBlock('#38a169', emoji, operation, avg, '| excelente'); }); } // Recomendações console.log('%cRecomendações:', 'color: #fff; font-size: 13px; font-weight: bold; margin-top: 14px; padding: 2px 0 2px 0;'); if (criticalOperations.length > 0) { console.log('%c• Priorize a otimização das operações críticas.', 'color: #fff; font-size: 13px; font-weight: normal;'); console.log('%c• Considere implementar cache ou otimizar consultas SQL para essas operações.', 'color: #fff; font-size: 13px; font-weight: normal;'); } if (slowOperations.length > 0) { console.log('%c• Operações lentas podem se beneficiar de índices no banco de dados.', 'color: #fff; font-size: 13px; font-weight: normal;'); } if (criticalOperations.length === 0 && slowOperations.length === 0) { console.log('%c• Todas as operações estão com performance excelente!', 'color: #fff; font-size: 13px; font-weight: normal;'); } // Score const totalOperations = this.performanceSummary.size; const fastCount = fastOperations.length; const performanceScore = totalOperations > 0 ? Math.round((fastCount / totalOperations) * 100) : 100; let scoreColor = performanceScore >= 80 ? '#38a169' : performanceScore >= 60 ? '#f6e05e' : '#c53030'; let scoreMsg = performanceScore >= 80 ? 'Excelente! A maioria das operações está performando bem.' : performanceScore >= 60 ? 'Médio. Há espaço para melhorias de performance.' : 'Crítico. Muitas operações precisam de otimização urgente.'; console.log(`%cScore de performance: ${performanceScore}%`, `color: #fff; background: ${scoreColor}; font-size: 14px; font-weight: bold; margin-top: 10px; padding: 2px 8px; border-radius: 3px;`); console.log(`%c${scoreMsg}`, `color: #fff; font-size: 13px; font-weight: normal; margin-bottom: 8px;`); console.log(''); } /** * 📋 Categoriza operações por performance * @returns Objeto com arrays de operações categorizadas */ categorizeOperations() { const criticalOperations = Array.from(this.performanceSummary.entries()).filter(([_, stats]) => stats.totalTime / stats.count > 2000); const slowOperations = Array.from(this.performanceSummary.entries()).filter(([_, stats]) => { const avg = stats.totalTime / stats.count; return avg >= 500 && avg <= 2000; }); const fastOperations = Array.from(this.performanceSummary.entries()).filter(([_, stats]) => stats.totalTime / stats.count < 500); return { criticalOperations, slowOperations, fastOperations }; } /** * 💡 Exibe recomendações baseadas na análise * @param criticalOperations Array de operações críticas * @param slowOperations Array de operações lentas */ showRecommendations(criticalOperations, slowOperations) { console.log('RECOMENDAÇÕES:'); if (criticalOperations.length > 0) { console.log(' Priorize a otimização das operações críticas.'); console.log(' Considere implementar cache ou otimizar consultas SQL para essas operações.'); } if (slowOperations.length > 0) { console.log(' Operações lentas podem se beneficiar de índices no banco de dados.'); } if (criticalOperations.length === 0 && slowOperations.length === 0) { console.log(' Todas as operações estão com performance excelente!'); } } /** * 📊 Exibe score de performance * @param fastOperationsCount Número de operações rápidas */ showPerformanceScore(fastOperationsCount) { const totalOperations = this.performanceSummary.size; const performanceScore = Math.round((fastOperationsCount / totalOperations) * 100); console.log(`SCORE DE PERFORMANCE: ${performanceScore}%`); if (performanceScore >= 80) { console.log('Excelente! A maioria das operações está performando bem.'); } else if (performanceScore >= 60) { console.log('Médio. Há espaço para melhorias de performance.'); } else { console.log('Crítico. Muitas operações precisam de otimização urgente.'); } } // ===== API PÚBLICA ===== /** * 📊 Método público para exibir relatório de performance * Pode ser chamado no console do navegador para análise */ getPerformanceReport() { this.showPerformanceSummary(); } /** * 🧹 Método público para limpar dados de performance * Útil para resetar estatísticas e começar nova análise */ resetPerformanceData() { this.performanceTimers.clear(); this.performanceSummary.clear(); this.httpRequests.clear(); // Mensagem estilizada de limpeza console.log('%c🧹 [CLEANUP] Dados de performance limpos', 'color: #fff; background: #43248bff; font-size: 13px; font-weight: bold; border-radius: 4px; padding: 4px 12px; margin: 6px 0;'); } /** * ⏰ Configura o delay para relatório por inatividade * @param seconds Número de segundos de inatividade para mostrar relatório */ setInactivityDelay(seconds) { // Desabilitado console.log('⏰ Relatório por inatividade está desabilitado.'); } /** * 🔇 Desabilita relatório automático por inatividade */ disableInactivityReport() { // Desabilitado console.log('🔇 Relatório por inatividade já está desabilitado'); } /** * ⚙️ Configura o threshold para relatório automático * @param threshold Número de operações para mostrar relatório automaticamente */ setAutoReportThreshold(threshold) { // Desabilitado console.log('⚙️ Threshold para relatório automático está desabilitado.'); } /** * 🔇 Desabilita relatório automático */ disableAutoReport() { // Desabilitado console.log('🔇 Relatório automático desabilitado'); } /** * 📈 Obtém estatísticas resumidas sem exibir no console * @returns Objeto com estatísticas de performance */ getStatistics() { const { criticalOperations, slowOperations, fastOperations } = this.categorizeOperations(); const totalOperations = this.performanceSummary.size; let totalTime = 0; let totalCount = 0; this.performanceSummary.forEach((stats) => { totalTime += stats.totalTime; totalCount += stats.count; }); const averageTime = totalCount > 0 ? Math.round(totalTime / totalCount) : 0; const performanceScore = totalOperations > 0 ? Math.round((fastOperations.length / totalOperations) * 100) : 100; return { totalOperations, averageTime, fastOperations: fastOperations.length, slowOperations: slowOperations.length, criticalOperations: criticalOperations.length, performanceScore, }; } /** * 🎯 Obtém dados de uma operação específica * @param operationName Nome da operação * @returns Estatísticas da operação ou null se não encontrada */ getOperationStats(operationName) { const baseStats = this.performanceSummary.get(operationName); if (!baseStats) return null; // Extrai nomes das requisições HTTP como array de strings const httpRequestEntry = this.httpRequests.get(operationName); const httpCalls = httpRequestEntry ? [operationName] : []; return Object.assign(Object.assign({}, baseStats), { httpCalls }); } /** * 📋 Lista todas as operações monitoradas * @returns Array com nomes das operações */ getMonitoredOperations() { return Array.from(this.performanceSummary.keys()); } /** * 🔄 Verifica se há timers ativos * @returns true se há timers em execução */ hasActiveTimers() { return this.performanceTimers.size > 0; } /** * 🗑️ Limpa apenas os timers ativos (não as estatísticas) */ clearActiveTimers() { this.performanceTimers.clear(); console.log('%c🗑️ [CLEANUP] Timers ativos limpos', 'color: #fff; background: #23272f; font-size: 13px; font-weight: bold; border-radius: 4px; padding: 4px 12px; margin: 6px 0;'); } /** * 💾 Exporta dados de performance para JSON * @returns String JSON com todos os dados */ exportData() { const data = { timestamp: new Date().toISOString(), serviceName: this.serviceName, statistics: this.getStatistics(), operations: Array.from(this.performanceSummary.entries()).map(([name, stats]) => (Object.assign(Object.assign({ name }, stats), { averageTime: Math.round(stats.totalTime / stats.count) }))), }; return JSON.stringify(data, null, 2); } /** * 🎯 Calcula thresholds dinâmicos baseados na quantidade de execuções * @param executionCount Número de execuções da operação * @returns Objeto com thresholds calculados dinamicamente */ calculateDynamicThresholds(executionCount) { if (executionCount === 1) { // Primeira execução - expectativas mais relaxadas return { ok: 1000, lento: 2000, critico: 2000, }; } else if (executionCount <= 5) { // Até 5 execuções - sistema ainda aquecendo return { ok: 500, lento: 1000, critico: 1000, }; } else if (executionCount <= 10) { // Até 10 execuções - sistema otimizado return { ok: 100, lento: 250, critico: 250, }; } else { // Acima de 10 execuções - expectativas altas return { ok: 20, lento: 60, critico: 60, }; } } injectMonitorButton() { if (document.getElementById('btn-monitorar-performance')) return; // ====== ESTILO MODERNO E BOTÃO DE OLHO ====== const BUTTON_COLOR = '#23272f'; // cinza escuro elegante const BUTTON_TEXT_COLOR = '#f3f4f6'; const BUTTON_RADIUS = '8px'; const BUTTON_FONT_SIZE = '13px'; const BUTTON_PADDING = '10px 5px'; const BUTTON_WIDTH = '210px'; const BUTTON_HEIGHT = '44px'; const BUTTON_BOX_SHADOW = '0 2px 12px #0002'; const BUTTON_BORDER = '1px solid #353a40'; // Container para animação const container = document.createElement('div'); container.id = 'performance-monitor-container'; Object.assign(container.style, { position: 'fixed', bottom: '5px', left: '50px', zIndex: '9999', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'flex-end', transition: 'transform 0.5s cubic-bezier(.4,2,.6,1)', gap: '10px', }); // Função para criar botões padronizados const criarBotao = (id, texto) => { const btn = document.createElement('button'); btn.id = id; btn.innerText = texto; Object.assign(btn.style, { width: BUTTON_WIDTH, height: BUTTON_HEIGHT, background: BUTTON_COLOR, color: BUTTON_TEXT_COLOR, borderRadius: BUTTON_RADIUS, border: BUTTON_BORDER, padding: BUTTON_PADDING, fontSize: BUTTON_FONT_SIZE, fontWeight: '600', cursor: 'pointer', boxShadow: BUTTON_BOX_SHADOW, letterSpacing: '0.01em', textAlign: 'center', transition: 'background 0.2s, color 0.2s, transform 0.5s cubic-bezier(.4,2,.6,1)', }); btn.onmouseenter = () => { btn.style.background = '#353a40'; btn.style.color = '#fff'; }; btn.onmouseleave = () => { btn.style.background = BUTTON_COLOR; btn.style.color = BUTTON_TEXT_COLOR; }; return btn; }; // Botões principais const btnMain = criarBotao('btn-monitorar-performance', 'Parar monitoramento'); const btnFinalizar = criarBotao('btn-finalizar-monitoramento', 'Finalizar monitoramento'); const btnRequisicoesDetalhadas = criarBotao('btn-req-detalhadas-performance', 'Requisições detalhadas'); const btnAnaliseDetalhada = criarBotao('btn-analise-detalhada-performance', 'Análise detalhada'); // Inicialmente escondidos btnRequisicoesDetalhadas.style.display = 'none'; btnAnaliseDetalhada.style.display = 'none'; btnFinalizar.style.display = 'none'; // Botão de esconder/mostrar com ícone de olho (fora do container) const btnToggle = document.createElement('button'); btnToggle.id = 'btn-toggle-performance'; btnToggle.innerHTML = ` <img src="https://cdn-icons-png.flaticon.com/512/565/565655.png" alt="esconder" style="width:15px; height:15px; vertical-align:middle; filter: invert(1);" /> `; Object.assign(btnToggle.style, { width: '38px', height: '38px', background: '#23272f', color: '#f3f4f6', borderRadius: '50%', border: BUTTON_BORDER, fontSize: '20px', fontWeight: 'bold', cursor: 'pointer', boxShadow: BUTTON_BOX_SHADOW, position: 'fixed', left: '5px', bottom: '5px', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: '10000', }); btnToggle.onmouseenter = () => { btnToggle.style.background = '#353a40'; btnToggle.style.color = '#fff'; }; btnToggle.onmouseleave = () => { btnToggle.style.background = '#23272f'; btnToggle.style.color = '#f3f4f6'; }; let hidden = false; btnToggle.onclick = () => { hidden = !hidden; if (hidden) { container.style.display = 'none'; btnToggle.innerHTML = ` <img src="https://cdn-icons-png.flaticon.com/512/159/159604.png" alt="mostrar" style="width:15px; height:15px; vertical-align:middle; filter: invert(1);" /> `; } else { container.style.display = 'flex'; btnToggle.innerHTML = ` <img src="https://cdn-icons-png.flaticon.com/512/565/565655.png" alt="esconder" style="width:15px; height:15px; vertical-align:middle; filter: invert(1);" /> `; } }; // Estado dos botões let estado = 'monitorando'; const atualizarBotoes = (novoEstado) => { estado = novoEstado; switch (estado) { case 'inativo': btnMain.innerText = 'Iniciar monitoramento'; this.monitoramentoAtivo = false; btnFinalizar.style.display = 'none'; btnRequisicoesDetalhadas.style.display = 'none'; btnAnaliseDetalhada.style.display = 'none'; break; case 'monitorando': btnMain.innerText = 'Parar monitoramento'; this.monitoramentoAtivo = true; btnFinalizar.style.display = 'none'; btnRequisicoesDetalhadas.style.display = 'none'; btnAnaliseDetalhada.style.display = 'none'; break; case 'relatorio': btnMain.innerText = 'Gerar relatório'; this.monitoramentoAtivo = false; btnFinalizar.style.display = 'none'; btnRequisicoesDetalhadas.style.display = 'block'; btnAnaliseDetalhada.style.display = 'block'; break; case 'relatorio_gerado': btnMain.innerText = 'Gerar relatório'; this.monitoramentoAtivo = false; btnFinalizar.style.display = 'block'; btnRequisicoesDetalhadas.style.display = 'block'; btnAnaliseDetalhada.style.display = 'block'; break; } }; // Ações dos botões btnMain.onclick = () => { if (estado === 'inativo') { this.resetPerformanceData(); this.showWelcomeMessage(); atualizarBotoes('monitorando'); } else if (estado === 'monitorando') { atualizarBotoes('relatorio'); } else if (estado === 'relatorio' || estado === 'relatorio_gerado') { this.showPerformanceSummary(false); atualizarBotoes('relatorio_gerado'); } }; btnFinalizar.onclick = () => { this.resetPerformanceData(); atualizarBotoes('inativo'); }; // Apêndice this.showWelcomeMessage(); container.appendChild(btnMain); container.appendChild(btnRequisicoesDetalhadas); container.appendChild(btnAnaliseDetalhada); container.appendChild(btnFinalizar); document.body.appendChild(container); document.body.appendChild(btnToggle); // Ação do botão de requisições detalhadas btnRequisicoesDetalhadas.onclick = () => { this.showHttpRequestsReport(); }; // Ação do botão de análise detalhada btnAnaliseDetalhada.onclick = () => { this.generateDetailedAnalysis(); }; } } /** * 🏭 Factory function para criar instância do LogsPerformatico * @param serviceName Nome do serviço (para logs personalizados) * @returns Nova instância de LogsPerformatico */ function createPerformanceLogger(serviceName = 'Service') { return new LogsPerformatico(serviceName); } const GlobalPerformanceLogger = createPerformanceLogger('GLOBAL'); const PerformanceMonitor = PerformanceMonitorFactory(GlobalPerformanceLogger); function PerformanceMonitorFactory(globalLogger) { return function PerformanceMonitor(options) { return function (target, propertyKey, descriptor) { const originalMethod = descriptor.value; let opName; let customMethod; let customThresholds; if (typeof options === 'object' && options !== null) { opName = options.name || propertyKey; customMethod = options.method; customThresholds = { ok: options.ok, lento: options.lento, critico: options.critico, }; } else if (typeof options === 'function') { opName = options.name || propertyKey; customMethod = options; } else if (typeof options === 'string') { opName = options; } else { opName = propertyKey; } descriptor.value = function (...args) { return __awaiter(this, void 0, void 0, function* () { const instanceLogger = this .performanceLogger; const logger = instanceLogger || globalLogger; if (logger) { logger.startTimer(opName); try { const methodToCall = customMethod || originalMethod; const result = yield methodToCall.apply(this, args); return result; } finally { logger.endTimer(opName, undefined, customThresholds); } } else { const methodToCall = customMethod || originalMethod; return yield methodToCall.apply(this, args); } }); }; return descriptor; }; }; } class PerformanceMonitorInterceptor { intercept(req, next) { var _a; // Ignora arquivos de assets if (!req.url.startsWith('./assets')) { // 🔹 Recupera dados da sessão let tela = sessionStorage.getItem('idTela'); if (!tela) { tela = 'SEL041'; sessionStorage.setItem('idTela', tela); } const cdUsuario = (_a = sessionStorage.getItem('cdUsuario')) !== null && _a !== void 0 ? _a : ''; // 🔹 Clona a requisição adicionando headers const authReq = req.clone({ headers: req.headers .set('tela_id', tela) .set('tela', 'SEL041') .set('user', cdUsuario), }); const start = performance.now(); return next.handle(authReq).pipe(tap({ next: (event) => { var _a, _b; if (event instanceof HttpResponse) { const tempo = performance.now() - start; // ✅ Verificação segura do body e suas propriedades const operationType = ((_a = authReq.body) === null || _a === void 0 ? void 0 : _a.operationType) || 'UNKNOWN'; const operationName = ((_b = authReq.body) === null || _b === void 0 ? void 0 : _b.name) || ''; console.log(`%c🟢 [HTTP] ${operationType} ${operationType === 'SELECT_FULL' ? '' : operationName} - ${tempo.toFixed(1)}ms`, 'color: #6cbbd8ff; font-weight: bold;'); GlobalPerformanceLogger.registerHttpRequest(authReq, tempo, false); } }, error: (error) => { var _a, _b; const tempo = performance.now() - start; // ✅ Verificação segura do body e suas propriedades const operationType = ((_a = authReq.body) === null || _a === void 0 ? void 0 : _a.operationType) || 'UNKNOWN'; const operationName = ((_b = authReq.body) === null || _b === void 0 ? void 0 : _b.name) || ''; console.groupCollapsed(`%c🔴 [HTTP] ${operationType} ${operationName} - ${tempo.toFixed(1)}ms`, 'color: #6cbbd8ff; font-weight: bold;'); console.error(error); console.groupEnd(); GlobalPerformanceLogger.registerHttpRequest(authReq, tempo, true); }, })); } // Requisição de asset, passa direto return next.handle(req); } } PerformanceMonitorInterceptor.decorators = [ { type: Injectable } ]; /* * Public API Surface of performance-monitor */ /** * Generated bundle index. Do not edit. */ export { GlobalPerformanceLogger, PerformanceMonitor, PerformanceMonitorComponent, PerformanceMonitorInterceptor, PerformanceMonitorModule, PerformanceMonitorService, LogsPerformatico as ɵa, createPerformanceLogger as ɵb }; //# sourceMappingURL=performance-monitor-logger.js.map