您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
迅速查看最耗时的接口、最大的接口、调用次数最多的接口
// ==UserScript== // @name k8s接口统计 // @namespace http://tampermonkey.net/ // @version 2024-05-23 // @description 迅速查看最耗时的接口、最大的接口、调用次数最多的接口 // @author Peter Chiang // @match http://*/* // @match https://*/* // @icon https://www.microsoft.com/favicon.ico // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; })(); // 出口接口延迟 function getOutgoingApis(hitsArray) { let outPutDetails = []; hitsArray.forEach((hit) => { // 获取_source.message的值 const messageString = hit._source.message; const appname = hit._source.appname; // 解析message字符串为JSON对象 try { const messageJSON = JSON.parse(messageString); const utcDateString = hit._source['@timestamp']; const date = new Date(utcDateString); const localDateString = date.toLocaleString(); if (messageJSON.path && messageJSON.path.length > 0) { // 将message的大小和对应的uri存储到数组中 outPutDetails.push({ size: messageString.length / 1000, appname, path: messageJSON.path, latency: parseInt(messageJSON.latency), timestamp: localDateString, trace_id: messageJSON.trace_id, }); } } catch (parseError) { // console.info('Error parsing message to JSON:', parseError); } }); return outPutDetails; } // 微服务接口大小排序 function getMicroServiceApis(hitsArray) { let messageDetails = []; hitsArray.forEach((hit) => { // 获取_source.message的值 const messageString = hit._source.message; const appname = hit._source.appname; // 解析message字符串为JSON对象 try { const messageJSON = JSON.parse(messageString); if (messageJSON.uri && messageJSON.uri.length > 0) { // 将message的大小和对应的uri存储到数组中 messageDetails.push({ size: messageString.length / 1000, appname, path: messageJSON.uri, latency: parseFloat(messageJSON.latency), trace_id: messageJSON.trace_id, }); } } catch (parseError) { // console.info('Error parsing message to JSON:', parseError); } }); return messageDetails; } function countAndSortPaths(arr) { // 创建一个 Map 来存储每个路径及其出现次数 const pathCount = new Map(); // 遍历数组,统计每个路径的出现次数 for (const item of arr) { if (pathCount.has(item.path)) { pathCount.set(item.path, pathCount.get(item.path) + 1); } else { pathCount.set(item.path, 1); } } // 将 Map 转换为对象数组,并按照出现次数排序 const sortedPaths = Array.from(pathCount.entries()).sort((a, b) => b[1] - a[1]); // 创建一个对象来存储排序后的路径及其出现次数 const result = []; for (const [path, count] of sortedPaths) { result.push({ path, count }); } return result; } function arrayToCSV(dataArray) { // 将对象数组转换为 CSV 字符串 const csvRows = []; const headers = ['appname', 'path', 'size', 'latency', 'count', 'trace_id']; csvRows.push(headers.join(',')); for (const row of dataArray) { const values = headers.map(header => { let value = row[header] || ''; if (typeof value === "string") { value = value.replace(/"/g, '""'); } return value; }).join(','); csvRows.push(values); } return csvRows.join('\n'); } function downloadCSV(csvData, filename) { // 创建 Blob 对象 const blob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' }); // 创建下载链接 const link = document.createElement('a'); const url = URL.createObjectURL(blob); link.href = url; link.download = filename; // 添加链接至 DOM,模拟点击下载 document.body.appendChild(link); link.click(); // 移除链接并释放 URL document.body.removeChild(link); URL.revokeObjectURL(url); } // 保存原始的 XMLHttpRequest 方法 const originalOpen = XMLHttpRequest.prototype.open; const originalSend = XMLHttpRequest.prototype.send; // 重写 open 方法 XMLHttpRequest.prototype.open = function(method, url) { this._method = method; this._url = url; return originalOpen.apply(this, arguments); }; // 重写 send 方法 XMLHttpRequest.prototype.send = function(body) { this.addEventListener('load', function() { const keyword1 = '/elasticsearch'; const keyword2 = '/_search'; const url = this._url; const needResponds = (url && url.includes(keyword1) && url.includes(keyword2) && this.status === 200) if (needResponds) { const jsonData = JSON.parse(this.responseText); // 获取原始数据 const hitsArray = jsonData.hits.hits; // APP接口 const outGoing = getOutgoingApis(hitsArray); let outGoingSort = outGoing.sort((item1, item2)=> item2.latency - item1.latency); const latenceTop20 = outGoingSort.slice(0, 20); console.log('latenceTop20', latenceTop20); // 微服务接口 const microApis = getMicroServiceApis(hitsArray); const microApisSort = microApis.sort((item1, item2)=> item2.size - item1.size); const sizeTop20 = microApisSort.slice(0, 20); console.log('sizeTop20', sizeTop20); // 频率 const pathsArray = outGoing; pathsArray.concat(microApis); const frequnceyTop20 = countAndSortPaths(pathsArray); const latencyHeader = {appname: '延迟TOP20', size: 0, path: '', latency: 0, timestamp: 0}; const sizeHeader = {appname: '数据量TOP20'}; const frequenceHeader = {appname: '调用频次TOP20'}; let cvsData = []; cvsData.push(latencyHeader); cvsData = cvsData.concat(latenceTop20); cvsData.push(sizeHeader); cvsData = cvsData.concat(sizeTop20); cvsData.push(frequenceHeader); cvsData = cvsData.concat(frequnceyTop20); const cvsResult = arrayToCSV(cvsData); // 转化和下载 const inputElement = document.querySelector('.euiFieldText.euiFieldText--fullWidth.euiFieldText--inGroup'); const timeString = new Date().toLocaleString(); // const downloadFuc = () => downloadCSV(cvsResult, `k8s-${timeString}-${inputElement.value || ''}`); const oldButton = document.getElementById('pertercvs'); if (oldButton) { oldButton.remove(); } // 通过类名选择器找到 <span> 元素 const spanElement = document.querySelector('span.euiButton__text'); // 创建一个新的 <button> 元素 const downloadBtn = document.createElement('button'); downloadBtn.textContent = '统计数据'; downloadBtn.id = 'pertercvs'; if (spanElement) { spanElement.parentNode.insertBefore(downloadBtn, spanElement.nextSibling); downloadBtn.addEventListener('click', function(){ downloadCSV(cvsResult, `k8s-${timeString}-${inputElement.value || ''}`); }); } } }); return originalSend.apply(this, arguments); };
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址