夜莺-Nightingale
夜莺V7
项目介绍 功能概览
部署升级 部署升级
数据接入 数据接入
告警管理 告警管理
数据查看 数据查看
功能介绍 功能介绍
API FAQ
夜莺V6
项目介绍 架构介绍
快速开始 快速开始
黄埔营
安装部署 安装部署
升级
采集器 采集器
使用手册 使用手册
API API
数据库表结构 数据库表结构
FAQ FAQ
开源生态
Prometheus
版权声明
第1章:天降奇兵 第1章:天降奇兵
第2章:探索PromQL 第2章:探索PromQL
第3章:Prometheus告警处理 第3章:Prometheus告警处理
第4章:Exporter详解 第4章:Exporter详解
第5章:数据与可视化 第5章:数据与可视化
第6章:集群与高可用 第6章:集群与高可用
第7章:Prometheus服务发现 第7章:Prometheus服务发现
第8章:监控Kubernetes 第8章:监控Kubernetes
第9章:Prometheus Operator 第9章:Prometheus Operator
参考资料

snmp_zabbix插件

SNMP_Zabbix 插件用户文档

一、插件概述

1.1 插件功能介绍

snmp_zabbix 是一款兼容Zabbix采集模板的SNMP 数据采集插件,其最大特色是能够直接使用 Zabbix 的 YAML 格式模板文件。这意味着您可以利用 Zabbix 丰富的模板生态系统,无需重新编写监控配置。 主要功能包括:

  • 完整的 SNMP 协议支持:支持 SNMPv1、v2c、v3 所有版本
  • Zabbix 模板兼容:直接使用 Zabbix 6.0+ 的 YAML 格式模板
  • 自动发现机制:自动发现网络接口、文件系统等资源并动态创建监控项
  • 强大的预处理:支持正则表达式、JavaScript、数值计算等多种数据预处理方式
  • 精细化的调度:支持item粒度调度采集任务
  • 健康检查与自动恢复:自动检测连接状态并重连

1.2 与snmp 插件的区别

特性 SNMP_Zabbix 插件 SNMP 插件
配置方式 Zabbix 模板 + 简单配置 手动配置每个 OID
自动发现 支持 LLD(低级别发现) 需手动配置
预处理 支持 20+ 种预处理方式 基本数值转换
模板复用 可直接使用 Zabbix 模板库 需从零开始
配置复杂度 低(使用现成模板) 高(逐个配置)
动态监控项 支持(通过发现规则) 不支持

1.3 适用场景

从 Zabbix 迁移到 Categraf,希望复用现有监控模板 需要监控大量网络设备(交换机、路由器、防火墙等) 需要动态发现和监控变化的资源(如网络接口) 需要对采集数据进行复杂预处理 希望利用 Zabbix 社区丰富的模板资源

1.4 系统要求和依赖

  • Categraf 版本:开源版 >= v0.4.24 企业版 >= v0.4.40
  • 网络要求:能够访问目标 SNMP 设备的 UDP (默认161) 端口
  • 目标设备:启用 SNMP 服务的网络设备或服务器
  • 模板要求:Zabbix 6.0+ 及以上的YAML 格式模板(不支持旧版 XML 格式)

二、Zabbix 模板获取与管理

2.1 什么是 Zabbix 模板

Zabbix 模板是预定义的监控配置集合,包含了监控项、发现规则、触发器等配置。每个模板针对特定类型的设备或服务,如 “Cisco Switch”、“Linux SNMP” 等。

2.2 获取模板的方式

2.2.1 从 Zabbix Web 界面导出

  • 步骤 1:登录 Zabbix Web 界面 比如,https://your-zabbix-server/

  • 步骤2: 导航到模板页面 数据采集(Data Collection) -> 模板(Templates)

  • 步骤 3:选择要导出的模板 勾选需要导出的模板(可多选),点击底部"导出(Export)“按钮

  • 步骤 4:选择导出格式 重要:选择 “YAML” 格式(Zabbix 6.0+),如果只有 XML 选项,说明 Zabbix 版本过低

  • 步骤 5:保存文件 文件将自动下载,默认名称如:zbx_export_templates.yaml

2.2.2 使用 Zabbix API 导出

方法 1:使用 curl 命令

# 1. 获取认证 token
# 7.0 以上版本, 请参考https://flashcat.cloud/blog/zabbix-to-flashcat/ 如何申请api token
# 以下接口均在7.2版本上验证, 7.0 以下版本接口和参数可能有些差异,请自行查询zabbix官网文档

# 2. 获取模板 ID
curl -s -X POST \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $TOKEN" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"template.get\",
    \"params\": {
      \"output\": [\"templateid\", \"name\"],
      \"filter\": {
        \"name\": [\"Template Net Cisco IOS SNMPv2\"]
      }
    },
    \"id\": 2
  }" \
  http://your-zabbix-server/api_jsonrpc.php | jq .

# 3. 导出模板(获取到 templateid 后)
curl -s -X POST \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $TOKEN" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"configuration.export\",
    \"params\": {
      \"format\": \"yaml\",
      \"options\": {
        \"templates\": [\"10255\"]
      }
    },
    \"id\": 3
  }" \
  http://your-zabbix-server/api_jsonrpc.php | jq -r .result > template_cisco.yaml

2.2.3 使用官方/社区模板

访问 Zabbix Git 仓库:

# 克隆整个模板仓库,从仓库中拷贝相关 yaml 文件
git clone git@github.com:zabbix/zabbix.git

# 或者直接下载特定模板
wget https://github.com/zabbix/zabbix/blob/master/templates/net/cisco/cisco_snmp/template_net_cisco_snmp.yaml

常用网络设备模板推荐:

设备类型 模板名称 文件路径
Cisco 交换机 Cisco IOS by SNMP templates/net/cisco/cisco_snmp/template_net_cisco_snmp.yaml
Huawei 交换机 Huawei VRP by SNMP templates/net/huawei_snmp/template_net_huawei_snmp.yaml
HP 交换机 HP Enterprise Switch by SNMP templates/net/hp_hpn_snmp/template_net_hp_hpn_snmp.yaml
Linux 服务器 Linux by SNMP templates/os/linux_snmp_snmp/template_os_linux_snmp_snmp.yaml
Windows 服务器 Windows by SNMP templates/os/windows_snmp/template_os_windows_snmp.yaml
通用网络设备 Network Generic Device by SNMP templates/net/generic_snmp/template_net_generic_snmp.yaml

