使用 Rickshaw 可视化 InfluxDB 中的时间序列数据

导航至

最近,我们研究了使用图形库 plotly.js请参阅此处的帖子)可视化来自 InfluxDB 的时间序列数据,该库提供了超过 20 种不同的图表类型,并将所有内容整齐地打包在一起,用户可以轻松简单地重现自己风格和选择的图表。今天,我们将研究如何从 InfluxDB 中提取数据并使用 Rickshaw 库显示数据,该库与 plotly.js 类似,也是基于 d3.js 构建的。Rickshaw 工具包使用户能够创建自定义交互式时间序列图表,使用户可以访问各种样式和大量不同的元素——渲染器、图例、悬停和范围选择器——来构建他们的图表。

当然,在我们开始之前,您需要确保您的本地机器上已启动并运行 InfluxDB 实例。这是一个很棒的网站,可帮助您设置 TICK Stack 并在您的机器上执行操作——恰如其名的 “入门” 指南,InfluxData 网站上提供的文档将引导您完成堆栈中所有四个软件包的安装和运行。您也可以尝试在 沙箱 模式下进行实验。

我们需要数据!

现在为了可视化我们的数据,您首先需要获取一些数据。对于这种情况,我将通过 Node-influx 客户端库 查询 InfluxDB,以获取 Telegraf 已经收集的关于我的机器的统计信息。您可以对自己的机器执行相同的操作,或者如果您有兴趣,您可以连接并开始监控您自己的任何数量的应用程序。Telegraf 有许多 插件 可以处理将您的数据转换为 行协议(用于将点写入 InfluxDB 的基于文本的格式)并将您的数据直接发送到数据库。

对于此示例,我将使用 Node/Express 设置我的服务器文件并查询 InfluxDB 以获取平均 CPU 使用率数据。如果您已安装并运行完整的 TICK Stack,您应该能够执行相同的操作。在您安装并引入适当的依赖项后,您将连接到 InfluxDB 的本地实例以及您想要查询的特定数据库。这是我的服务器文件的样子

const Influx = require('influx');
const express = require('express');
const path = require('path');
const os = require('os');
const bodyParser = require('body-parser');
const app = express();
const influx = new Influx.InfluxDB('http://127.0.0.1:8086/telegraf');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));
app.use(express.static(path.join(__dirname, 'public')));
app.set('port', 3000);

influx.getMeasurements()
  .then(names => console.log('My measurement names are: ' + names.join(', ')))
  .then(() => {
    app.listen(app.get('port'), () => {
      console.log(`Listening on ${app.get('port')}.`);
    });
  })
  .catch(error => console.log({ error }));

app.get('/api/v1/usage', (request, response) => {
  influx.query(`
    select mean("usage_user") as "mean_usage_user",
    mean("usage_system") as "mean_usage_system" from cpu
    where time > now() - 1h and
    host = ${Influx.escape.stringLit(os.hostname())}
    group by time(10s)
    limit 100
    `)
    .then(result => response.status(200).json(result))
    .catch(error => response.status(500).json({ error }));
});

您会注意到代码的最后一部分有一个端点,该端点查询数据库以获取平均 CPU 用户使用率。

可视化您的数据

您需要设置您的 html、css 和脚本文件结构,以便您可以在浏览器中显示您的数据。您还需要安装 Rickshaw 和 d3 作为 npm 包,或将缩小的版本添加到您的文档头部。查看 Rickshaw 的 GitHub ReadMe 以获取更多信息。对于一些更华丽的图表,Rickshaw 需要 jQueryjQueryUI,但今天我们将保持简单。看看这个 index.html 文件

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link type="text/css" rel="stylesheet" type="text/css" href="styles.css">
    <link type="text/css" rel="stylesheet" href="rickshaw.min.css">
    <script src="d3.layout.min.js"></script>
    <script src="d3.min.js"></script>
    <script src="rickshaw.min.js"></script>
    <title>Visualizing Data from InfluxDB with Rickshaw</title>
  </head>
  <body>
    <header>
      <h1 class="title">Visualizing Your Time Series Data from InfluxDB with Rickshaw</h1>
    </header>
    <main>
      <div id="chart-container">
        <div class="chart-box">
          <div id="y-axis"></div>
          <div id="chart"></div>
        </div>
        <div class="legend-box">
          <div id="legend"></div>
          <form id="offset-form" class="toggler">
            <input type="radio" name="offset" id="lines" value="lines" checked>
            <label class="lines" for="lines">lines</label><br>
            <input type="radio" name="offset" id="stack" value="zero">
            <label class="stack" for="stack">stack</label>
          </form>
        </div>
      </div>
    </main>
    <script type="text/javascript" src="scripts.js"></script>
  </body>
