logo NodeSeekbeta

[增加中文版]🔹 Node Information - 更美观的 Grafana 性能监控面板 (Prometheus + Node Exporter) & Grafana 安装教程

  • 1

  • 普罗米修斯和grafana真是完美,比那一众面板好多了

  • bd

  • @Bene #0

    楼主辛苦了,一直在用你的监控,不错~!

    中文的贴图能否上一下,看看什么样子?
    另外能否增加每个VPS在一定期间内,例如30天,的流量统计?

  • @Bene #165

    收到,能否在Instance Overview中每一行增加对应VPS30天流量统计?这个信息的优先级还是很高的。

  • @tioman #167

    当时没有放上去是出于两个原因:

    1. Prometheus 的流量统计精确度存疑
    2. 表格更适合放实时数据,这种累积性的计算可能会带来更大的误差

    有这方面的需要,我觉得用 vnStat 更适合(当然有空的时候我也想一想怎么把 vnStat 的数据结合进面板里面

  • 因为目前楼主用的node_exporter, 让AI写了一个使用 Node.js 实现的 vnStat Exporter 代码,供楼主参考(假设vnstat已经安装):

    const { exec } = require('child_process');
    const express = require('express');
    const client = require('prom-client');
    
    // 创建 Prometheus 指标注册表
    const register = new client.Registry();
    client.collectDefaultMetrics({ register });
    
    // 定义网络流量指标(字节)
    const totalTraffic = new client.Gauge({
      name: 'vnstat_total_bytes',
      help: 'Total network traffic in bytes',
      labelNames: ['interface', 'direction'],
      registers: [register],
    });
    
    // 配置 Express 应用
    const app = express();
    const PORT = 9118;
    const UPDATE_INTERVAL = 300000; // 5分钟
    
    // 获取并解析 vnStat 数据
    async function getVnStatData() {
      return new Promise((resolve, reject) => {
        exec('vnstat --json', (error, stdout, stderr) => {
          if (error) {
            reject(new Error(`Command failed: ${stderr}`));
            return;
          }
        
          try {
            const data = JSON.parse(stdout);
            resolve(data);
          } catch (e) {
            reject(new Error('Failed to parse JSON'));
          }
        });
      });
    }
    
    // 更新指标数据
    async function updateMetrics() {
      try {
        const data = await getVnStatData();
      
        if (!data?.interfaces) {
          console.error('Invalid vnStat data format');
          return;
        }
    
        data.interfaces.forEach(iface => {
          const interfaceName = iface.name;
          const months = iface.traffic?.months || [];
    
          // 取最近一个月的数据(假设需要最近30天)
          const latestMonth = months[months.length - 1];
          if (latestMonth) {
            // 转换单位:vnStat 默认使用 KiB,需要转换为 bytes
            totalTraffic.labels({ interface: interfaceName, direction: 'tx' })
              .set(latestMonth.tx * 1024);
            totalTraffic.labels({ interface: interfaceName, direction: 'rx' })
              .set(latestMonth.rx * 1024);
          }
        });
      
        console.log(`Metrics updated at ${new Date().toISOString()}`);
      } catch (err) {
        console.error('Error updating metrics:', err.message);
      }
    }
    
    // 设置定时更新
    setInterval(updateMetrics, UPDATE_INTERVAL);
    updateMetrics(); // 立即执行第一次更新
    
    // 暴露指标端点
    app.get('/metrics', async (req, res) => {
      try {
        res.set('Content-Type', register.contentType);
        res.end(await register.metrics());
      } catch (err) {
        res.status(500).end(err.message);
      }
    });
    
    // 启动服务器
    app.listen(PORT, '0.0.0.0', () => {
      console.log(`Exporter running on http://0.0.0.0:${PORT}/metrics`);
    });
    

    配套文件说明

    1. 安装依赖
    npm init -y
    npm install express prom-client
    
    2. 启动方式
    # 直接运行
    node exporter.js
    
    # 使用 pm2 守护进程(推荐)
    npm install -g pm2
    pm2 start exporter.js --name vnstat-exporter
    pm2 save
    pm2 startup
    
    3. 验证指标

    访问 http://localhost:9118/metrics 应该能看到类似以下输出:

    # HELP vnstat_total_bytes Total network traffic in bytes
    # TYPE vnstat_total_bytes gauge
    vnstat_total_bytes{direction="rx",interface="eth0"} 254803008
    vnstat_total_bytes{direction="tx",interface="eth0"} 163842048
    

    扩展建议

    如果需要更精细的控制,可以添加以下功能:

    // 在 updateMetrics 函数中添加日期过滤
    const now = new Date();
    const thirtyDaysAgo = new Date(now.setDate(now.getDate() - 30));
    
    months.forEach(month => {
      const monthDate = new Date(`${month.year}-${String(month.date).padStart(2, '0')}-01`);
      if (monthDate >= thirtyDaysAgo) {
        totalTraffic.labels({ /* ... */ }).inc(month.tx * 1024); // 使用 counter 类型时
      }
    });
    

    常见问题处理

    1. 权限问题

      • 确保 Node.js 进程有权限执行 vnstat 命令
      • 可用 sudo setcap cap_net_raw+ep $(which vnstat) 解决权限问题
    2. 时间范围不匹配

      • 验证 vnStat 的数据库是否包含完整 30 天数据
      • 在 vnStat 配置中调整数据保存周期(默认已足够)
    3. 单位不一致

      • 确认 vnStat 的输出单位(通过 vnstat --config 查看 UnitMode
      • 如果使用 MiB 单位需要调整转换系数(MiB → Bytes 应乘以 1024²)

你好啊,陌生人!

我的朋友,看起来你是新来的,如果想参与到讨论中,点击下面的按钮!

📈用户数目📈

目前论坛共有61579位seeker

🎉欢迎新用户🎉