1. 背景环境

本次问题发生在以下环境中:

  • SmartX SMTX OS:6.2.0 P4
  • CloudTower:4.7.1
  • Zabbix:7.4.6
  • 模板文件:zabbix_metric_template.xml

监控方式为 Zabbix 通过 SNMP 抓取设备/系统信息

2. 问题现象

在 Zabbix 前端查看监控项时,发现某些虚拟机名称字段显示为一串十六进制字节,例如:

E6 B5 8B E8 AF 95 E8 99 9A E6 8B 9F E6 9C BA

而不是预期的中文字符串。

3. 原因分析

该现象通常不是“乱码”,而是:

  • SNMP 返回值类型为 OctetString(字节串)
  • Zabbix(或 SNMP 工具)在展示时,将其以 HEX 字节格式显示
  • 其中 E6 B5 8B ... 这一段本质是 UTF-8 编码的中文

例如上面的 HEX 字节解码后实际含义为:

测试虚拟机

4. 影响范围

该问题主要影响:

  • 监控项(Item)值展示不友好,无法直接阅读
  • Trigger / 报警消息中引用该字段时可读性差
  • Dashboard、报表、告警通知等场景中信息不直观

但不影响 SNMP 本身通信,属于 显示/编码处理问题

5. 解决方案(Zabbix 预处理 HEX → UTF-8)

5.1 适用条件

该方案适用于以下情况:

  • 监控项返回值为 “HEX 字节字符串”
  • 中文内容为 UTF-8 编码
  • 英文内容正常,不希望误处理英文

5.2 配置步骤

进入 Zabbix 前端:

Configuration → Hosts → Items → 选择对应 Item → Preprocessing → Add → JavaScript

粘贴以下脚本:

function isHexBytesString(s) {
  var t = s.trim();
  if (t.length < 2) return false;
  if (!/^[0-9A-Fa-f\s:,-]+$/.test(t)) return false;

  var hex = t.replace(/[^0-9A-Fa-f]/g, '');
  if (hex.length < 2) return false;
  if (hex.length % 2 !== 0) return false;

  // Only convert when there is at least one byte >= 0x80 (likely UTF-8)
  for (var i = 0; i < hex.length; i += 2) {
    var b = parseInt(hex.substr(i, 2), 16);
    if (b >= 0x80) return true;
  }
  return false;
}

function hexToBytes(s) {
  var hex = s.trim().replace(/[^0-9A-Fa-f]/g, '');
  var bytes = [];
  for (var i = 0; i < hex.length; i += 2) {
    bytes.push(parseInt(hex.substr(i, 2), 16));
  }
  return bytes;
}

function utf8DecodeStrict(bytes) {
  var out = '';
  for (var i = 0; i < bytes.length; ) {
    var b0 = bytes[i++] & 0xFF;

    if (b0 < 0x80) {
      out += String.fromCharCode(b0);
      continue;
    }

    if ((b0 & 0xE0) === 0xC0) {
      if (i >= bytes.length) throw "truncated";
      var b1 = bytes[i++] & 0xFF;
      if ((b1 & 0xC0) !== 0x80) throw "invalid";
      var cp = ((b0 & 0x1F) << 6) | (b1 & 0x3F);
      out += String.fromCharCode(cp);
      continue;
    }

    if ((b0 & 0xF0) === 0xE0) {
      if (i + 1 >= bytes.length) throw "truncated";
      var b1_3 = bytes[i++] & 0xFF;
      var b2_3 = bytes[i++] & 0xFF;
      if ((b1_3 & 0xC0) !== 0x80 || (b2_3 & 0xC0) !== 0x80) throw "invalid";
      var cp3 = ((b0 & 0x0F) << 12) | ((b1_3 & 0x3F) << 6) | (b2_3 & 0x3F);
      out += String.fromCharCode(cp3);
      continue;
    }

    if ((b0 & 0xF8) === 0xF0) {
      if (i + 2 >= bytes.length) throw "truncated";
      var b1_4 = bytes[i++] & 0xFF;
      var b2_4 = bytes[i++] & 0xFF;
      var b3_4 = bytes[i++] & 0xFF;
      if ((b1_4 & 0xC0) !== 0x80 || (b2_4 & 0xC0) !== 0x80 || (b3_4 & 0xC0) !== 0x80) throw "invalid";

      var cp4 = ((b0 & 0x07) << 18) | ((b1_4 & 0x3F) << 12) | ((b2_4 & 0x3F) << 6) | (b3_4 & 0x3F);
      cp4 -= 0x10000;
      var high = 0xD800 + ((cp4 >> 10) & 0x3FF);
      var low  = 0xDC00 + (cp4 & 0x3FF);
      out += String.fromCharCode(high, low);
      continue;
    }

    throw "invalid";
  }
  return out;
}

var s = (value === null || value === undefined) ? '' : String(value);

if (!isHexBytesString(s)) {
  return s;
}

try {
  var bytes = hexToBytes(s);
  return utf8DecodeStrict(bytes);
} catch (e) {
  return s;
}
Zabbix SNMP 获取SMTX OS虚拟机中文名称显示为乱码的处理方式

7. 注意事项

  • 如果 SNMP 返回的是 GBK 编码而非 UTF-8,该脚本无法正确解码,需要源端改 UTF-8 或额外转码方案
  • 建议该 Item 的 Value type 设置为 Text
  • 若该字段用于自动发现(LLD),建议在 LLD 的宏生成前完成预处理,避免宏内容异常

8. 总结

Zabbix 通过 SNMP 获取到的“HEX 字节串”通常并非数据异常,而是 字符串展示形式问题。通过 Zabbix 的 JavaScript 预处理将 HEX 按 UTF-8 解码,即可在图表、仪表盘、告警通知中正常显示中文内容。

相关新闻

联系我们

联系我们

400-0512-768

邮件:support@sworditsys.com

工作时间:周一至周五 8:00 - 21:00

分享本页
返回顶部