InfluxDB C++库介绍和使用

InfluxDB C++库介绍和使用

InfluxDB是现在使用排名最高的开源时序数据库,官方提供很多种语言的API进行库操作,包括Go、Java、JavaScript、JavaScript (Node.js)、PHP、Python等等,但是却不提供C++的支持。对于需要使用C++语言操作InfluxDB的场景,就有点麻烦。还好,gitbub上Influxdb-cxx项目提供了C++的方案。

这里介绍一下Influxdb-cxx的编译、裁剪和使用。需要注意的是,Influxdb-cxx需要使用支持C++17的编译器才能编译。

1 编译

下载代码https://github.com/awegrzyn/influxdb-cxx

1.1 裁剪掉boost库

Influxdb-cxx提供了三种协议操作InfluxDB,分别为HTTP,UDP和Unix socket。

                                                               表1. Influxdb-cxx支持的协议及依赖的第三方库

Name

Dependency

HTTP

libcurl

UDP

boost

Unix socket

boost

 

HTTP协议依赖libcurl库,UDP和Unix socket依赖boost库。因为我们只需要使用HTTP协议,为了减少依赖库,需要做一些裁剪,修改makefile如下:

  • File CMakeLists.txt

    注释掉下面两行:

         #set(Boost_USE_MULTITHREADED TRUE)

         #set(Boost_USE_MULTITHREADED TRUE)

  • File cmake/InfluxDBConfig.cmake.in

    注释掉下面一行

          #find_dependency(Boost)

 

这样,编译之后的库就只支持HTT协议了。

1.2 fix 查询bug

直接使用InfluxDB-cxx库查询数据会报404错误:

error:influx-cxx [HTTP::query]: Status code: 404

原因是代码有bug,构造的查询URL多了一个‘/’,如果将构造的URL打印出来,是下面的样子,多了一个红色位置的‘/’

http://tsuser:tsuser@localhost:8086//query?db=tsDB&q=select%20%2A%20from%20testTable

修改方法为:

修改HTTP.cxx

将函数void HTTP::initCurlRead(const std::string& url)中的

mReadUrl.insert(mReadUrl.find("?"), "query");

替换为如下代码:

auto position = mReadUrl.find("?");
  if (position == std::string::npos) {
     throw InfluxDBException("HTTP::initCurl", "Database not specified");
  }
  if (mReadUrl.at(position - 1) != '/') {
    mReadUrl.insert(position, "/query");
  } else {
    mReadUrl.insert(position, "query");
  }

1.3 编译

依次运行下面的命令:

$cd influxdb-cxx; mkdir build
$cd build
$cmake ..
$sudo make install

动态库和头文件会被安装到如下目录:

     /usr/local/lib/libInfluxDB.so

    /usr/local/include/Transport.h

    /usr/local/include/InfluxDB.h

    /usr/local/include/Point.h

    /usr/local/include/InfluxDBFactory.h

 

libInfluxDB.so依赖的第三方库如下:

