lepaoProxyLogDisplay.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /**
  2. * 管理员列表:可读摘要 + Arco Tag 色号(与设计约定一致)。
  3. */
  4. function parseDetail(raw) {
  5. if (raw == null || raw === '') return {}
  6. if (typeof raw === 'object') return raw
  7. try {
  8. return JSON.parse(raw)
  9. } catch {
  10. return { _text: String(raw) }
  11. }
  12. }
  13. const EVENT_META = {
  14. fetch: { label: '提取 IP', color: 'green' },
  15. invalidate: { label: '作废缓存', color: 'orangered' },
  16. fallback_direct: { label: '回退直连', color: 'red' },
  17. config_change: { label: '配置变更', color: 'arcoblue' },
  18. proxy_self_check: { label: '代理自检', color: 'purple' },
  19. proxy_self_check_skip: { label: '自检跳过', color: 'gray' },
  20. proxy_self_check_fail: { label: '自检失败', color: 'red' }
  21. }
  22. function summarizeLogRow(record) {
  23. const event = record.event
  24. const d = parseDetail(record.detail)
  25. const lines = []
  26. if (event === 'fetch') {
  27. if (d.request_id) lines.push(`请求 ID:${d.request_id}`)
  28. if (d.code) lines.push(`接口状态:${d.code}`)
  29. } else if (event === 'invalidate') {
  30. if (d.reason) lines.push(`原因:${d.reason}`)
  31. if (d.message) lines.push(`说明:${d.message}`)
  32. if (d.code) lines.push(`错误码:${d.code}`)
  33. if (d.status) lines.push(`HTTP:${d.status}`)
  34. } else if (event === 'fallback_direct') {
  35. if (d.trace_id) lines.push(`任务 trace:${d.trace_id}`)
  36. if (d.mq_task_id) lines.push(`MQ 任务 id:${d.mq_task_id}`)
  37. if (d.reason) lines.push(`触发原因:${d.reason}`)
  38. if (d.reason === 'exhausted_proxy_then_direct') {
  39. lines.push('多轮提取与经代理 POST 均未成功,已改直连接口')
  40. } else if (d.message) {
  41. lines.push(`说明:${d.message}`)
  42. }
  43. if (d.after) lines.push(`阶段:${d.after}`)
  44. if (d.code) lines.push(`错误码:${d.code}`)
  45. } else if (event === 'config_change') {
  46. if (d.project_scope_key) lines.push(`作用项目:${d.project_scope_key}`)
  47. lines.push(`代理开关:${d.proxy_enabled === 1 ? '开' : '关'}`)
  48. if (d.area !== undefined) lines.push(`地区 area:「${d.area || '(空)'}」`)
  49. if (d.area_ex !== undefined) lines.push(`排除 area_ex:「${d.area_ex || '(空)'}」`)
  50. if (d.isp !== undefined) lines.push(`运营商 isp:${d.isp ?? '不限'}`)
  51. if (d.distinct_extract !== undefined) lines.push(`去重提取:${d.distinct_extract ? '是' : '否'}`)
  52. if (d.invalidate_cache) lines.push('已勾选清空服务端 IP 缓存')
  53. if (d.operator) lines.push(`操作者 UUID:${d.operator}`)
  54. } else if (event === 'proxy_self_check') {
  55. if (d.proxy_ip) lines.push(`代理出口IP:${d.proxy_ip}`)
  56. if (d.http_status !== undefined) lines.push(`HTTP:${d.http_status}`)
  57. if (d.target) lines.push(`目标:${d.target}`)
  58. } else if (event === 'proxy_self_check_skip') {
  59. if (d.reason) lines.push(`原因:${d.reason}`)
  60. } else if (event === 'proxy_self_check_fail') {
  61. if (d.message) lines.push(`说明:${d.message}`)
  62. if (d.code) lines.push(`错误码:${d.code}`)
  63. if (d.status !== undefined) lines.push(`HTTP:${d.status}`)
  64. } else if (Object.keys(d).length) {
  65. if (d._text) lines.push(String(d._text))
  66. else {
  67. Object.keys(d).slice(0, 6).forEach(k => {
  68. lines.push(`${k}:${typeof d[k] === 'object' ? JSON.stringify(d[k]) : d[k]}`)
  69. })
  70. }
  71. }
  72. let summary = lines.length ? lines.join(';') : '—'
  73. const meta = EVENT_META[event] || { label: event || '未知', color: 'gray' }
  74. const serverShown = record.server ? `节点 ${record.server}` : ''
  75. return {
  76. event_label: meta.label,
  77. event_color: meta.color,
  78. summary,
  79. detail_lines: lines,
  80. server_tip: serverShown || null,
  81. ...(record.server && record.deadline ? { deadline_tip: `${record.server} · ${record.deadline}` } : {})
  82. }
  83. }
  84. /**
  85. * 青果语义下的出口 IP(proxy_ip),非代理节点 host。
  86. */
  87. function extractEgressIp(record) {
  88. const d = parseDetail(record.detail)
  89. const p = d.proxy_ip
  90. if (p === null || p === undefined || p === '') return null
  91. const s = String(p).trim()
  92. return /^(\d{1,3}\.){3}\d{1,3}$/.test(s) ? s : null
  93. }
  94. module.exports = {
  95. summarizeLogRow,
  96. parseDetail,
  97. EVENT_META,
  98. extractEgressIp
  99. }