InfluxDB C 客户端库用于捕获统计数据

导航到

这是由 InfluxAce,IBM 技术员工,AIX 和 Linux 的 nmon 开发者 Nigel Griffiths 首次在 IBM 网站上发布 的文章的重发。

目前,没有官方的 InfluxDB C 语言客户端库。幸运的是,我想做的是捕捉 AIX 和 Linux 的操作系统性能统计。这个数据捕捉工具叫做“njmon”,在 Sourceforge 上是开源的。因此,我开发了一个小的函数库,包含 12 个函数,以便于保存数据,我想与大家分享。希望它对其他人也会有所帮助。

InfluxDB 文档中关于行协议格式的统计数据很好,但是 HTTP 要求模糊,您需要通过多次实验来发现细节。这个库还包括网络套接字处理层,这可能是第一次接触时比较棘手。

此 InfluxDB C 客户端库没有涵盖从 InfluxDB 中提取数据的功能(在 C 语言中处理 JSON 数据非常困难),也没有数据库管理功能,如创建 InfluxDB 数据库(我使用“influx”命令)。

环境

假设

  1. 您有 C 语言编译器。
  2. 您能编写一些简单的 C 语言程序。
  3. 您正在运行 InfluxDB。

以下操作系统和硬件的当前版本上测试了此代码

  • AIX 7
  • ppc64le (POWER8/9) 上的 Linux RHEL、SUSE 和 Ubuntu
  • AMD64 (x86_64) 上的 Linux RHEL、SUSE 和 Ubuntu

代码可能适用于其他操作系统,因为 C 代码很直接。该代码使用常规套接字库函数。

?步骤

一个示例代码,用于使用 C 语言捕获统计数据并将它们添加到 InfluxDB(简称“ic”函数)

#include "ic.h"

