统计数据

是否接口上线后查询日志麻烦,统计繁琐,使用本插件可以直接一次性查询

  1. // ==UserScript==
  2. // @name 统计数据
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.3
  5. // @description 是否接口上线后查询日志麻烦,统计繁琐,使用本插件可以直接一次性查询
  6. // @author DaiXukai(xkplan@163.com
  7. // @match https://next.api.aliyun.com/**
  8. // @icon https://next.api.aliyun.com/favicon.ico
  9. // @license GNU GPLv3
  10. // @grant GM_registerMenuCommand
  11. // @grant GM_notification
  12. // ==/UserScript==
  13.  
  14. // 使用方式:
  15. // 1. 打开网站 https://next.api.aliyun.com/api/Sls/2020-12-30/GetHistograms
  16. // 2. 登录 RAM 账号
  17. // 3. 点击脚本“执行”,输入参数等待结果
  18.  
  19. // 插件配置
  20. const config = {
  21. // 日志库配置
  22. logstore: {
  23. // 访问日志
  24. access: "hd_manbo_portal_access",
  25. // 错误日志
  26. error: "hd_manbo_portal_error",
  27. }
  28. }
  29. // 运行状态
  30. const state = {
  31. running: false,
  32. inputQuery: "",
  33. inputDate: "1,2",
  34. eleBox: undefined
  35. }
  36.  
  37. /**
  38. * prompt 用户输入,忽略空字符串
  39. * @param {string} promptMsg 输入提示信息
  40. * @param {string} def 默认输入内容(占位)
  41. * @param {RegExp} regex 校验内容正则表达式
  42. * @throws 1 点击取消抛出
  43. * @returns string 用户输入内容
  44. */
  45. function input(promptMsg, def, regex) {
  46. let tmpInput = "";
  47. while (!regex.test(tmpInput)) {
  48. tmpInput = prompt(promptMsg, def);
  49. if (tmpInput === null || tmpInput === undefined) {
  50. // 点击取消
  51. throw 1;
  52. }
  53. tmpInput = tmpInput.trim();
  54. }
  55. return tmpInput;
  56. }
  57.  
  58. /**
  59. * 请求接口查询日志统计数
  60. * @param {string} logstore 日志库名
  61. * @param {number} from 开始时间戳(秒)
  62. * @param {number} to 结束时间戳(秒)
  63. * @param {string} query 查询语句
  64. * @returns Promise 结果为统计到的日志数量
  65. */
  66. async function request(logstore, from, to, query) {
  67. let resp = await fetch("https://next.api.aliyun.com/api/auth/product/openAPIRequest", {
  68. "headers": {
  69. "accept": "application/json",
  70. "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
  71. "bx-v": "2.5.6",
  72. "cache-control": "no-cache",
  73. "content-type": "application/json",
  74. "pragma": "no-cache",
  75. "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Microsoft Edge\";v=\"120\"",
  76. "sec-ch-ua-mobile": "?0",
  77. "sec-ch-ua-platform": "\"Windows\"",
  78. "sec-fetch-dest": "empty",
  79. "sec-fetch-mode": "cors",
  80. "sec-fetch-site": "same-origin"
  81. },
  82. "referrer": "https://next.api.aliyun.com/api/Sls/2020-12-30/GetHistograms?sdkStyle=dara&params=%7B%22to%22:1703073392,%22from%22:1703072486,%22logstore%22:%22hd_service_live_info%22,%22project%22:%22hd-live%22,%22query%22:%22444%22%7D&tab=DEBUG&lang=PYTHON",
  83. "referrerPolicy": "strict-origin-when-cross-origin",
  84. "body": "{\"action\":\"GetHistograms\",\"product\":\"Sls\",\"bodyStyle\":null,\"apiStyle\":\"ROA\",\"apiVersion\":\"2020-12-30\",\"accessKeyId\":null,\"proxyEndpoint\":\"http://popunify-inner-pre.aliyuncs.com\",\"endpoint\":\"cn-beijing.log.aliyuncs.com\",\"regionId\":\"cn-beijing\",\"paramObject\":{\"method\":\"GET\",\"path\":\"/logstores/{logstore}/index?type=histogram\",\"params\":\"[{\\\"name\\\":\\\"project\\\",\\\"position\\\":\\\"Host\\\",\\\"required\\\":true,\\\"checkBlank\\\":false,\\\"visibility\\\":\\\"Public\\\",\\\"deprecated\\\":false,\\\"type\\\":\\\"String\\\",\\\"title\\\":\\\"project 名称。\\\",\\\"example\\\":\\\"ali-test-project\\\",\\\"description\\\":\\\"project 名称。\\\"},{\\\"name\\\":\\\"logstore\\\",\\\"position\\\":\\\"Path\\\",\\\"required\\\":true,\\\"checkBlank\\\":false,\\\"visibility\\\":\\\"Public\\\",\\\"deprecated\\\":false,\\\"type\\\":\\\"String\\\",\\\"title\\\":\\\"logstore 名称。\\\",\\\"example\\\":\\\"test-logstore\\\",\\\"description\\\":\\\"Logstore名称。\\\"},{\\\"name\\\":\\\"from\\\",\\\"position\\\":\\\"Query\\\",\\\"required\\\":true,\\\"checkBlank\\\":false,\\\"visibility\\\":\\\"Public\\\",\\\"deprecated\\\":false,\\\"type\\\":\\\"Long\\\",\\\"title\\\":\\\"查询开始时间点。UNIX时间戳格式,表示从1970-1-1 00:00:00 UTC计算起的秒数。\\\\n\\\\n时间区间遵循“左闭右开”原则,即该时间区间包括区间开始时间点,但不包括区间结束时间点。如果from和to的值相同,则为无效区间,函数直接返回错误。\\\",\\\"example\\\":\\\"1409529600\\\",\\\"description\\\":\\\"子时间区间的开始时间点。UNIX时间戳格式,表示从1970-1-1 00:00:00 UTC计算起的秒数。\\\"},{\\\"name\\\":\\\"to\\\",\\\"position\\\":\\\"Query\\\",\\\"required\\\":true,\\\"checkBlank\\\":false,\\\"visibility\\\":\\\"Public\\\",\\\"deprecated\\\":false,\\\"type\\\":\\\"Long\\\",\\\"title\\\":\\\"查询结束时间点。UNIX时间戳格式,表示从1970-1-1 00:00:00 UTC计算起的秒数。\\\\n\\\\n时间区间遵循“左闭右开”原则,即该时间区间包括区间开始时间点,但不包括区间结束时间点。如果from和to的值相同,则为无效区间,函数直接返回错误。\\\",\\\"example\\\":\\\"1409569200\\\",\\\"description\\\":\\\"子时间区间的结束时间点。UNIX时间戳格式,表示从1970-1-1 00:00:00 UTC计算起的秒数。\\\"},{\\\"name\\\":\\\"topic\\\",\\\"position\\\":\\\"Query\\\",\\\"required\\\":false,\\\"checkBlank\\\":false,\\\"visibility\\\":\\\"Public\\\",\\\"deprecated\\\":false,\\\"type\\\":\\\"String\\\",\\\"title\\\":\\\"日志主题。\\\",\\\"example\\\":\\\"topic\\\",\\\"description\\\":\\\"日志主题。\\\"},{\\\"name\\\":\\\"query\\\",\\\"position\\\":\\\"Query\\\",\\\"required\\\":false,\\\"checkBlank\\\":false,\\\"visibility\\\":\\\"Public\\\",\\\"deprecated\\\":false,\\\"type\\\":\\\"String\\\",\\\"title\\\":\\\"查询语句。仅支持查询语句,不支持分析语句。关于查询语句的详细语法,请参见查询语法。\\\",\\\"example\\\":\\\"with_pack_meta\\\",\\\"description\\\":\\\"查询语句。仅支持查询语句,不支持分析语句。关于查询语句的详细语法,请参见[查询语法](~~43772~~)。\\\"}]\",\"protocol\":\"HTTP|HTTPS\"},\"params\":{\"to\":" + to + ",\"from\":" + from + ",\"logstore\":\"" + logstore + "\",\"project\":\"hd-live\",\"query\":\"" + query + "\"},\"credential\":{\"type\":\"ak\"}}",
  85. "method": "POST",
  86. "mode": "cors",
  87. "credentials": "include"
  88. });
  89. if (resp.status !== 200) {
  90. alert("请求失败,请重试");
  91. throw Error(`请求失败 logstore=${logstore}, from=${from}, to=${to}, query=${query}\nresponse=>${JSON.stringify(resp)}`);
  92. }
  93. let data = await resp.json();
  94. if (data.code === "E_NEED_LOGIN") {
  95. // 未登录
  96. alert("请先登录后重试\nhttps://next.api.aliyun.com/api/Sls/2020-12-30/GetHistograms");
  97. throw Error(`未登录`);
  98. }
  99. if (data.code !== 0) {
  100. alert("请求失败,未知异常,请重试");
  101. throw Error(`请求失败 logstore=${logstore}, from=${from}, to=${to}, query=${query}\nresponse=>${JSON.stringify(resp)}`);
  102. }
  103. data = data.data
  104. // 计数
  105. let count = 0;
  106. if (data.result === undefined){
  107. return 0;
  108. }
  109. for (let item of data.result) {
  110. count += item.count;
  111. }
  112. return count;
  113. }
  114.  
  115. /**
  116. * html 字符串转换为 Node 对象
  117. * @param {string} html html 代码段
  118. * @returns Node 转换出的 Node 元素
  119. */
  120. function parseDom(html) {
  121. let template = document.createElement('template');
  122. template.innerHTML = html;
  123. return template.content.childNodes[0];
  124. }
  125.  
  126. function closeResult() {
  127. if (state.eleBox) {
  128. state.eleBox.remove();
  129. state.eleBox = undefined;
  130. }
  131. }
  132.  
  133. unsafeWindow.closeResult = closeResult;
  134.  
  135. function showResult(data) {
  136. console.log("result", data);
  137. let eleBox = parseDom(`<div id="_sls_result_box_" style="padding: 12px; background: white; border-radius: 16px; position: fixed; z-index: 999; top: 0; bottom:0; left: 0; right: 0; margin: auto auto; width: fit-content; height: fit-content; box-shadow: rgba(0, 0, 0, 0.3) 0 19px 38px, rgba(0, 0, 0, 0.22) 0 15px 12px; display: flex; flex-direction: column; align-items: center;"></div>`)
  138. let eleTable = parseDom(`<table style="background: white; border: 1px solid #818181; border-collapse: collapse;"></table>`);
  139. let eleThead = document.createElement('thead');
  140. let eleTbody = document.createElement('tbody');
  141. eleTable.appendChild(eleThead);
  142. eleTable.appendChild(eleTbody);
  143. eleBox.appendChild(eleTable);
  144. let eleButton = parseDom(`<button onclick="window.closeResult()" style="background: #00adff; margin-top: 16px; border: 0; border-radius: 8px; padding: 4px 24px; color: white;">关闭</button>`)
  145. eleBox.appendChild(eleButton);
  146.  
  147. // 表头
  148. let eleTr = document.createElement('tr');
  149. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>日期</th>"));
  150. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>查询接口(已排除登录校验和用户禁用)</th>"));
  151. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>接口名称</th>"));
  152. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>全天请求次数</th>"));
  153. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>失败总数</th>"));
  154. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>成功率</th>"));
  155. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>晚高峰请求次数</th>"));
  156. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>晚高峰失败次数</th>"));
  157. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>晚高峰成功率</th>"));
  158. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>晚高峰QPS</th>"));
  159. eleThead.appendChild(eleTr);
  160.  
  161. // 表内容
  162. for (let item of data) {
  163. eleTr = document.createElement('tr');
  164. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'>${item.date}</td>`));
  165. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'>${item.api}</td>`));
  166. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'></td>`));
  167. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'>${item.dayAccessCount}</td>`));
  168. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'>${item.dayErrorCount}</td>`));
  169. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'>${parseFloat(Math.floor(item.daySuccessRatio * 100) / 100)}%</td>`));
  170. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'>${item.peakAccessCount}</td>`));
  171. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'>${item.peakErrorCount}</td>`));
  172. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'>${parseFloat(Math.floor(item.peakSuccessRatio * 100) / 100)}%</td>`));
  173. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'>${parseFloat(Math.floor(item.peakQps * 10000) / 10000)}</td`));
  174. eleTbody.appendChild(eleTr);
  175. }
  176.  
  177. document.body.appendChild(eleBox);
  178. state.eleBox = eleBox;
  179.  
  180. GM_notification({
  181. title: "有咖互动接口数据统计",
  182. text: "统计完成",
  183. timeout: 3000,
  184. });
  185. }
  186.  
  187. // 脚本主体
  188. GM_registerMenuCommand("执行", async () => {
  189. if (state.running) {
  190. return;
  191. }
  192. try {
  193. state.running = true;
  194. closeResult();
  195. // 输入查询参数
  196. state.inputQuery = input(`请输入查询接口(英文逗号分隔,如 "/dynamic/lottery/basic/info, /dynamic/lottery/detail")`, state.inputQuery, /^.+(,.+)*$/);
  197. state.inputDate = input(`请输入查询日期(前一天为 1,前第二天为 2,以此类推,英文逗号分隔,如 "1,2" 查询前两天)`, state.inputDate, /^[1-9]\d{0,6}(,[1-9]\d{0,6})*$/);
  198.  
  199. // 解析参数
  200. let apiList = state.inputQuery.split(",");
  201. for (let i in apiList) {
  202. apiList[i] = apiList[i].trim();
  203. }
  204. let dateList = state.inputDate.split(",");
  205. for (let i in dateList) {
  206. dateList[i] = parseInt(dateList[i].trim());
  207. }
  208.  
  209. GM_notification({
  210. title: "有咖互动接口数据统计",
  211. text: "执行统计中,请勿关闭窗口,请稍等...",
  212. timeout: 3000,
  213. });
  214.  
  215. // 获取今天的开始时间戳(秒)
  216. const now = new Date();
  217. const todayStartTimestamp = new Date(`${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()} 00:00:00`).getTime() / 1000;
  218.  
  219. let data = [];
  220. for (let api of apiList) {
  221. for (let date of dateList) {
  222. let startTimestamp = todayStartTimestamp - date * 24 * 3600;
  223. let startTime = new Date(startTimestamp * 1000);
  224. let endTimestamp = todayStartTimestamp - (date - 1) * 24 * 3600;
  225. // 全天请求次数
  226. let dayAccessCount = await request(config.logstore.access, startTimestamp, endTimestamp, `#\\"${api} remote\\"`);
  227. // 失败总数
  228. let dayErrorCount = await request(config.logstore.error, startTimestamp, endTimestamp, `#\\"| requestURI:${api} |\\" not 用户鉴权失败 not 用户已被禁用`);
  229. // 成功率
  230. let daySuccessRatio = dayAccessCount === 0 ? 100 : ((1 - dayErrorCount / dayAccessCount) * 100);
  231. // 晚高峰请求次数 20:00-24:00
  232. let peakAccessCount = await request(config.logstore.access, endTimestamp - 4 * 3600, endTimestamp, `#\\"${api} remote\\"`);
  233. // 晚高峰失败次数 20:00-24:00
  234. let peakErrorCount = await request(config.logstore.error, endTimestamp - 4 * 3600, endTimestamp, `#\\"| requestURI:${api} |\\" not 用户鉴权失败 not 用户已被禁用`);
  235. // 晚高峰成功率
  236. let peakSuccessRatio = peakAccessCount === 0 ? 100 : ((1 - (peakErrorCount / peakAccessCount)) * 100);
  237. // 晚高峰QPS
  238. let peakQps = peakAccessCount / (4 * 3600);
  239. data.push({
  240. date: `${startTime.getFullYear()}-${startTime.getMonth() + 1}-${startTime.getDate()}`,
  241. api,
  242. dayAccessCount,
  243. dayErrorCount,
  244. daySuccessRatio,
  245. peakAccessCount,
  246. peakErrorCount,
  247. peakSuccessRatio,
  248. peakQps
  249. });
  250. }
  251. }
  252. showResult(data);
  253. } finally {
  254. state.running = false;
  255. }
  256. }, "Random");
  257.  
  258. // 脚本主体
  259. GM_registerMenuCommand("kafka 消息发送统计", async () => {
  260. if (state.running) {
  261. return;
  262. }
  263. try {
  264. state.running = true;
  265. closeResult();
  266.  
  267. GM_notification({
  268. title: "有咖互动接口数据统计",
  269. text: "执行统计中,请勿关闭窗口,请稍等...",
  270. timeout: 3000,
  271. });
  272.  
  273. // 获取今天的开始时间戳(秒)
  274. const todayStartTimestamp = new Date(`2024-03-24 00:00:00`).getTime() / 1000;
  275.  
  276. let topicList = [
  277. "add_room_tags",
  278. "adv_balance_deduction_check",
  279. "async_forbid_2_im_server",
  280. "async_forbid_4_living_room_2_im_server",
  281. "async_group_change",
  282. "async_h5_cancellation_account",
  283. "async_push_activity_message",
  284. "async_send_audit_message",
  285. "async_send_fans_group_member_change",
  286. "async_send_talker_audit_message",
  287. "backpack_operation",
  288. "calculate_novel_rank_list_score",
  289. "calculate_ranking_information",
  290. "calculate_user_ranking_information",
  291. "chapter_publish",
  292. "collect_update_sync_to_all",
  293. "combination_goods_reward",
  294. "comment_incr_sort_value",
  295. "comment_info_sync",
  296. "communicate_accept",
  297. "communicate_accept_by_id",
  298. "communicate_add_rmb",
  299. "communicate_invite",
  300. "communicate_refund",
  301. "dispatch_apns_message",
  302. "dispatch_jiguang_message",
  303. "doudian_message_handle_push",
  304. "drama_count_sync_to_es",
  305. "drama_pay_to_vip_return_gold",
  306. "drama_resource_zip_retry",
  307. "drama_role_add_popularity",
  308. "fans_group_member_consume",
  309. "fans_group_order",
  310. "fans_ranking_user_action",
  311. "full_site_float_screen_first_level",
  312. "full_site_float_screen_second_level",
  313. "gacha_broadcast_fist_push_consume",
  314. "gacha_broadcast_second_push_consume",
  315. "get_attention_weibouid_from_openapi",
  316. "gift_bag_gift_queue",
  317. "gift_push_msg_first_level",
  318. "gift_push_msg_second_level",
  319. "global_index_create",
  320. "global_index_update",
  321. "global_index_update_video_info",
  322. "global_index_video_info",
  323. "good_msg_database_sync_h5",
  324. "good_msg_sync_h5",
  325. "good_msg_sync_h5_live_show",
  326. "google_renewal_retry",
  327. "google_renewal_status_retry",
  328. "group_discovery_content_base_score_sync",
  329. "group_discovery_group_base_score_sync",
  330. "gt_push",
  331. "h5_activity_topic",
  332. "h5_bi_data_monitor",
  333. "h5_event_good_reward",
  334. "h5_gacha_info_topic",
  335. "h5_live_room_heart_beat",
  336. "h5_specific_repost_vip",
  337. "h5_sync_server_api_niudan_log",
  338. "h5_sync_server_api_room_log",
  339. "h5_user_exp_result",
  340. "hidden_lottie_gift_send",
  341. "hongdou_grab_red_packet_reward",
  342. "huajiao_big_gift_notify_queue",
  343. "ice_chaved_topic",
  344. "init_novice_mission",
  345. "init_user_send_gold",
  346. "ios_renewal_retry",
  347. "ios_renewal_status_retry",
  348. "ios_retry_verify_receipt",
  349. "kila-user-change-log",
  350. "kila_client_upload_log",
  351. "klive_h5_activity",
  352. "klive_h5_room_heartbeat",
  353. "klive_inviter_reward",
  354. "klive_sync_h5_user_exp_add",
  355. "klive_user_exp_activity",
  356. "link_small_video",
  357. "lottery_condition_status_info",
  358. "meet_game_record_queue",
  359. "noble_push_msg",
  360. "novel_es_info",
  361. "novel_monitor",
  362. "novel_msg_sync_h5",
  363. "novel_pay_sync_h5",
  364. "novel_statistic_count_sync_to_es",
  365. "novice_follow_user",
  366. "operate_room_to_category",
  367. "order_send_category_reward",
  368. "order_send_communicate_reward",
  369. "order_send_gift_reward",
  370. "order_send_house_reward",
  371. "order_send_question_reward",
  372. "order_send_recharge_reward",
  373. "order_send_reward",
  374. "order_send_share_question_reward",
  375. "other_platform_buy_member",
  376. "pendant_gift_push_msg",
  377. "pika_month_live_reward",
  378. "pika_ranklist_topic",
  379. "process_when_drama_zip_complete",
  380. "purify_word_sync_new_es",
  381. "push_jiguang_retry",
  382. "push_message",
  383. "question_add_rmb",
  384. "question_refund",
  385. "question_video_process",
  386. "radio_drama_collect_push",
  387. "random_video_match_push_queue",
  388. "random_video_match_queue",
  389. "record_month_active_user_for_push",
  390. "red_packet_grab_im",
  391. "red_packet_grab_over",
  392. "red_packet_refund",
  393. "red_packet_refund_new",
  394. "red_packet_send_im",
  395. "renewal_unsign",
  396. "room_record_profit",
  397. "room_resource_zip",
  398. "room_resource_zip_retry",
  399. "room_server_test_topic",
  400. "room_timeline_auto_recommend",
  401. "room_weight_update",
  402. "search_server_test_topic",
  403. "send_chat_room_message",
  404. "send_hongdou_diamond_queue",
  405. "send_sms_after_user_withdraw",
  406. "send_sms_when_create_room",
  407. "send_weibo_when_create_room",
  408. "slive_gift_queue",
  409. "sync_account_trans_detail",
  410. "sync_account_trans_detail_for_h5",
  411. "sync_api_log_for_h5",
  412. "sync_audit_text",
  413. "sync_biz_data_2_h5",
  414. "sync_change_user_image",
  415. "sync_elastic_search_consumer_center",
  416. "sync_h5_command_kafka_log",
  417. "sync_h5_heat_beat_user_exp_add",
  418. "sync_h5_ios_order",
  419. "sync_h5_user_exp_add",
  420. "sync_h5_user_exp_add_h5",
  421. "sync_interaction_data_2_h5",
  422. "sync_oms_auditing_info",
  423. "sync_oms_auditing_info_live_show",
  424. "sync_pika_room_heart_beat",
  425. "sync_room_counters_change",
  426. "sync_room_end_for_h5",
  427. "sync_room_exposure_gacha_log_to_h5",
  428. "sync_room_number_to_weibo",
  429. "sync_room_statistic_to_es",
  430. "sync_send_audit_result",
  431. "sync_specific_log_for_h5",
  432. "sync_star_pamper_value",
  433. "sync_trans_detail_for_statistics",
  434. "sync_trans_detail_to_statistics",
  435. "sync_user_like_record",
  436. "sync_user_relation_to_es",
  437. "sync_user_stats_to_es",
  438. "sync_user_work_role",
  439. "sync_waku_h5_user_exp_add",
  440. "sync_weibo_comment",
  441. "sync_year_end_new_user_task_activity",
  442. "synd_h5_msg",
  443. "talker_match",
  444. "talker_user_close",
  445. "test1",
  446. "third_user_add_portrait",
  447. "ugc_keyword_audit",
  448. "ugc_keyword_remove",
  449. "user_add_balance_act",
  450. "user_device_emulator_info",
  451. "user_letter_image",
  452. "user_relation_update",
  453. "video_resource_pack",
  454. "video_statistic_count_sync_to_es",
  455. "weibo_livecard_callback_update_trigger",
  456. "weibo_login_recommend_attention_anchor",
  457. ];
  458. let logList = [
  459. "chat_service_info",
  460. "hd_callback",
  461. "hd_manbo_portal_info",
  462. "hd_oms_live_info",
  463. "hd_portal_live_info",
  464. "hd_push_dispatcher_live_info",
  465. "hd_push_live_info",
  466. "hd_service_live_info",
  467. "room_kila_info",
  468. "room_manbo_info",
  469. "room_server_info",
  470. "base_manbo_info",
  471. "base_portal_info",
  472. ];
  473. let data = [];
  474. let error = [];
  475. for (let topic of topicList) {
  476. let startTimestamp = todayStartTimestamp;
  477. let startTime = new Date(startTimestamp * 1000);
  478. let endTimestamp = todayStartTimestamp + 24 * 3600;
  479. let dayAccessCount = 0;
  480. let peakAccessCount = 0;
  481. try{
  482. for (let logName of logList) {
  483. // 全天请求次数
  484. let tmp = await request(logName, startTimestamp, endTimestamp, `#\\"MQ send topic:${topic},\\"`);
  485. dayAccessCount += tmp;
  486. if(tmp > 0){
  487. // 晚高峰请求次数 20:00-24:00
  488. peakAccessCount += await request(logName, endTimestamp - 4 * 3600, endTimestamp, `#\\"MQ send topic:${topic},\\"`);
  489. }
  490. }
  491. }catch(err){
  492. error.push(topic);
  493. console.error(err);
  494. continue;
  495. }
  496. data.push({
  497. topic,
  498. dayAccessCount,
  499. peakAccessCount
  500. });
  501. }
  502. showResultKafka(data);
  503. console.log(error);
  504. let csvData = [["查询 topic", "全天请求次数", "晚高峰请求次数"]];
  505. data.forEach(record => csvData.push([record.topic, record.dayAccessCount, record.peakAccessCount]));
  506. exportCSV(csvData, "topic.csv");
  507. } finally {
  508. state.running = false;
  509. }
  510. }, "Random");
  511.  
  512.  
  513. function exportCSV(data, filename) {
  514. let csv = data.map(row => row.join(',')).join('\n');
  515. let blob = new Blob([csv], {
  516. type: 'text/csv;charset=utf-8;'
  517. });
  518. let link = document.createElement('a');
  519. link.href = URL.createObjectURL(blob);
  520. link.download = filename;
  521. link.click();
  522. }
  523.  
  524. function showResultKafka(data) {
  525. console.log("result", data);
  526. let eleBox = parseDom(`<div id="_sls_result_box_" style="padding: 12px; background: white; border-radius: 16px; position: fixed; z-index: 999; top: 0; bottom:0; left: 0; right: 0; margin: auto auto; width: fit-content; height: fit-content; box-shadow: rgba(0, 0, 0, 0.3) 0 19px 38px, rgba(0, 0, 0, 0.22) 0 15px 12px; display: flex; flex-direction: column; align-items: center;"></div>`)
  527. let eleTable = parseDom(`<table style="background: white; border: 1px solid #818181; border-collapse: collapse;"></table>`);
  528. let eleThead = document.createElement('thead');
  529. let eleTbody = document.createElement('tbody');
  530. eleTable.appendChild(eleThead);
  531. eleTable.appendChild(eleTbody);
  532. eleBox.appendChild(eleTable);
  533. let eleButton = parseDom(`<button onclick="window.closeResult()" style="background: #00adff; margin-top: 16px; border: 0; border-radius: 8px; padding: 4px 24px; color: white;">关闭</button>`)
  534. eleBox.appendChild(eleButton);
  535.  
  536. // 表头
  537. let eleTr = document.createElement('tr');
  538. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>查询 topic</th>"));
  539. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>全天请求次数</th>"));
  540. eleTr.append(parseDom("<th style='padding: 8px 16px; border: 1px solid #818181'>晚高峰请求次数</th>"));
  541. eleThead.appendChild(eleTr);
  542.  
  543. // 表内容
  544. for (let item of data) {
  545. eleTr = document.createElement('tr');
  546. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'>${item.topic}</td>`));
  547. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'>${item.dayAccessCount}</td>`));
  548. eleTr.append(parseDom(`<td style='padding: 8px 16px; border: 1px solid #818181'>${item.peakAccessCount}</td>`));
  549. eleTbody.appendChild(eleTr);
  550. }
  551.  
  552. document.body.appendChild(eleBox);
  553. state.eleBox = eleBox;
  554.  
  555. GM_notification({
  556. title: "有咖互动接口数据统计",
  557. text: "统计完成",
  558. timeout: 3000,
  559. });
  560. }