UNPKG

mm_os

Version:

这是超级美眉服务端框架,用于快速构建应用程序。

143 lines (125 loc) 4.5 kB
/** * 请求性能监控中间件 * 记录请求响应时间,监控慢请求,提供性能数据收集 */ module.exports = function(server, config) { if(config.web && !config.web.performance) { return server; } // 默认配置 const cg = Object.assign({ slowThreshold: 1000, // 慢请求阈值,单位毫秒 enableMetrics: true, // 是否启用性能指标收集 ignorePaths: [] // 忽略监控的路径 }, config); // 性能监控数据收集器 const performanceData = { counters: new Map(), // 请求计数器 responseTimes: new Map(), // 响应时间数据 slowRequests: [] // 慢请求记录 }; // 全局性能监控对象 $.performanceMonitor = { record: function(path, responseTime) { if (!cg.enableMetrics) return; // 更新请求计数 if (!performanceData.counters.has(path)) { performanceData.counters.set(path, 1); performanceData.responseTimes.set(path, { sum: responseTime, count: 1, min: responseTime, max: responseTime }); } else { performanceData.counters.set(path, performanceData.counters.get(path) + 1); const stats = performanceData.responseTimes.get(path); stats.sum += responseTime; stats.count += 1; stats.min = Math.min(stats.min, responseTime); stats.max = Math.max(stats.max, responseTime); } // 记录慢请求 if (responseTime > cg.slowThreshold) { performanceData.slowRequests.push({ path: path, time: new Date(), responseTime: responseTime }); // 限制慢请求记录数量 if (performanceData.slowRequests.length > 1000) { performanceData.slowRequests.shift(); } } }, getStats: function() { const result = {}; performanceData.counters.forEach((count, path) => { const times = performanceData.responseTimes.get(path); result[path] = { count: count, avg: times.sum / times.count, min: times.min, max: times.max }; }); return result; }, getSlowRequests: function(limit = 100) { return performanceData.slowRequests.slice(-limit); }, reset: function() { performanceData.counters.clear(); performanceData.responseTimes.clear(); performanceData.slowRequests = []; } }; // 性能监控中间件 server.use(async (ctx, next) => { // 检查是否需要忽略此路径 const shouldIgnore = cg.ignorePaths.some(pattern => { if (typeof pattern === 'string') { return ctx.path === pattern; } else if (pattern instanceof RegExp) { return pattern.test(ctx.path); } return false; }); if (shouldIgnore) { await next(); return; } const start = Date.now(); const startTime = process.hrtime(); try { await next(); } finally { const ms = Date.now() - start; const [seconds, nanoseconds] = process.hrtime(startTime); const executionTime = seconds * 1000 + nanoseconds / 1000000; // 设置响应时间头 ctx.set('X-Response-Time', `${ms}ms`); // 记录性能数据 $.performanceMonitor.record(ctx.path, ms); // 慢请求报警 if (ms > cg.slowThreshold) { const clientIP = ctx.headers['x-forwarded-for'] || ctx.ip; $.log.warn(`【慢请求】 ${ctx.method} ${ctx.path} - ${ms}ms - ${clientIP}`); // 如果是非常慢的请求(超过阈值的2倍),记录更多信息 if (ms > cg.slowThreshold * 2) { const userAgent = ctx.headers['user-agent'] || 'unknown'; let requestData = ''; try { if (ctx.method !== 'GET' && ctx.request.body) { const bodyStr = JSON.stringify(ctx.request.body); // 限制记录的请求体大小 requestData = bodyStr.length > 1024 ? bodyStr.substring(0, 1024) + '...' : bodyStr; } } catch (e) { requestData = '[无法序列化请求体]'; } $.log.warn(`【慢请求详情】路径: ${ctx.path}, 方法: ${ctx.method}, 耗时: ${ms}ms, IP: ${clientIP}, UA: ${userAgent.substring(0, 200)}`); if (requestData) { $.log.warn(`【慢请求数据】${requestData}`); } } } } }); return server; };