main()
{
   ic_influx_database("myinfluxdbserver", 8086, "ic"); /* the details of the connection to InfluxDB */
   ic_tags("host=myserver.acme.com");                  /* tags to find specific data amongst the data */

   for(;;) {
       ic_measure("mystats");             /* name of a group of data */
           ic_long("busy",  42);          /* example of saving an integer */
           ic_double("pi",   3.142);      /* example of saving a floating point number */
           ic_string("state", "Running"); /* example of saving some text */
       ic_measureend();                   /* end the group */

       ic_push();      /* after many measures it is sent to InfluxDB over the network in one go*/

       sleep(60);      /* pause 60 seconds and then repeat */
}

在这个小小的例子中,统计信息(42,3.141,"运行")是硬编码的。这不是一个好主意,而且相当没有意义。希望这段代码能展示库函数与各种C数据类型的使用。通常,C代码会包括调用C函数从操作系统、应用程序库或执行命令来获取实时数据。这些“ic”函数的详细信息以及更多内容将在本文的其余部分进行介绍。

本文末尾提供了代码及其在GitHub上的使用示例供您下载。

介绍C函数

提供的函数(按正常使用顺序)如下:

void ic_influxdb(char * hostname, long port, char * database)

  • 仅在C程序的开始处调用此函数一次。
  • 此函数提供了您的InfluxDB服务器的连接详细信息。
  • 例如,ic_influxdb("admin.domain.company.com", 8086, "ic")
  • 主机名很明显。InfluxDB的默认端口为8086。可以在InfluxDB配置文件中更改它,但需要重启InfluxDB才能激活。
  • 在运行程序之前需要预先创建数据库。假设数据库名称为"ic",在InfluxDB服务器上
    $ influx
    > create database ic
    > exit
    $
  • 您可以使用InfluxDB服务器的主机名或IP地址。
  • 此函数只是记录详细信息。只有在数据被推送到InfluxDB(ic_push())时才会建立与InfluxDB的连接,并在之后立即断开连接。

void ic_influx_userpw(char *user, char *password)

  • 仅在C程序的开始处调用此函数一次。
  • 例如,ic_influx_userpw("Nigel", "SECRET");
  • 如果您的InfluxDB需要用户名和密码进行访问,请使用此函数提供后续连接到InfluxDB的详细信息。
  • 如果您的InfluxDB服务器没有强制性的用户名和密码(例如,默认安装配置),则不需要调用此函数。如果不需要,InfluxDB会静默忽略任何用户名和密码。
  • 尚不支持SSL证书。

void ic_tags(char *tag_string)

  • 仅在C程序的开始处调用此函数一次。
  • 标签用于缩小数据库数据以针对特定资源。
  • 例如,从计算机性能统计信息中:主标签通常是收集统计信息的服务器的主机名。图形工具可以使用标签值来限制数据到子集。例如,通过主机名选择特定服务器的CPU统计信息。
  • 示例,ic_tags("host=server42")
  • 您可以有多个标签。标签由逗号分隔,不包含空格:ic_tags("host=server42,serialno=75629475")
  • 标签中不能包含任何空格或制表符字符。最好避免它们。
  • 有一种特殊情况,如果您有多个同类型的资源,例如,多个磁盘,则可能使用
    • ic_tags("host=server42,serialno=75629475,disk=sda")
    • ic_tags("host=server42,serialno=75629475,disk=sdb")
    • 等等。
    • 这些额外的标签允许在一个图表上绘制所有磁盘,Grafana可以计算出每个服务器有多少磁盘,并调整图表以匹配——更多细节请参考本文的下文。

InfluxDB行协议——非常简短的介绍

InfluxDB行协议需要以下部分

测量名称,标签,一个空格,键=值对,一个空格和时间戳

测量名称最好是有意义的,例如:cpu,memory,disk,transactions,temperature等。这些名称列在图形工具中,因此清晰的名称可以帮助选择正确的统计信息。

标签标识数据来源和使用来选择数据的特征。例如,服务器主机名(host=vm99)、数据的来源仪器(probe=a12)、应用程序名称(app=DB2)。

空格表示标签的结束和键值对的开始。键=值是实际数据,如“cpubusy”=56因此

  • 格式:测量值,标签 key=value 时间戳
  • CPU利用率,host=vm123 cpu_user=60,cpu_sys=15,cpu_wait=15,cpu_idle=10 时间戳
  • ic 库允许 InfluxDB 添加时间戳(自1970年1月1日起的秒数),从而确保收集工具之间的时间一致性。

捕获您的统计信息

  • 假设您知道如何在C程序中捕获您的实际数据。
  • 通常数据来自操作系统的C库函数调用或与您安装的额外工具和应用程序一起提供的库。
  • 文章开头的小型示例涵盖了基础知识。以下是详细说明
    • ic_measure()
    • 然后,根据数据格式保存数据的多个函数
      • ic_long() 用于C语言长整型(大整数(技术上为64位长整型))
      • ic_double() 用于C语言双精度浮点数
      • ic_string() 用于C语言字符串(以零字符终止的字符数组)
    • 最后使用 ic_measureend()

void ic_measure(char *measurement_name)

  • 此函数命名测量(一组统计信息),并以对 ic_measureend() 的匹配调用结束。部分名称被保存在输出缓冲区中。
  • 您可以有多个 ic_measure()ic_measureend() 对来保存不同的资源。例如,计算机统计信息:CPU、内存、磁盘、网络等。
  • 例如,ic_measure("CPU利用率");

void ic_measureend()

  • 此函数用于标记当前测量的结束。

void ic_long(char *name, long long value)

  • 此函数将名称和整数保存到输出缓冲区。
  • 测量中可以有多个 ic_long() 函数调用。
  • 例如
ic_long("cpu_user", 60);
ic_long("cpu_sys", 15);
ic_long("cpu_wait", 15);
ic_long("cpu_idle", 10);

void ic_double(char *name, double value)

  • 此函数将名称和双精度浮点数保存到输出缓冲区。
  • 测量中可以有多个 ic_double() 函数调用。
  • 例如
ic_double("cpu_user", 60.3);
ic_double("cpu_sys", 15.1);
ic_double("cpu_wait", 15.2);
ic_double("cpu_idle", 9.4);

关于使用 InfluxDB 的长整型和双精度浮点数的说明

  • 与 InfluxDB 相比,使用整数而不是双精度浮点数实际上没有空间优势。
  • 此外,InfluxDB 很聪明,不会与精确比较(如将双精度浮点数与零比较)混淆。
  • 我的建议是大多数时候使用双精度值。
  • 在数据添加到数据库后,无法尝试将 InfluxDB 中的数据从整数更改为双精度。因此,请确保第一次数据类型正确。如果您尝试添加一个 "key = 浮点数" 的键,但该键已作为整数写入 InfluxDB,则整个测量将被拒绝。
  • 当我认为数据显然是整数(例如运行队列号)时,我遇到了这样的问题。然后,后来意识到运行队列变化需要除以秒数。因此,它变成了一个浮点数。选项是删除数据库中的所有当前数据或将 "runqueue" 重命名为略微不同的名称,如 "runq"。

void ic_string(char *name, char *value)

  • 此函数将名称和字符串保存到输出缓冲区。
  • 测量中可以有多个 ic_string() 函数调用。
  • 例如
ic_string("architecture", "ppc64le");
ic_stringe("os_version", "7.2.5.2");
ic_string("os_name", "AIX");
ic_string("vendor", "IBM");
ic_string("status", "Running")
ic_string("location", "London, UK");

不要这样使用,因为字符串无法进行绘图

is_string("processes", "42") ;
is_string("processes", "42.12345") ;
is_string("meaning", "forty two");

void ic_push()

  • 所有数据保存后,需要将其发送到 InfluxDB。  ic_push() 函数执行此操作。
  • ic_push() 函数打开网络套接字,将所有保存的数据发送到 InfluxDB 服务器,并关闭套接字。一次性推送所有数据是一种高效的方法,可以一次发送可能成千上万的统计数据。
  • 之后,套接字连接被关闭。
  • 由于与InfluxDB的连接只是临时的,这意味着
    • 如果没有问题,如果InfluxDB重启以更新到更新的InfluxDB版本或如果服务器重新启动。
    • 它还可以处理短暂的网络中断。
    • 如果无法创建套接字,数据将被丢弃,但下一个 ic_push() 工作正常。
  • 通常,您的程序结构如下所示
Initialise functions

while(1) {
   ic_measure()
       add data to this measure
   ic_measureend()

   ic_measure()
       add data to this measure
   ic_measureend()

   ic_measure()
       add data to this measure
   ic_measureend()

   ...

   ic_push()
   sleep(for some seconds)
}

始终在ic_push()之后直接调用sleep(),以便尽可能减小数据收集与ic_push()之间的时间。

如果您有多个相同类型的单元怎么办?

来自计算机统计领域的示例,您的笔记本电脑只有一个硬盘,但更大的服务器可能有数十个甚至数百个硬盘,每个服务器可能有不同数量的硬盘。这使得绘图变得很棘手,因为图表上可能有1到100多条线。CPU核心、网络、文件系统、网络缓冲区、Firbe通道适配器等等也是如此。

为了处理这个问题,我们在测量中有一个称为子测量统计的东西。

void ic_sub(char *sub_name)

  • 此函数用于ic_measurement()和ic_measurementend()函数中。
  • 在匹配ic_subend()之前,将sub_name添加到此测量的标签中。
  • 在ic_sub()和ic_subend()之间,使用ic_long()、ic_double()和ic_string()保存数据。

void ic_subend()

  • 结束子测量,即与之前ic_sub()匹配的一对。
  • 删除之前ic_sub()添加的标签。

一个简单的例子——以帮助使这一点更清晰。缩进不是必需的(在C语言中被忽略),但在这里使用以阐明函数对。

ic_measurement("disks");

   ic_sub("hdisk0");
       is_double("reads", 45.6);
       is_double("writes",105.83);
   ic_subend();

   ic_sub("hdisk1");
       is_double("reads", 2084.91);
       is_double("writes",4.1);
   ic_subend();

ic_meassurementend();

最后的函数是打开调试输出

void ic_debug(int level)

  • 此函数可以在任何时候调用,但如果您遇到问题,最好在开始时调用此函数。
  • 只有三个值有效
  • Level = 0表示关闭调试输出。库将只输出警告(可恢复错误)和错误(其中ic会导致程序退出)。
  • Level = 1表示跟踪输出,因为库中的每个数字都被调用,因此您可以轻松地看到程序如何与库交互。对于ic_push(),还将输出InfluxDB的基本信息头和响应。
  • Level = 2表示与level = 1相同,并且还输出InfluxDB行协议的详细信息——如果您向InfluxDB写入大量数据,这将可能很大。

编译

有经验的C程序员会发现代码只有300行左右,主要在ic.c和example.c中使用示例。代码在GitHub上:  github.com/nigelargriffiths/InfluxDB-C-client。文件如下

  1. ic.h - 用于访问ic.c中函数的头文件
  2. ic.c - 实际的ic代码。通过在您的应用程序代码或example.c代码中编译来使用它。也可以通过创建库来使用它。
  3. example.c - 简单示例代码,帮助您正确使用函数。包括启动函数然后是简单的测量和包含子数据的测量。
  4. ic_all_in_one.c - 这是ic.c和example.c代码在一个文件中。如果您想快速编译并试验代码,这很有用。
  5. InfluxDB_C_client_example_Grafana_Dashboard.json - 允许更改主机名的有效Grafana仪表板

选项是

使用ic.c文件作为数据收集程序的基础。将您的代码替换为示例main()函数中的代码。

  • 选项 1:带有编译器的
cc ic_all_in_one.c -g -O3 -o ic_test

如果您的编译器关于“isnan”出现错误,请在编译器命令中添加数学库: -lm

  • 选项 2:创建一个可以添加到您的应用程序中的库。在您的应用程序中包含ic.h头文件,然后调用ic库函数
# Compile as a library archive
cc ic.c -g -O3 -c

# Check you have an archive
ls -l ic.a

# Compile other code and include the library
cc -g -O3 mycode.c ic.o -o myapp

运行示例代码

在ic_all_in_one.c文件的末尾,main()函数中有示例数据捕获代码。   这可以编译以开始。您将必须修改mail()函数以及您与InfluxDB和InfluxDB数据库的连接详细信息。

示例代码如下

ic_influx_database("silver2", 8086, "ic");
       ic_influx_userpw("nigel", "secret");

       ic_debug(2);

按照以下方式更改这些代码行

  1. 将"silver2"更改为您的InfluxDB服务器的主机名。您也可以使用IP地址。
  2. 8086是InfluxDB的默认端口号 - 如果使用非标准端口号,请更改此端口号。
  3. "ic"是InfluxDB服务器中的数据库名(也称为桶)- 我建议快速测试时使用"ic"。通常,我们选择一个有意义的数据库名称。   确保您已创建了名为"ic"的InfluxDB数据库或您决定的任何名称。
  4. 如果为访问InfluxDB设置了用户名和密码,则使用用户名和密码
  5. 您可能希望使用ic_debug(level)设置调试级别。其中0="无输出",1="输出您调用的ic函数",2="也输出发送到InfluxDB的数据的详细信息。

使用以下命令编译示例代码

cc ic_all_in_one.c -g -O3 -o ic_test

现在您有一个名为“ic_test”的可执行二进制文件。

调试级别为2的示例输出(所有可能的调试消息)。

[nag@silver2 ic]$ ./ic_test
ic_influx_by_hostname(host=silver2,port=8086,database=ic))
ic_influx_by_hostname hostname=silver2 converted to ip address 9.137.62.12))
ic_influx_userpw(username=nigel,password=secret))
ic_tags(host=silver2.aixncc.uk.ibm.com)
ic_measure("cpu") count=35
ic_long("user",30) count=44
ic_double("system",8.3) count=57
ic_string("status","low") count=70
ic_measureend()
ic_measure("disks") count=110
ic_sub("sda1") count=125
ic_long("reads",26) count=135
ic_double("writes",73.3) count=149
ic_subend()
ic_sub("sda2") count=204
ic_long("reads",51) count=214
ic_double("writes",101.5) count=229
ic_subend()
ic_measureend()
ic_push() size=232
socket: trying to connect to "9.137.62.12":8086
buffer size=88
buffer=<POST /write?db=ic&u=nigel&p=secret HTTP/1.1
Host: silver2:8086
Content-Length: 232