</html>

正如您所见,您需要为您的图表、y 轴和图例定义单独的容器,以及一个可选的切换功能,以不同的格式渲染图表。所有这些组件的分离允许用户创建自定义格式和独特的 visualizations,但对于图形游戏的新手来说,设置所有内容可能有点棘手。例如,我试图立即重现以下示例的版本,并很快意识到,最好从 Rickshaw 的 教程 开始。

<figcaption> 蹒跚学步,才能健步如飞!</figcaption>

但是,我离题了。让我们继续脚本文件,在那里我们可以添加所有功能以在图表中绘制我们的 InfluxDB 时间序列数据。复制并粘贴(或键入以进行肌肉记忆开发!)以下内容:

const loadData = () => {
  fetch('/api/v1/usage')
    .then( response => {
      if (response.status !== 200) {
        console.log(response);
      }
      return response;
    })
    .then(response => response.json())
    .then(parsedResponse => {
      const unpackData = (array, key) => {
        return array.map(obj => Object.assign({}, { x: Date.parse(obj['time']), y: obj[key] }))
      };

      const palette = new Rickshaw.Color.Palette({ scheme: 'colorwheel' });
      const graph = new Rickshaw.Graph({
        element: document.querySelector('#chart'),
        width: 1200,
        height: 640,
        renderer: 'line',
        series: [
          {
            name: 'Mean User Usage',
            data: unpackData(parsedResponse, 'mean_usage_user'),
            color: palette.color()
          },
          {
            name: 'Mean System Usage',
            data: unpackData(parsedResponse, 'mean_usage_system'),
            color: palette.color()
          },
        ]
      });

      const xAxis = new Rickshaw.Graph.Axis.Time({
        graph: graph,
        ticksTreatment: 'glow'
      });

      const yAxis = new Rickshaw.Graph.Axis.Y({
        element: document.getElementById('y-axis'),
        graph: graph,
        orientation: 'left',
        tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
      });
      const legend = new Rickshaw.Graph.Legend( {
        element: document.getElementById('legend'),
        graph: graph
      });
      const offsetForm = document.getElementById('offset-form');
      offsetForm.addEventListener('change', function(e) {
        const offsetMode = e.target.value;

        if (offsetMode == 'lines') {
                graph.setRenderer('line');
                graph.offset = 'zero';
        } else {
                graph.setRenderer('stack');
                graph.offset = offsetMode;
        }
        graph.render();
      }, false);

      return graph.render();
    })
    .catch( error => console.log(error) );
}

document.addEventListener('DOMContentLoaded', loadData);

现在,除了我的“loadData”函数太长且根本不符合单一职责原则之外,这里肯定发生了很多事情。让我们深入研究一下,好吗?

我们首先发出一个 fetch 调用,从 InfluxDB 中抓取数据,如果我们的调用成功,我们就可以解析和变异(解包)我们的数据以适应 Rickshaw 要求的格式。Rickshaw 有几种颜色方案可供选择,因此在将我们的调色板设置为“colorwheel”之后,我们可以实例化一个新的 Rickshaw 图表并相应地插入格式化数据。

接下来是创建 x 轴和 y 轴、表示我们正在查看的数据的图例以及在折线图或堆积图之间切换图表格式的切换器功能(Rickshaw 还有更多格式)。在我看来,这些可选的附加组件是事情变得棘手的地方。尤其是在 x 轴和 y 轴方面,由于这是一个时间序列图,因此对我来说,默认情况下存在这些轴最有意义,而不是必须作为事后才添加的东西(然后再在其之上进行样式设置和定位!)。有关可能扩展的列表,我建议您访问 Rickshaw 的 GitHub 页面 并花一些时间进行实验。

最终产品

如果您此时重新启动服务器并导航到端口 3000,您应该有望看到一个特别美丽且成形的图表。如果它看起来不像下面那个那么棒,请不要忘记添加一些 CSS 风格来使其生动起来并突出显示!

<figcaption> 图形的可能性!</figcaption>

感谢您的阅读,欢迎查看 GitHub 上的源代码 GitHub,或发送电子邮件至 [email protected],如果您有任何问题。祝您制图愉快!