$ ldd lib/libInfluxDB.so

         linux-vdso.so.1 (0x00007ffe59ba3000)

         libcurl.so.4 => /usr/lib/x86_64-linux-gnu/libcurl.so.4 (0x00007fa8b795e000)

         libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fa8b757e000)

         libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa8b7366000)

         libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa8b6f75000)

         libnghttp2.so.14 => /usr/lib/x86_64-linux-gnu/libnghttp2.so.14 (0x00007fa8b6d50000)

         libidn2.so.0 => /usr/lib/x86_64-linux-gnu/libidn2.so.0 (0x00007fa8b6b33000)

         librtmp.so.1 => /usr/lib/x86_64-linux-gnu/librtmp.so.1 (0x00007fa8b6917000)

         libpsl.so.5 => /usr/lib/x86_64-linux-gnu/libpsl.so.5 (0x00007fa8b6709000)

         libssl.so.1.1 => /usr/lib/x86_64-linux-gnu/libssl.so.1.1 (0x00007fa8b647c000)

         libcrypto.so.1.1 => /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 (0x00007fa8b5fb1000)

         libgssapi_krb5.so.2 => /usr/lib/x86_64-linux-gnu/libgssapi_krb5.so.2 (0x00007fa8b5d66000)

         libldap_r-2.4.so.2 => /usr/lib/x86_64-linux-gnu/libldap_r-2.4.so.2 (0x00007fa8b5b14000)

         liblber-2.4.so.2 => /usr/lib/x86_64-linux-gnu/liblber-2.4.so.2 (0x00007fa8b5906000)

         libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fa8b56e9000)

         libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa8b54ca000)

         libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa8b512c000)

         /lib64/ld-linux-x86-64.so.2 (0x00007fa8b7def000)

         libunistring.so.2 => /usr/lib/x86_64-linux-gnu/libunistring.so.2 (0x00007fa8b4dae000)

         libgnutls.so.30 => /usr/lib/x86_64-linux-gnu/libgnutls.so.30 (0x00007fa8b4a48000)

         libhogweed.so.4 => /usr/lib/x86_64-linux-gnu/libhogweed.so.4 (0x00007fa8b4814000)

         libnettle.so.6 => /usr/lib/x86_64-linux-gnu/libnettle.so.6 (0x00007fa8b45de000)

         libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007fa8b435d000)

         libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa8b4159000)

         libkrb5.so.3 => /usr/lib/x86_64-linux-gnu/libkrb5.so.3 (0x00007fa8b3e83000)

         libk5crypto.so.3 => /usr/lib/x86_64-linux-gnu/libk5crypto.so.3 (0x00007fa8b3c51000)

         libcom_err.so.2 => /lib/x86_64-linux-gnu/libcom_err.so.2 (0x00007fa8b3a4d000)

         libkrb5support.so.0 => /usr/lib/x86_64-linux-gnu/libkrb5support.so.0 (0x00007fa8b3842000)

         libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007fa8b3627000)

         libsasl2.so.2 => /usr/lib/x86_64-linux-gnu/libsasl2.so.2 (0x00007fa8b340c000)

         libgssapi.so.3 => /usr/lib/x86_64-linux-gnu/libgssapi.so.3 (0x00007fa8b31cb000)

         libp11-kit.so.0 => /usr/lib/x86_64-linux-gnu/libp11-kit.so.0 (0x00007fa8b2e9c000)

         libtasn1.so.6 => /usr/lib/x86_64-linux-gnu/libtasn1.so.6 (0x00007fa8b2c89000)

         libkeyutils.so.1 => /lib/x86_64-linux-gnu/libkeyutils.so.1 (0x00007fa8b2a85000)

         libheimntlm.so.0 => /usr/lib/x86_64-linux-gnu/libheimntlm.so.0 (0x00007fa8b287c000)

         libkrb5.so.26 => /usr/lib/x86_64-linux-gnu/libkrb5.so.26 (0x00007fa8b25ef000)

         libasn1.so.8 => /usr/lib/x86_64-linux-gnu/libasn1.so.8 (0x00007fa8b234d000)

         libhcrypto.so.4 => /usr/lib/x86_64-linux-gnu/libhcrypto.so.4 (0x00007fa8b2117000)

         libroken.so.18 => /usr/lib/x86_64-linux-gnu/libroken.so.18 (0x00007fa8b1f01000)

         libffi.so.6 => /usr/lib/x86_64-linux-gnu/libffi.so.6 (0x00007fa8b1cf9000)

         libwind.so.0 => /usr/lib/x86_64-linux-gnu/libwind.so.0 (0x00007fa8b1ad0000)

         libheimbase.so.1 => /usr/lib/x86_64-linux-gnu/libheimbase.so.1 (0x00007fa8b18c1000)

         libhx509.so.5 => /usr/lib/x86_64-linux-gnu/libhx509.so.5 (0x00007fa8b1677000)

         libsqlite3.so.0 => /usr/lib/x86_64-linux-gnu/libsqlite3.so.0 (0x00007fa8b136e000)

         libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007fa8b1136000)

2 API介绍

2.1创建一个Influxdb client

使用InfluxDBFactory::Get(std::string url)函数可以创建一个Infludb 的client。

具体说明如下:

#include

std::unique_ptr InfluxDBFactory::Get(std::string url)

入参

输入为一个字符串的URL,格式为:

[protocol]://[username:password@]host:port[/?db=database]

各个字段的说明为:

protocol:具体的协议,可以为http/https/udp/unix,见表2

username:访问数据库的用户名

password:用户名对应的密码

host:主机地址

port:端口号,默认为8086

db=database :database替换为使用的数据库

                                                                表2:协议格式及例子

Name

Dependency

URI protocol

Sample URI

HTTP

cURL

http/https

http://localhost:8086/?db=

UDP

boost

udp

udp://localhost:8094

Unix socket

boost

unix

unix:///tmp/telegraf.sock

返回值

返回一个InfluxDB对象的指针,所有的操作通过此指针完成

示例代码:

#include "InfluxDBFactory.h"
#include "InfluxDBException.h"
#include 
using namespace std;