>
output size=232 output=
<cpu,host=silver2.aixncc.uk.ibm.com user=30i,system=8.284,status="low"  
disks,host=silver2.aixncc.uk.ibm.com,disk_name=sda1 reads=26i,writes=73.266  
disks,host=silver2.aixncc.uk.ibm.com,disk_name=sda2 reads=51i,writes=101.544  
>
written=232 bytes sent=0 total=232
received bytes=249 data=<HTTP/1.1 204 No Content
Content-Type: application/json
Request-Id: 9f6edc98-584f-11eb-be71-3a71321b9604
X-Influxdb-Build: OSS
X-Influxdb-Version: 1.7.10
X-Request-Id: 9f6edc98-584f-11eb-be71-3a71321b9604
Date: Sat, 16 Jan 2021 23:07:36 GMT

>
http-code=204 text=No Content [204=Success]
ic_push complete

注意

  • "26i"和"51i"是整数值的表示法。
  • 以ic_开始的行告诉您如何调用ic包。
  • 在ic_push()之后记录了与InfluxDB的交互。
  • 发送的数据通过套接字以HTTP包括POST详细信息输出。
  • Influx Line Protocol数据。
  • ic_push()获取从InfluxDB返回的结果。这是一个简单的确认消息。
  • 204消息和文本"No Content"表示成功。InfluxDB正在回复"no comment";也就是说,"没有问题",数据已保存。如果数据有问题,则InfluxDB返回其他错误代码,描述问题的文本以及需要更改的内容。

