Greasy Fork

来自缓存

Greasy Fork is available in English.

k8s接口统计

迅速查看最耗时的接口、最大的接口、调用次数最多的接口

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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);
};