int main()
{
  std::unique_ptr dbPtr;
  try
  {
    dbPtr = influxdb::InfluxDBFactory::Get("http://tsuser:tsuser@localhost:8086/?db=tsDB");
    
  }
  catch(influxdb::InfluxDBException& e)
  {
    cout <<"error:"<

 

2.2向数据库插入数据

使用InfluxDB::write()接口插入数据,具体格式为:

#include "InfluxDB.h"

void InfluxDB::write(Point&& metric);

入参是一个Point对象,所以重要的工作是将数据构造成Point对象。

                                       表3:Point对象的方法

方法名

功能

Point::Point(const std::string& measurement)

设定表的名字,在构造函数指定

Point&& Point::addField(std::string_view name, std::variant value)

添加一个field键值对,field的值可以使init, long int,string和double

Point&& Point::addTag(std::string_view key, std::string_view value)

添加一个tag键值对, tag的值只能是string类型

std::string Point::getName()

返回表明

std::string Point::getFields()

返回所有的fields键值对,格式为:”name=value,name=value,name=value”

std::string Point::getTags()

返回所有的tags键值对,格式为:”name=value,name=value,name=value”

 

示例代码:

#include "InfluxDBFactory.h"
#include "InfluxDBException.h"
#include 
using namespace std;

int main()
{
  std::unique_ptr dbPtr;
  try
  {
    dbPtr = influxdb::InfluxDBFactory::Get("http://tsuser:tsuser@localhost:8086/?db=tsDB");
    influxdb::Point point("testTable");
    point.addField("Temperature", 100.0);
    point.addTag("Device", "D1");
    dbPtr->write(std::move(point));
  }
  catch(influxdb::InfluxDBException& e)
  {
    cout <<"error:"<

2.3 查询数据

使用InfluxDB::query ()接口插入数据,具体格式为:

#include "InfluxDB.h"

std::vector InfluxDB::query(const std::string& query);

输入

输入为查询的sql语句,例如"SELECT * FROM test"

输出

输出为Point对象的vector。

可以通过表3中说明的Point类的方法获取实际的值。

注意,query ()接口只有在使用Boost库的情况下才能工作,因为需要使用Boost中的Json文件解析功能来处理数据库返回的结果。

示例代码:

#include "InfluxDBFactory.h"
#include "InfluxDBException.h"
#include 
using namespace std;

int main()
{
  std::unique_ptr dbPtr;
  try
  {
    dbPtr = influxdb::InfluxDBFactory::Get("http://tsuser:tsuser@localhost:8086/?db=tsDB");
    std::vector dbPoints = dbPtr->query("select * from testTable");
    for(int i = 0; i < dbPoints.size(); i++)
    {
      cout << "===========================" << endl;
      cout << "Name: " <

2.4库的链接和使用

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/local/eiconfig/influxdb-cxx/lib

$ g++ -std=c++17 -o write write.cpp -L/local/eiconfig/influxdb-cxx/lib -lInfluxDB -I/local/eiconfig/influxdb-cxx/include

$ g++ -std=c++17 -o query query.cpp -L/local/eiconfig/influxdb-cxx/lib -lInfluxDB -I/local/eiconfig/influxdb-cxx/include

 

3 常用sql格式

3.1 时间格式

influxdb时间的默认显示使用的是unix时间戳,执行命令precision rfc3339 可以设置时间格式

> select * from testTable

name: testTable

time                Device Temperature

----                ------ -----------

1602836361586833335 D1     100

> precision rfc3339

> select * from testTable

name: testTable

time                           Device Temperature

----                           ------ -----------

2020-10-16T08:19:21.586833335Z D1     100

 

但是这里显示采用的时区为UTC时区,与中国时区差了8个小时,因此执行命令

 

select * from testTable tz('Asia/Shanghai'), 查询结果如下

> select * from testTable tz('Asia/Shanghai')

name: testTable

time                                Device Temperature

----                                ------ -----------

2020-10-16T16:19:21.586833335+08:00 D1     100

 

3.2基于时间查询数据

1)时间格式为年月日

select * from testTable where time >='2020-10-16T16:19:21Z' tz('Asia/Shanghai')

这时,这里的时间是UTC 0时区的时间

 

> select * from testTable tz('Asia/Shanghai')

name: testTable

time                                Device Temperature

----                                ------ -----------

2020-10-16T16:19:21.586833335+08:00 D1     100

 

> select * from testTable where time >='2020-10-16T16:19:21Z' tz('Asia/Shanghai')

查不到数据

 

> select * from testTable where time >='2020-10-16T08:19:21Z' tz('Asia/Shanghai')

name: testTable

time                                Device Temperature

----                                ------ -----------

2020-10-16T16:19:21.586833335+08:00 D1     100

可以查到数据。

 

2)时间格式是秒

通过转换函数将'2020-10-16T16:19:21Z'转换为秒,因为influxDB中时间精确到纳秒,所以需要需要乘上6个0.

 

> select * from testTable where time < 1602838080000000000 and time > 1602837598559188326;

name: testTable

time                Device Temperature

----                ------ -----------

1602837655477990673 D1     100

1602837852824072231 D1     100

1602837944389538189 D1     100

1602838064225581200 D1     100

>

3.3 利用curl命令操作influxDB

具体的用法在官方文档中https://docs.influxdata.com/influxdb/v1.8/tools/api/#query-http-endpoint 有详细说明。

Curl的用法可以参考http://www.ruanyifeng.com/blog/2019/09/curl-reference.html

简单说明一下:

1) -G参数是指定用get方法,如果不加-G,则是post方法。

2)--data-urlencode参数将发送的数据进行 URL 编码,例如发送的数据之间如果有空格,就需要需要进行 URL 编码

 

写数据库

curl -i -XPOST "http://localhost:8086/write?db=tsDB&u=tsuser&p=tsuser" --data-binary 'mymeas,mytag=1 myfield=91'

 

查询数据库

curl -G 'http://localhost:8086/query?db=tsDB' --data-urlencode 'q=SELECT * FROM "testTable"'

编码之后的实际URL为:

http://tsuser:tsuser@localhost:8086/query?db=tsDB&q=select%20%2A%20from%20testTable

将此URL输入浏览器也可查询到数据。

你可能感兴趣的:(工业互联网+边缘计算)