我们可以在InfluxDB中找到数据吗?

一旦您使用“ic”库和程序将统计数据保存到InfluxDB,在尝试绘图之前检查数据是否正确保存是一个好主意。这可以通过名为“influx”的InfluxDB命令行界面来完成,只需要几个简单的命令。   在这里,我们选择“ic”数据库(使用ic)并列出已保存的测量值(显示测量值)。此示例输出是从运行ic.c文件中的示例代码生成的,   因此CPU和磁盘统计数据是伪造的数据。

[nag@silver2 ic]$ influx
Connected to https://127.0.0.1:8086 version 1.7.10
InfluxDB shell version: 1.8.3

> use ic
Using database ic

> show measurements
name: measurements
name
----
cpu
disks

> select * from cpu
name: cpu
time                host                      status system user
----                ----                      ------ ------ ----
1610838551375866432 silver2.aixncc.uk.ibm.com low    8.284  30
1610838552391246233 silver2.aixncc.uk.ibm.com high   8.284  39
1610838553392913108 silver2.aixncc.uk.ibm.com high   6.284  60
1610838554394548129 silver2.aixncc.uk.ibm.com high   9.284  24

> select * from disks
name: disks
time                disk_name host                      reads writes
----                --------- ----                      ----- ------
1610838551375866432 sda0      silver2.aixncc.uk.ibm.com 1     1
1610838551375866432 sda1      silver2.aixncc.uk.ibm.com 26    51.272
1610838551375866432 sda2      silver2.aixncc.uk.ibm.com 25    57.556
1610838552391246233 sda0      silver2.aixncc.uk.ibm.com 1     1
1610838552391246233 sda1      silver2.aixncc.uk.ibm.com 24    51.272
1610838552391246233 sda2      silver2.aixncc.uk.ibm.com 1     38.704
1610838553392913108 sda0      silver2.aixncc.uk.ibm.com 1     1
1610838553392913108 sda1      silver2.aixncc.uk.ibm.com 10    7.284
1610838553392913108 sda2      silver2.aixncc.uk.ibm.com 41    13.568
1610838554394548129 sda0      silver2.aixncc.uk.ibm.com 1     1
1610838554394548129 sda1      silver2.aixncc.uk.ibm.com 13    57.556
1610838554394548129 sda2      silver2.aixncc.uk.ibm.com 59    170.668

> exit

用于可视InfluxDB数据的Grafana图形的示例

Grafana是图形InfluxDB数据时的一个流行选择,以下是几个伪造数据的简单线形图。

grafana influxdb graphs

在Grafana仪表板中,两个图形面板的定义如下

对于简单的CPU统计信息,测量值被命名。Grafana仪表板CPU统计InfluxDB? 对于磁盘统计信息,每个服务器上都有不同数量的磁盘,因此代码使用ic_sub()来处理。Grafana可以计算子测量磁盘的数量,并确定如何显示该数量。注意“GROUP BY”和“ALIAS BY”字段的使用。

influxdb group by

保修=无

  • 严格“自行承担风险”。