174 lines
4.1 KiB
JavaScript
174 lines
4.1 KiB
JavaScript
|
|
"use strict";
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Prompt 解析器 - 从命令输出中提取指标
|
|||
|
|
*
|
|||
|
|
* 分层策略:
|
|||
|
|
* 1. 正则匹配(快,简单场景够用)
|
|||
|
|
* 2. 返回原始输出(解析失败时让用户看原始数据)
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 华为/H3C 交换机命令解析配置
|
|||
|
|
*/
|
|||
|
|
const HUAWEI_H3C_PATTERNS = {
|
|||
|
|
cpu_usage: {
|
|||
|
|
// CPU 使用率:多种可能的格式
|
|||
|
|
patterns: [
|
|||
|
|
/CPU\s+Usage\s*:\s*(\d+)%/i,
|
|||
|
|
/CPU\s+utilization.*one\s+minute:\s*(\d+)%/i,
|
|||
|
|
/CPU\s+Usage\s+:\s*(\d+)%/i,
|
|||
|
|
],
|
|||
|
|
default: null,
|
|||
|
|
},
|
|||
|
|
memory_usage: {
|
|||
|
|
// 内存使用率:多种格式
|
|||
|
|
patterns: [
|
|||
|
|
/Memory\s+Using\s+Percentage\s+Is:\s*(\d+)%/i,
|
|||
|
|
/Memory\s+utilization.*:\s*(\d+)%/i,
|
|||
|
|
],
|
|||
|
|
default: null,
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 解析单行指标
|
|||
|
|
* @param {string} output - 命令原始输出
|
|||
|
|
* @param {object} config - { patterns: RegExp[], default: any }
|
|||
|
|
* @returns {any} 解析结果
|
|||
|
|
*/
|
|||
|
|
function parseMetric(output, config) {
|
|||
|
|
if (!output || !config?.patterns) return config?.default ?? null;
|
|||
|
|
|
|||
|
|
for (const pattern of config.patterns) {
|
|||
|
|
const match = output.match(pattern);
|
|||
|
|
if (match) {
|
|||
|
|
return parseFloat(match[1]);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return config.default ?? null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 解析端口状态
|
|||
|
|
* @param {string} output - 命令输出
|
|||
|
|
* @returns {object} { up_count, down_count, ports }
|
|||
|
|
*/
|
|||
|
|
function parseInterfaceBrief(output) {
|
|||
|
|
const lines = output.split("\n");
|
|||
|
|
const ports = [];
|
|||
|
|
let upCount = 0;
|
|||
|
|
let downCount = 0;
|
|||
|
|
|
|||
|
|
for (const line of lines) {
|
|||
|
|
// 匹配端口行:GigabitEthernet0/0/1 up up
|
|||
|
|
const portMatch = line.match(/^(GigabitEthernet|FastEthernet|Ethernet)(\S+)\s+(\w+)\s+(\w+)/);
|
|||
|
|
if (portMatch) {
|
|||
|
|
const phy = portMatch[3].toLowerCase();
|
|||
|
|
const proto = portMatch[4].toLowerCase();
|
|||
|
|
ports.push({
|
|||
|
|
name: portMatch[1] + portMatch[2],
|
|||
|
|
phy,
|
|||
|
|
protocol: proto,
|
|||
|
|
is_up: phy === "up" && proto === "up",
|
|||
|
|
});
|
|||
|
|
if (phy === "up") upCount++;
|
|||
|
|
else downCount++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { up_count: upCount, down_count: downCount, ports };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 解析电源状态
|
|||
|
|
* @param {string} output - 命令输出
|
|||
|
|
* @returns {object} { normal_count, abnormal_count }
|
|||
|
|
*/
|
|||
|
|
function parsePowerStatus(output) {
|
|||
|
|
const lines = output.split("\n");
|
|||
|
|
let normalCount = 0;
|
|||
|
|
let abnormalCount = 0;
|
|||
|
|
|
|||
|
|
for (const line of lines) {
|
|||
|
|
// 匹配电源状态行
|
|||
|
|
if (/Normal|Supply|OK/i.test(line)) {
|
|||
|
|
normalCount++;
|
|||
|
|
} else if (/Absent|Fault|Error/i.test(line)) {
|
|||
|
|
abnormalCount++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { normal_count: normalCount, abnormal_count: abnormalCount };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 清理交换机输出
|
|||
|
|
* @param {string} output - 原始输出
|
|||
|
|
* @returns {string} 清理后的输出
|
|||
|
|
*/
|
|||
|
|
function cleanOutput(output) {
|
|||
|
|
return output
|
|||
|
|
// 移除提示符
|
|||
|
|
.replace(/<\w+[-A-Za-z0-9]*>/g, "")
|
|||
|
|
// 移除分页标记
|
|||
|
|
.replace(/---- More ----/g, "")
|
|||
|
|
// 移除命令回显
|
|||
|
|
.replace(/^[^\r\n]*\r?\n/, "")
|
|||
|
|
// 移除空行
|
|||
|
|
.replace(/\n{3,}/g, "\n\n")
|
|||
|
|
.trim();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 使用 prompt 风格解析交换机输出
|
|||
|
|
* @param {string} output - 原始命令输出
|
|||
|
|
* @param {object} context - { catalog_id, device_info }
|
|||
|
|
* @returns {object} 结构化指标
|
|||
|
|
*/
|
|||
|
|
function parseSwitchOutput(output, context = {}) {
|
|||
|
|
const cleaned = cleanOutput(output);
|
|||
|
|
const lines = cleaned.split("\n");
|
|||
|
|
|
|||
|
|
const metrics = {
|
|||
|
|
cpu_usage: null,
|
|||
|
|
memory_usage: null,
|
|||
|
|
port_status: [],
|
|||
|
|
power_status: [],
|
|||
|
|
fan_status: [],
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 解析 CPU
|
|||
|
|
metrics.cpu_usage = parseMetric(cleaned, HUAWEI_H3C_PATTERNS.cpu_usage);
|
|||
|
|
|
|||
|
|
// 解析内存
|
|||
|
|
metrics.memory_usage = parseMetric(cleaned, HUAWEI_H3C_PATTERNS.memory_usage);
|
|||
|
|
|
|||
|
|
// 解析端口
|
|||
|
|
metrics.port_status = parseInterfaceBrief(cleaned);
|
|||
|
|
|
|||
|
|
// 解析电源
|
|||
|
|
metrics.power_status = parsePowerStatus(cleaned);
|
|||
|
|
|
|||
|
|
// 原始输出(便于调试)
|
|||
|
|
metrics._raw_output = cleaned;
|
|||
|
|
metrics._parse_errors = [];
|
|||
|
|
|
|||
|
|
if (metrics.cpu_usage === null) {
|
|||
|
|
metrics._parse_errors.push("cpu_usage: 无法解析");
|
|||
|
|
}
|
|||
|
|
if (metrics.memory_usage === null) {
|
|||
|
|
metrics._parse_errors.push("memory_usage: 无法解析");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return metrics;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = {
|
|||
|
|
parseMetric,
|
|||
|
|
parseInterfaceBrief,
|
|||
|
|
parsePowerStatus,
|
|||
|
|
cleanOutput,
|
|||
|
|
parseSwitchOutput,
|
|||
|
|
};
|