2.3 模板文件格式转换(XML to YAML)

如果只有 XML 格式的模板,需要进行转换:

  1. 把 XML 模板导入 Zabbix
  2. 重新导出为 YAML 格式的模板

三、Zabbix 模板结构详解

3.1 模板基本结构

一个典型的 Zabbix YAML 模板结构如下:

zabbix_export:
  version: '7.0'
  date: '2024-01-15T10:00:00Z'
  templates:
    - template: Template Net Example Device
      name: Template Net Example Device
      description: Template for monitoring example network device
      groups:
        - name: Templates/Network devices
      items:           # 监控项
        - name: Interface {#IFNAME} incoming traffic
          type: SNMP_AGENT
          snmp_oid: .1.3.6.1.2.1.2.2.1.10.{#SNMPINDEX}
          key: net.if.in[{#IFNAME}]
          delay: 60s
          value_type: UNSIGNED
          units: bps
          preprocessing:
            - type: CHANGE_PER_SECOND
      discovery_rules:  # 发现规则
        - name: Network interfaces discovery
          type: SNMP_AGENT
          snmp_oid: discovery[{#IFNAME},.1.3.6.1.2.1.2.2.1.2]
          key: net.if.discovery
          delay: 1h
          filter:
            conditions:
              - macro: '{#IFNAME}'
                value: '{$NET.IF.NAME.MATCHES}'
                #value: '^(eth|bond|eno|ens)' # 直接这么写也行,上一行的写法只是为了用户宏的说明
                operator: MATCHES_REGEX
          item_prototypes:  # 项目原型
            - name: 'Interface {#IFNAME}: Bits received'
              type: SNMP_AGENT
              snmp_oid: .1.3.6.1.2.1.2.2.1.10.{#SNMPINDEX}
              key: net.if.in[{#IFNAME}]
      macros:          # 用户宏
        - macro: '{$NET.IF.NAME.MATCHES}'
          value: '^(eth|bond|eno|ens)'

3.2 核心配置项说明

3.2.1 Items(监控项)

监控项定义了要采集的具体指标:

items:
  - name: CPU utilization         # 监控项名称(用于显示)
    type: SNMP_AGENT              # 类型(插件只处理 SNMP_AGENT)
    snmp_oid: .1.3.6.1.4.1.9.9.109.1.1.1.1.7.1  # SNMP OID
    key: system.cpu.util          # 唯一标识符
    value_type: FLOAT             # 数据类型
    units: '%'                    # 单位
    delay: 30s                    # 采集间隔
    preprocessing:                # 预处理步骤
      - type: MULTIPLIER
        parameters: ['0.01']      # 乘以 0.01 转换为百分比

Type 类型说明:

  • SNMP_AGENT:SNMPv2c(插件支持)
  • SNMPV1_AGENT:SNMPv1(插件支持)
  • SNMPV3_AGENT:SNMPv3(插件支持)
  • 其他类型(如 ZABBIX_AGENT、HTTP_AGENT):插件忽略

Value_type 数据类型:

  • FLOAT:浮点数
  • CHAR:字符(作为标签处理)
  • LOG:日志
  • UNSIGNED:无符号整数
  • TEXT:文本(作为标签处理)

Units 单位处理: 常见单位:

  • B、KB、MB、GB:字节单位
  • bps、Kbps、Mbps:速率单位
  • %:百分比
  • ms、s:时间单位

3.2.2 Discovery Rules(发现规则)

发现规则用于动态发现资源并创建监控项:

discovery_rules:
  - name: Network interfaces discovery
    type: SNMP_AGENT
    key: net.if.discovery
    delay: 1h                     # 发现间隔
    snmp_oid: discovery[{#IFNAME},.1.3.6.1.2.1.2.2.1.2,{#IFTYPE},.1.3.6.1.2.1.2.2.1.3]
    filter:
      evaltype: AND               # 过滤条件组合方式
      conditions:
        - macro: '{#IFNAME}'
          value: '^eth'
          operator: MATCHES_REGEX
        - macro: '{#IFTYPE}'
          value: '6'              # 以太网接口
          operator: EQUALS
    item_prototypes:              # 基于发现结果创建的监控项
      - name: 'Interface {#IFNAME}: Incoming traffic'
        type: SNMP_AGENT
        snmp_oid: .1.3.6.1.2.1.2.2.1.10.{#SNMPINDEX}
        key: net.if.in[{#IFNAME}]

Delay 采集间隔语法:

  • 30s:30 秒
  • 5m:5 分钟
  • 1h:1 小时
  • 1d:1 天
  • 30:30 秒(纯数字默认为秒) Filter 过滤器详解:

过滤器用于筛选发现的资源,只为符合条件的资源创建监控项。

操作符(operator)类型:

操作符 说明 示例
EQUALS 完全匹配 value: eth0
NOT_EQUALS 不等于 value: lo
LIKE 包含 value: eth
NOT_LIKE 不包含 value: docker
MATCHES_REGEX 正则匹配 value: ^(eth|ens)
NOT_MATCHES_REGEX 正则不匹配 value: ^lo

条件组合方式(evaltype):

AND:所有条件都满足 OR:任一条件满足 FORMULA:自定义表达式

Filter 经典案例:

只监控物理网络接口:

filter:
  evaltype: AND
  conditions:
    - macro: '{#IFNAME}'
      value: '^(eth|eno|ens|em)\d+$'
      operator: MATCHES_REGEX
    - macro: '{#IFADMINSTATUS}'
      value: '1'                  # 管理状态为 UP
      operator: EQUALS

排除虚拟接口和环回接口:

filter:
  evaltype: AND
  conditions:
    - macro: '{#IFNAME}'
      value: '^(lo|docker|virbr|veth)'
      operator: NOT_MATCHES_REGEX
    - macro: '{#IFTYPE}'
      value: '24'                 # 排除环回接口类型
      operator: NOT_EQUALS

只监控特定 VLAN 接口:

filter:
  conditions:
    - macro: '{#IFNAME}'
      value: '\.(100|200|300)$'  # VLAN 100, 200, 300
      operator: MATCHES_REGEX

使用复杂表达式:

filter:
  evaltype: FORMULA
  formula: (A and B) or C
  conditions:
    - macro: '{#IFNAME}'
      value: '^eth'
      operator: MATCHES_REGEX
      formulaid: A
    - macro: '{#IFSPEED}'
      value: '1000000000'         # 1Gbps
      operator: EQUALS
      formulaid: B
    - macro: '{#IFALIAS}'
      value: 'IMPORTANT'
      operator: LIKE
      formulaid: C

3.2.3 Preprocessing(预处理)

预处理步骤在数据存储前对其进行转换:

preprocessing:
  - type: CHANGE_PER_SECOND      # 计算每秒变化率
  - type: MULTIPLIER              # 乘法运算
    parameters: ['8']             # 字节转比特
  - type: REGEX                  # 正则提取
    parameters:
      - 'Temperature: ([\d.]+)'
      - '\1'

支持的预处理类型:

类型 说明 参数示例
MULTIPLIER 乘数 ['0.001']
SIMPLE_CHANGE 简单变化 无参数
CHANGE_PER_SECOND 每秒变化率 无参数
REGEX 正则表达式 ['pattern', 'output']
JSONPATH JSON路径 ['$.value']
SNMP_WALK_TO_JSON SNMP Walk转JSON ['{#MACRO}', 'oid', '0']
HEX_TO_DECIMAL 十六进制转十进制 无参数
JAVASCRIPT JavaScript脚本 ['return value * 100']

3.2.4 Macros(宏)

宏用于动态替换配置中的值

用户宏 {$MACRO}

macros:
  - macro: '{$SNMP.TIMEOUT}'
    value: '5'
  - macro: '{$CPU.UTIL.CRIT}'
    value: '90'

LLD 宏 {#MACRO}

在发现过程中自动填充:

  • {#SNMPINDEX}:SNMP 索引

  • {#IFNAME}:接口名称

  • {#IFTYPE}:接口类型

  • 自定义宏:通过 discovery 配置定义 宏替换机制:

  • 发现阶段:提取 LLD 宏值

  • 展开阶段:将宏替换为实际值

  • 优先级:LLD 宏 > 用户宏 > 默认值

四、插件配置详解

4.1 基础配置

4.1.1 SNMP 连接参数

[[instances]]
# 目标设备列表
agents = [
    "192.168.1.1",                    # 简单 IP
    "192.168.1.2:161",                # 指定端口
    "udp://192.168.1.3:161",          # 指定协议
    "tcp://switch.example.com:161",   # TCP 传输
    "192.168.1.0/24",                 # CIDR 网段(自动扫描)
]

# SNMP 版本(1, 2, 3)
version = 2

# SNMPv1/v2c 参数
community = "public"

# SNMPv3 参数
username = "snmpuser"
security_level = "authPriv"          # noAuthNoPriv, authNoPriv, authPriv
auth_protocol = "SHA"                 # MD5, SHA, SHA224, SHA256, SHA384, SHA512
auth_password = "auth_pass_123"
priv_protocol = "AES"                 # DES, AES, AES192, AES256
priv_password = "priv_pass_456"
context_name = ""

# 连接参数
port = 161                           # 默认 SNMP 端口
timeout = "5s"                        # 超时时间
retries = 3                          # 重试次数
max_repetitions = 10                 # BULK 请求最大重复数

# UDP 套接字模式
unconnected_udp_socket = false       # 使用非连接模式(处理大量设备时更高效)

Agents 配置格式说明:

  • 支持多种格式混合使用
  • CIDR 网段会自动展开为单个 IP
  • 默认使用 UDP 协议和 161 端口

4.1.2 模板加载

方式一:加载外部文件

template_files = [
    "/etc/categraf/templates/cisco_switch.yaml",
    "/etc/categraf/templates/interface_addon.yaml"
]

方式二:内嵌模板内容

[instances.template_file_contents]
# 直接在配置中嵌入模板内容
basic_template = '''
zabbix_export:
  version: '6.0'
  templates:
    - template: Embedded Template
      items:
        - name: System uptime
          type: SNMP_AGENT
          snmp_oid: .1.3.6.1.2.1.1.3.0
          key: system.uptime
'''

多模板合并规则:

  • 后加载的模板覆盖前面的同名项
  • 宏定义按名称合并
  • 发现规则独立处理

4.2 高级配置

4.2.1 发现功能配置

发现功能会自动从模板中读取 discovery_rules,发现调度机制:

  • 每个发现规则按其 delay 独立调度
  • 首次启动时立即执行一次发现
  • 发现结果会缓存,避免重复执行

4.2.2 健康检查

健康检查自动进行,无需配置。默认参数:

  • 检查间隔:30秒
  • 检查超时:5秒
  • 最大重试:3次
  • 自动重连:启用

五、数据类型处理机制

5.1 SNMP 数据类型映射

SNMP PDU 类型 Go 类型 处理方式
Integer int 直接使用
Counter32 uint32 转为 uint64
Counter64 uint64 直接使用
Gauge32 uint32 直接使用
TimeTicks uint32 转换为秒(÷100)
OctetString []byte 自动识别可打印字符串
ObjectIdentifier string 字符串表示
IPAddress string 点分十进制表示
Opaque []byte 十六进制字符串

5.2 特殊类型处理

5.2.1 CHAR/TEXT 类型作为标签

当监控项的 value_type 为 CHAR 或 TEXT 时,插件会将其作为标签而非指标值:

item_prototypes:
  - name: Interface {#IFNAME} alias
    type: SNMP_AGENT
    snmp_oid: .1.3.6.1.2.1.31.1.1.1.18.{#SNMPINDEX}
    key: net.if.alias[{#IFNAME}]
    value_type: TEXT              # 文本类型
    # 这个值会被提取为 "alias" 标签

Label Provider 机制:

  • 识别 CHAR/TEXT 类型的监控项
  • 提取标签键(从 key 中解析,如 net.if.alias -> alias)
  • 缓存标签值并关联到相同索引的其他监控项
  • 在输出指标时自动添加这些标签

对于一些枚举的CHAR或者TEXT类型的item, 最佳实践是通过预处理将其转换为数值。比如

items:
  - name: "Interface {#IFNAME}: Operational status"
    key: "net.if.status[{#IFNAME}]"
    type: SNMP_AGENT
    snmp_oid: ".1.3.6.1.2.1.2.2.1.8.{#SNMPINDEX}"
    value_type: UNSIGNED  # 改为数值类型
    preprocessing:
      - type: JAVASCRIPT
        parameters:
          - |
            // 将 SNMP 返回的状态值转换为标准数值
            // IF-MIB::ifOperStatus 值:
            // 1 = up, 2 = down, 3 = testing, 4 = unknown,
            // 5 = dormant, 6 = notPresent, 7 = lowerLayerDown
            
            var statusMap = {
              '1': 1,  // up -> 1
              '2': 0,  // down -> 0
              '3': 0,  // testing -> 0
              '4': 0,  // unknown -> 0
              '5': 0,  // dormant -> 0
              '6': 0,  // notPresent -> 0
              '7': 0   // lowerLayerDown -> 0
            };
            
            return statusMap[value] !== undefined ? statusMap[value] : 0;            

5.2.2 Counter 类型处理

计数器类型会自动处理溢出:

preprocessing:
  - type: CHANGE_PER_SECOND       # 自动处理计数器溢出
    # 32位计数器最大值:4294967295
    # 64位计数器最大值:18446744073709551615

速率计算公式:

  • 正常情况:(新值 - 旧值) / 时间差
  • 溢出情况:(最大值 - 旧值 + 新值) / 时间差

5.2.3 OctetString 处理

OctetString 的处理取决于内容:

  • 可打印字符串:直接转换为 string
  • 二进制数据:转换为十六进制
  • 特殊处理(通过预处理):
    • MAC 地址:MAC_FORMAT
    • IP 地址:IP_FORMAT
    • 十六进制数值:HEX_TO_DECIMAL

六、自动发现功能

6.1 自动发现流程

1. 执行 SNMP Walk
   ↓
2. 提取索引和宏值
   ↓
3. 应用过滤器
   ↓
4. 生成监控项
   ↓
5. 动态调度采集

6.2 支持的发现类型

6.2.1 网络接口发现

discovery_rules:
  - name: Network interfaces discovery
    snmp_oid: .1.3.6.1.2.1.2.2.1.2     # ifDescr
    # 或使用多 OID 发现
    snmp_oid: discovery[{#IFNAME},.1.3.6.1.2.1.2.2.1.2,{#IFTYPE},.1.3.6.1.2.1.2.2.1.3]

自动生成的宏:

  • {#SNMPINDEX}:接口索引
  • {#IFNAME}:接口名称
  • {#IFTYPE}:接口类型

6.2.2 文件系统发现

discovery_rules:
  - name: Mounted filesystem discovery
    snmp_oid: .1.3.6.1.2.1.25.2.3.1.3  # hrStorageDescr

6.2.3 自定义发现

使用 walk[] 语法执行多个 OID walk:

discovery_rules:
  - name: Custom discovery
    snmp_oid: walk[.1.3.6.1.4.1.9.9.48.1.1.1.2,.1.3.6.1.4.1.9.9.48.1.1.1.5]
    preprocessing:
      - type: SNMP_WALK_TO_JSON
        parameters:
          - '{#VLANID}'
          - '.1.3.6.1.4.1.9.9.48.1.1.1.2'
          - '0'
          - '{#VLANNAME}'
          - '.1.3.6.1.4.1.9.9.48.1.1.1.5'
          - '0'

举个例子,原始 SNMP Walk 数据:

.1.3.6.1.2.1.2.2.1.2.1 = "lo"
.1.3.6.1.2.1.2.2.1.2.2 = "eth0"
.1.3.6.1.2.1.2.2.1.2.3 = "eth1"
.1.3.6.1.2.1.2.2.1.3.1 = 24        # loopback type
.1.3.6.1.2.1.2.2.1.3.2 = 6         # ethernet type
.1.3.6.1.2.1.2.2.1.3.3 = 6         # ethernet type
.1.3.6.1.2.1.2.2.1.5.1 = 10000000  # 10 Mbps
.1.3.6.1.2.1.2.2.1.5.2 = 1000000000 # 1 Gbps
.1.3.6.1.2.1.2.2.1.5.3 = 10000000000 # 10 Gbps

配置:

discovery_rules:
  - name: Network interface discovery
    type: SNMP_AGENT
    key: net.if.discovery
    # 使用 walk[] 语法执行多个 OID walk
    snmp_oid: walk[.1.3.6.1.2.1.2.2.1.2,.1.3.6.1.2.1.2.2.1.3,.1.3.6.1.2.1.2.2.1.5]
    preprocessing:
      - type: SNMP_WALK_TO_JSON
        parameters:
          - '{#IFNAME}'                # 宏名称
          - '.1.3.6.1.2.1.2.2.1.2'     # OID 基础
          - '0'                        # 批量提取标志 (0=单个值)
          - '{#IFTYPE}'                # 第二个宏
          - '.1.3.6.1.2.1.2.2.1.3'     # 第二个 OID
          - '0'
          - '{#IFSPEED}'               # 第三个宏
          - '.1.3.6.1.2.1.2.2.1.5'     # 第三个 OID
          - '0'

生成的 JSON:

[
  {
    "{#SNMPINDEX}": "1",
    "{#IFNAME}": "lo",
    "{#IFTYPE}": "24",
    "{#IFSPEED}": "10000000"
  },
  {
    "{#SNMPINDEX}": "2",
    "{#IFNAME}": "eth0",
    "{#IFTYPE}": "6",
    "{#IFSPEED}": "1000000000"
  },
  {
    "{#SNMPINDEX}": "3",
    "{#IFNAME}": "eth1",
    "{#IFTYPE}": "6",
    "{#IFSPEED}": "10000000000"
  }
]

6.3 发现数据处理流程

6.3.1 OID Walk 执行

插件使用 BulkWalk 提高效率:

  • 自动处理 SNMP v1 的 Walk
  • v2c/v3 使用 BulkWalk
  • 支持并发多个 OID walk

6.3.2 宏值提取

从 OID 结果中提取:

OID: .1.3.6.1.2.1.2.2.1.2.1 = "eth0"
     └─ 基础 OID ─┘└─索引─┘   └值┘

提取结果:
{#SNMPINDEX} = "1"
{#IFNAME} = "eth0"

6.3.3 过滤器应用

按照 filter 配置筛选发现的项目(见 3.2.2 Filter 部分)

6.3.4 监控项生成

基于 item_prototypes 和宏值生成实际监控项:

模板:net.if.in[{#IFNAME}]
宏值:{#IFNAME} = "eth0"
结果:net.if.in[eth0]

七、预处理功能详解

7.1 支持的预处理类型列表

类型 用途 示例
MULTIPLIER 数值乘法 字节转比特(×8)
SIMPLE_CHANGE 简单变化 当前值-上次值
CHANGE_PER_SECOND 速率计算 流量速率
REGEX 正则提取 从字符串提取数值
JSONPATH JSON解析 提取JSON字段
TRIM/LTRIM/RTRIM 字符串修剪 去除空白
JAVASCRIPT JS脚本 复杂逻辑处理
HEX_TO_DECIMAL 进制转换 0xFF -> 255
MAC_FORMAT MAC格式化 标准化MAC地址
IP_FORMAT IP格式化 提取IP地址

7.2 常用预处理案例

7.2.1 数值计算

字节转比特:

preprocessing:
  - type: MULTIPLIER
    parameters: ['8']

百分比转换:

preprocessing:
  - type: MULTIPLIER
    parameters: ['0.01']     # 如果原值是 0-10000,转为 0-100

计算速率:

preprocessing:
  - type: CHANGE_PER_SECOND  # 自动计算每秒变化

7.2.2 字符串处理

提取温度数值:

preprocessing:
  - type: REGEX
    parameters:
      - 'Temperature: ([\d.]+)°C'
      - '\1'

去除空白:

preprocessing:
  - type: TRIM               # 去除前后空白

7.2.3 格式转换

MAC 地址格式化:

preprocessing:
  - type: MAC_FORMAT
    parameters: [':']         # 分隔符(默认冒号)
# 输入:001122334455 或 00-11-22-33-44-55
# 输出:00:11:22:33:44:55

十六进制转十进制:

preprocessing:
  - type: HEX_TO_DECIMAL
# 输入:FF 或 0xFF
# 输出:255

7.2.4 JavaScript 脚本

简单计算:

preprocessing:
  - type: JAVASCRIPT
    parameters: ['return value * 100 / 1024']

条件处理:

preprocessing:
  - type: JAVASCRIPT
    parameters:
      - |
        if (value > 1000000) {
            return value / 1000000;  // 转为 MB
        }
        return value / 1000;         // 转为 KB        

字符串处理:

preprocessing:
  - type: JAVASCRIPT
    parameters:
      - 'return value.toLowerCase().replace(/\s+/g, "_")'

7.2.5 JSONPath 提取

提取 JSON 字段:

preprocessing:
  - type: JSONPATH
    parameters: ['$.temperature.value']

提取数组元素:

preprocessing:
  - type: JSONPATH
    parameters: ['$.interfaces[0].name']

八、实际配置示例

8.1 最小化配置示例

# /etc/categraf/conf/inputs.snmp_zabbix/snmp_zabbix.toml

[[instances]]
# 最简配置:监控单个设备的系统信息
agents = ["192.168.1.1"]
version = 2
community = "public"
template_files = ["/etc/categraf/templates/basic_system.yaml"]

对应的最简模板:

# /etc/categraf/templates/basic_system.yaml
zabbix_export:
  version: '6.0'
  templates:
    - template: Basic System
      items:
        - name: System uptime
          type: SNMP_AGENT
          snmp_oid: .1.3.6.1.2.1.1.3.0
          key: system.uptime
          value_type: UNSIGNED
          preprocessing:
            - type: MULTIPLIER
              parameters: ['0.01']  # TimeTicks to seconds

8.2 完整配置示例

# /etc/categraf/conf/inputs.snmp_zabbix/snmp_zabbix.toml

[[instances]]
# 基础标签
labels = { region = "beijing", env = "production" }

# SNMP 连接配置
agents = [
    "192.168.1.0/24",           # 扫描整个网段
    "core-switch.example.com"   # 域名
]
version = 2
community = "public"
port = 161
timeout = "5s"
retries = 3
max_repetitions = 25

# 加载多个模板(会自动合并)
template_files = [
    "/etc/categraf/templates/cisco_catalyst.yaml",
    "/etc/categraf/templates/custom_oids.yaml"
]

# 设备映射标签
[instances.mappings]
"192.168.1.1" = { device_name = "core-sw-01", location = "DC1" }
"192.168.1.2" = { device_name = "core-sw-02", location = "DC2" }

8.3 常见场景配置

8.3.1 交换机端口监控

[[instances]]
agents = ["192.168.1.1"]
version = 2
community = "public"

# 使用 Cisco 官方模板
template_files = ["/etc/categraf/templates/net/cisco/cisco_snmp/template_net_cisco_snmp.yaml"]

# 或内嵌简化模板
[instances.template_file_contents]
switch_interfaces = '''
zabbix_export:
  version: '6.0'
  templates:
    - template: Switch Interfaces
      discovery_rules:
        - name: Interface discovery
          type: SNMP_AGENT
          key: net.if.discovery
          delay: 1h
          snmp_oid: discovery[{#IFNAME},.1.3.6.1.2.1.2.2.1.2,{#IFTYPE},.1.3.6.1.2.1.2.2.1.3,{#IFADMINSTATUS},.1.3.6.1.2.1.2.2.1.7]
          filter:
            evaltype: AND
            conditions:
              - macro: '{#IFTYPE}'
                value: '6'              # Ethernet
                operator: EQUALS
              - macro: '{#IFADMINSTATUS}'
                value: '1'              # UP
                operator: EQUALS
          item_prototypes:
            - name: 'Interface {#IFNAME}: Incoming traffic'
              type: SNMP_AGENT
              snmp_oid: .1.3.6.1.2.1.2.2.1.10.{#SNMPINDEX}
              key: net.if.in[{#IFNAME}]
              value_type: UNSIGNED
              units: bps
              preprocessing:
                - type: CHANGE_PER_SECOND
                - type: MULTIPLIER
                  parameters: ['8']
            - name: 'Interface {#IFNAME}: Outgoing traffic'
              type: SNMP_AGENT
              snmp_oid: .1.3.6.1.2.1.2.2.1.16.{#SNMPINDEX}
              key: net.if.out[{#IFNAME}]
              value_type: UNSIGNED
              units: bps
              preprocessing:
                - type: CHANGE_PER_SECOND
                - type: MULTIPLIER
                  parameters: ['8']
            - name: 'Interface {#IFNAME}: Description'
              type: SNMP_AGENT
              snmp_oid: .1.3.6.1.2.1.31.1.1.1.18.{#SNMPINDEX}
              key: net.if.alias[{#IFNAME}]
              value_type: TEXT          # 作为标签
'''

8.3.2 路由器监控

[[instances]]
agents = ["10.0.0.1"]
version = 3
username = "snmpv3user"
security_level = "authPriv"
auth_protocol = "SHA"
auth_password = "authpass123"
priv_protocol = "AES"
priv_password = "privpass456"

[instances.template_file_contents]
router_template = '''
zabbix_export:
  version: '6.0'
  templates:
    - template: Router Monitoring
      items:
        # CPU 使用率
        - name: CPU utilization
          type: SNMP_AGENT
          snmp_oid: .1.3.6.1.4.1.9.9.109.1.1.1.1.7.1
          key: system.cpu.util
          value_type: FLOAT
          units: '%'
        # 内存使用
        - name: Memory used
          type: SNMP_AGENT
          snmp_oid: .1.3.6.1.4.1.9.9.48.1.1.1.5.1
          key: vm.memory.used
          value_type: UNSIGNED
          units: B
        # 路由表大小
        - name: Routing table size
          type: SNMP_AGENT
          snmp_oid: .1.3.6.1.2.1.4.24.3.0
          key: net.routing.table.size
          value_type: UNSIGNED
      discovery_rules:
        # BGP 邻居发现
        - name: BGP peer discovery
          type: SNMP_AGENT
          key: bgp.peer.discovery
          snmp_oid: .1.3.6.1.2.1.15.3.1.2
          item_prototypes:
            - name: 'BGP peer {#PEER}: State'
              type: SNMP_AGENT
              snmp_oid: .1.3.6.1.2.1.15.3.1.2.{#SNMPINDEX}
              key: bgp.peer.state[{#PEER}]
              value_type: UNSIGNED
'''

8.3.3 存储设备监控

[[instances]]
agents = ["storage.example.com"]
version = 2
community = "public"

[instances.template_file_contents]
storage_template = '''
zabbix_export:
  version: '6.0'
  templates:
    - template: Storage Device
      discovery_rules:
        - name: Storage discovery
          type: SNMP_AGENT
          key: storage.discovery
          delay: 30m
          snmp_oid: discovery[{#STORAGEDESCR},.1.3.6.1.2.1.25.2.3.1.3,{#STORAGETYPE},.1.3.6.1.2.1.25.2.3.1.2]
          filter:
            conditions:
              - macro: '{#STORAGETYPE}'
                value: '.1.3.6.1.2.1.25.2.1.4'  # Fixed disk
                operator: EQUALS
          item_prototypes:
            - name: '{#STORAGEDESCR}: Total space'
              type: SNMP_AGENT
              snmp_oid: .1.3.6.1.2.1.25.2.3.1.5.{#SNMPINDEX}
              key: vfs.fs.size[{#STORAGEDESCR},total]
              value_type: UNSIGNED
              units: B
              preprocessing:
                - type: MULTIPLIER
                  parameters: ['4096']  # 块大小
            - name: '{#STORAGEDESCR}: Used space'
              type: SNMP_AGENT
              snmp_oid: .1.3.6.1.2.1.25.2.3.1.6.{#SNMPINDEX}
              key: vfs.fs.size[{#STORAGEDESCR},used]
              value_type: UNSIGNED
              units: B
              preprocessing:
                - type: MULTIPLIER
                  parameters: ['4096']
            - name: '{#STORAGEDESCR}: Usage in %'
              type: SNMP_AGENT
              snmp_oid: .1.3.6.1.2.1.25.2.3.1.6.{#SNMPINDEX}
              key: vfs.fs.pused[{#STORAGEDESCR}]
              value_type: FLOAT
              units: '%'
              preprocessing:
                - type: JAVASCRIPT
                  parameters:
                    - |
                      var used = value;
                      var total = 1000000;  // 需要从其他地方获取
                      return (used / total) * 100;
'''

8.3.4 打印机监控

[[instances]]
agents = ["printer.example.com"]
version = 1  # 很多打印机只支持 v1
community = "public"

[instances.template_file_contents]
printer_template = '''
zabbix_export:
  version: '6.0'
  templates:
    - template: Printer Monitoring
      items:
        - name: Printer status
          type: SNMP_AGENT
          snmp_oid: .1.3.6.1.2.1.25.3.5.1.1.1
          key: printer.status
          value_type: UNSIGNED
        - name: Printer error state
          type: SNMP_AGENT
          snmp_oid: .1.3.6.1.2.1.25.3.5.1.2.1
          key: printer.error
          value_type: TEXT
        - name: Toner level black
          type: SNMP_AGENT
          snmp_oid: .1.3.6.1.2.1.43.11.1.1.9.1.1
          key: printer.toner.black
          value_type: UNSIGNED
          units: '%'
        - name: Pages printed
          type: SNMP_AGENT
          snmp_oid: .1.3.6.1.2.1.43.10.2.1.4.1.1
          key: printer.pages.total
          value_type: UNSIGNED
'''

九、故障排查

9.1 常见问题及解决方案

9.1.1 连接问题

问题:无法连接到 SNMP 设备

检查步骤:

# 1. 测试网络连通性
ping 192.168.1.1

# 2. 测试 SNMP 端口
nc -zvu 192.168.1.1 161

# 3. 使用 snmpwalk 测试
snmpwalk -v2c -c public 192.168.1.1 system

# 4. 检查防火墙
sudo iptables -L -n | grep 161

常见原因:

  • 防火墙阻止 UDP 161 端口
  • SNMP 服务未启动
  • Community 字符串错误
  • ACL 限制访问

9.1.2 认证问题

SNMPv3 认证失败

检查配置:

# 确保所有参数匹配
username = "snmpuser"
security_level = "authPriv"
auth_protocol = "SHA"      # 大小写敏感
auth_password = "password"  # 至少8个字符
priv_protocol = "AES"
priv_password = "password"  # 至少8个字符

测试命令:

snmpget -v3 -l authPriv -u snmpuser -a SHA -A authpass123 -x AES -X privpass456 192.168.1.1 sysDescr.0

9.1.3 OID 不存在

错误:OID not found on device

排查方法:

# 1. 列出设备支持的所有 OID
snmpwalk -v2c -c public 192.168.1.1 .1

# 2. 检查特定 OID
snmpget -v2c -c public 192.168.1.1 .1.3.6.1.2.1.2.2.1.10.1

# 3. 查看 MIB 支持
snmpwalk -v2c -c public 192.168.1.1 sysORTable

解决方案:

  • 确认设备支持该 MIB
  • 使用正确的 OID
  • 某些设备需要启用特定 MIB

9.1.4 发现失败

发现规则未返回任何项目

调试步骤:

手动执行 walk:

snmpwalk -v2c -c public 192.168.1.1 .1.3.6.1.2.1.2.2.1.2

检查过滤器:

filter:
  conditions:
    - macro: '{#IFNAME}'
      value: 'eth'    # 可能过滤太严格
      operator: LIKE

查看日志:

tail -f /var/log/categraf/categraf.log | grep -i discovery

9.1.5 预处理错误

预处理失败的常见原因:

正则表达式错误:

# 错误:未转义特殊字符
- type: REGEX
  parameters: ['Temp: (\d+).(\d+)', '\1.\2']

# 正确:
- type: REGEX
  parameters: ['Temp: (\d+)\.(\d+)', '\1.\2']

JavaScript 语法错误:

# 错误:缺少 return
- type: JAVASCRIPT
  parameters: ['value * 100']

# 正确:
- type: JAVASCRIPT
  parameters: ['return value * 100']

类型不匹配:

# 错误:对字符串使用数值运算
- type: MULTIPLIER
  parameters: ['8']

# 正确:先转换类型
- type: REGEX
  parameters: ['(\d+)', '\1']
- type: MULTIPLIER
  parameters: ['8']

9.2 调试模式使用

启用调试模式:

# 启动时添加 debug 参数
./categraf --debug --inputs snmp_zabbix

# 查看详细日志
tail -f /var/log/categraf/categraf.log

9.3 日志分析

关键日志标识:

  • E! - 错误
  • W! - 警告
  • I! - 信息
  • D! - 调试 常见日志分析:
# 查看错误
grep "E!" /var/log/categraf/categraf.log

# 查看发现相关
grep -i discovery /var/log/categraf/categraf.log

# 查看特定设备
grep "192.168.1.1" /var/log/categraf/categraf.log

# 查看预处理错误
grep -i preprocessing /var/log/categraf/categraf.log

9.4 性能问题排查

采集延迟或超时

优化建议:

调整超时和重试:

timeout = "10s"        # 增加超时
retries = 2           # 减少重试
max_repetitions = 10  # 减少批量大小

减少并发请求:

# 分散不同设备的采集时间
[[instances]]
agents = ["192.168.1.1"]

[[instances]]
agents = ["192.168.1.2"]

优化发现规则:

discovery_rules:
  - delay: 6h          # 减少发现频率
    filter:
      conditions:      # 严格过滤,减少生成的监控项
        - macro: '{#IFTYPE}'
          value: '6'
          operator: EQUALS

十、限制和注意事项

10.1 功能限制

10.1.1 只支持 SNMP_AGENT 类型

插件只处理以下类型的监控项:

  • SNMP_AGENT
  • SNMPV1_AGENT
  • SNMPV3_AGENT) 不支持的类型(会被忽略):
  • ZABBIX_AGENT
  • HTTP_AGENT
  • CALCULATED
  • DEPENDENT
  • TRAP

10.1.2 不支持的 Zabbix 功能

功能 支持情况 说明
Items ✅ 部分支持 仅 SNMP 类型
Discovery ✅ 支持 完整支持
Triggers ❌ 不支持 插件不处理告警
Graphs ❌ 不支持 忽略图表定义
Dashboards ❌ 不支持 忽略仪表板
Actions ❌ 不支持 不执行动作
Trends ❌ 不支持 不存储趋势数据
Events ❌ 不支持 不生成事件

10.1.3 模板版本兼容性

  • 完全支持:Zabbix 6.0+ YAML 格式
  • 不支持:Zabbix 5.x 及以下的 XML 格式
  • 部分支持:可能无法识别最新版本的新特性

10.2 性能考虑

建议限制:

  • 单个实例最多监控 100 个设备
  • 每个设备最多 1000 个监控项
  • 发现规则生成的项目不超过 10000 个
  • 批量请求大小固定为 60 个 OID 资源消耗:
  • 每个设备一个 SNMP 连接
  • 每个监控项占用约 1KB 内存
  • CPU 使用主要在预处理阶段

10.3 安全建议

使用 SNMPv3:

version = 3
security_level = "authPriv"

限制 community 权限:

  • 使用只读 community
  • 配置设备 ACL

网络隔离:

  • SNMP 流量不应跨越不信任网络
  • 使用 VLAN 隔离管理网络

定期更新:

  • 及时更新 Categraf
  • 更新设备固件

十一、迁移指南

11.1 从原生 SNMP 插件迁移

步骤 1:导出现有配置 原生 snmp插件 配置示例:

[[instances]]
agents = ["192.168.1.1"]
version = 2
community = "public"

[[instances.field]]
oid = ".1.3.6.1.2.1.1.3.0"
name = "uptime"

[[instances.field]]
oid = ".1.3.6.1.2.1.2.2.1.10.1"
name = "interface.eth0.in"

步骤 2: 转换为模板格式 创建模板文件 migration_template.yaml:

zabbix_export:
  version: '6.0'
  templates:
    - template: Migrated from SNMP
      items:
        - name: System Uptime
          type: SNMP_AGENT
          snmp_oid: .1.3.6.1.2.1.1.3.0
          key: uptime
          value_type: UNSIGNED
        - name: Interface eth0 In
          type: SNMP_AGENT
          snmp_oid: .1.3.6.1.2.1.2.2.1.10.1
          key: interface.eth0.in
          value_type: UNSIGNED

步骤 3: 添加snmp_zabbix插件配置文件

# 新的 snmp_zabbix 配置
[[instances]]
agents = ["192.168.1.1"]
version = 2
community = "public"
template_files = ["new_template.yaml"]

11.2 从 Zabbix 迁移

步骤 1:导出 Zabbix 配置 推荐使用 Web 界面(见 2.2.1)

步骤 2:分析和筛选模板

# 查找包含 SNMP 项的模板
grep -l "type: SNMP" templates/*.yaml

# 统计每个模板的 SNMP 项数量
for f in templates/*.yaml; do
    count=$(grep -c "type: SNMP" "$f" 2>/dev/null || echo 0)
    if [ $count -gt 0 ]; then
        echo "$f: $count SNMP items"
    fi
done

步骤 3:配置映射表 如果 Zabbix 中使用了主机变量,创建映射:

[instances.mappings]
"192.168.1.1" = {
    device_name = "core-sw-01",
    location = "DC1",
    contact = "admin@example.com"
}

步骤 4:验证迁移

# 测试配置
categraf --test --inputs snmp_zabbix

# 与zabbix对比指标

十二、附录

A. 配置参数速查表

参数 类型 默认值 说明
agents []string 必填 目标设备列表
version int 2 SNMP 版本(1,2,3)
community string public 团体字符串
username string - SNMPv3 用户名
security_level string noAuthNoPriv 安全级别
auth_protocol string MD5 认证协议
auth_password string - 认证密码
priv_protocol string DES 加密协议
priv_password string - 加密密码
port int 161 SNMP 端口
timeout duration 5s 超时时间
retries int 3 重试次数
max_repetitions int 10 BULK单次请求返回的数据
template_files []string - 模板文件路径

B. 预处理类型对照表

Zabbix 类型 插件支持 说明
MULTIPLIER 乘数
SIMPLE_CHANGE 简单变化
CHANGE_PER_SECOND 每秒变化率
REGEX 正则表达式
JSONPATH JSON 路径
SNMP_WALK_TO_JSON Walk 转 JSON
HEX_TO_DECIMAL 十六进制转十进制
JAVASCRIPT JavaScript
TRIM 去除空白
MAC_FORMAT MAC 格式化
IP_FORMAT - ✅ IP 格式化

C. 常用 OID 列表 系统信息:

.1.3.6.1.2.1.1.1.0 - sysDescr
.1.3.6.1.2.1.1.3.0 - sysUpTime
.1.3.6.1.2.1.1.5.0 - sysName
.1.3.6.1.2.1.1.6.0 - sysLocation
.1.3.6.1.2.1.1.7.0 - sysServices

网络接口:

.1.3.6.1.2.1.2.2.1.2 - ifDescr
.1.3.6.1.2.1.2.2.1.3 - ifType
.1.3.6.1.2.1.2.2.1.5 - ifSpeed
.1.3.6.1.2.1.2.2.1.7 - ifAdminStatus
.1.3.6.1.2.1.2.2.1.8 - ifOperStatus
.1.3.6.1.2.1.2.2.1.10 - ifInOctets
.1.3.6.1.2.1.2.2.1.16 - ifOutOctets

CPU/内存(企业 MIB):

# Cisco
.1.3.6.1.4.1.9.9.109.1.1.1.1.7 - CPU 使用率
.1.3.6.1.4.1.9.9.48.1.1.1.5 - 内存已用
.1.3.6.1.4.1.9.9.48.1.1.1.6 - 内存空闲

# HP
.1.3.6.1.4.1.11.2.14.11.5.1.9.6.1 - CPU 使用率

D. 正则表达式示例

# 提取数字
- type: REGEX
  parameters: ['(\d+)', '\1']

# 提取温度值
- type: REGEX
  parameters: ['Temperature:\s*(\d+\.?\d*)', '\1']

# 提取接口名称
- type: REGEX
  parameters: ['([\w-]+)\s*:\s*(.+)', '\1']

# 提取 IP 地址
- type: REGEX
  parameters: ['(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', '\1']

# 提取 MAC 地址
- type: REGEX
  parameters: ['([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})', '\0']

E. JavaScript 脚本模板

// 基本计算
return value * 100;

// 条件判断
if (value > 1000) {
    return value / 1000;
} else {
    return value;
}

// 字符串处理
return value.toUpperCase();
return value.replace(/\s+/g, '_');

// JSON 处理
var obj = JSON.parse(value);
return obj.temperature;

// 数组处理
var parts = value.split(',');
return parts[0];

// 复杂逻辑
function convertBytes(bytes) {
    if (bytes >= 1099511627776) {
        return (bytes / 1099511627776).toFixed(2) + " TB";
    } else if (bytes >= 1073741824) {
        return (bytes / 1073741824).toFixed(2) + " GB";
    } else if (bytes >= 1048576) {
        return (bytes / 1048576).toFixed(2) + " MB";
    } else if (bytes >= 1024) {
        return (bytes / 1024).toFixed(2) + " KB";
    } else {
        return bytes + " B";
    }
}
return convertBytes(value);

F. 术语表

术语 说明
OID Object Identifier,对象标识符
MIB Management Information Base,管理信息库
PDU Protocol Data Unit,协议数据单元
LLD Low-Level Discovery,低级别发现
SNMP Walk 遍历 SNMP 子树的操作
Community SNMPv1/v2c 的认证字符串
Bulk Request SNMPv2c/v3 的批量请求
Trap SNMP 主动推送的告警
Counter 累加计数器,会溢出
Gauge 测量值,可增可减
TimeTicks 时间计数器,单位 1/100 秒
Item 监控项,定义要采集的指标
Item Prototype 项目原型,发现后生成监控项的模板
Macro 宏,用于动态替换的变量
Preprocessing 预处理,数据采集后的转换步骤
快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云
OpenSource
开源版
Flashcat
Flashcat
Flashduty
Flashduty