spring接入influxdb记录日志。
docker-compose 安装 influxdb
version: '2'
services:
influxdb:
image: influxdb
container_name: influxdb
volumes:
- /data/influxdb/conf:/etc/influxdb
- /data/influxdb/data:/var/lib/influxdb/data
- /data/influxdb/meta:/var/lib/influxdb/meta
- /data/influxdb/wal:/var/lib/influxdb/wal
ports:
- "8086:8086"
restart: always
maven依赖:
org.influxdb
influxdb-java
2.19
com.google.code.gson
gson
参考的开源项目:
https://github.com/ashishdoneriya/influxdb-java
设置好数据库连接设置
influx:
username: admin
password: admin
host: 127.0.0.1
port: 8086
database: logs
将Configuration注册到spring容器
package com.wooki.feature.influxdb.entity;
import com.wooki.feature.influxdb.constant.Constants;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class Configuration {
private String protocol = Constants.HTTP;
@Value("${influx.host}")
private String host;
@Value("${influx.port}")
private String port;
@Value("${influx.username}")
private String username;
@Value("${influx.password}")
private String password;
@Value("${influx.database}")
private String database;
public Configuration() {
}
public Configuration(String host, String port, String username, String password, String database) {
this.host = host.toLowerCase();
this.port = port;
this.username = username;
this.password = password;
this.database = database;
}
public Configuration(String protocol, String host, String port, String username, String password, String database) {
this(host, port, username, password, database);
this.protocol = protocol;
}
}
自己写service,使用MySQL语法,拼接sql语句,实现insert、query基本功能,批量插入写的较简单
package com.wooki.feature.influxdb.service.impl;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.plugins.Page;
import com.wooki.feature.influxdb.util.Utilities;
import com.wooki.feature.influxdb.entity.*;
import com.wooki.feature.influxdb.service.InfluxDBService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @author aobs
* @date 2020-06-22 17:28
*/
@Service
public class InfluxDBServiceImpl implements InfluxDBService {
@Autowired
Configuration configuration;
@Override
public void createDatabase(String name) throws Exception {
configuration.setDatabase(name);
Utilities.createDatabase(configuration);
}
@Override
public void insert(InfluxDBInsert influxDBInsert) throws Exception {
DataWriter writer = new DataWriter(configuration);
// 数据库
writer.setMeasurement(influxDBInsert.getType());
// Default is in seconds
writer.setTimeUnit(TimeUnit.MILLISECONDS);
writer.addField("deviceName" , influxDBInsert.getDeviceName());
writer.addField("msg" , influxDBInsert.getMsg());
writer.addField("body" , influxDBInsert.getBody());
// 企业id 做索引
writer.addTag("enterpriseId", String.valueOf(influxDBInsert.getEnterpriseId()));
// If we'll set time it will set automatically
writer.setTime(influxDBInsert.getTime().getTime());
writer.writeData();
}
@Override
public void insertBatch(List influxDBInserts) throws Exception {
DataWriter writer = new DataWriter(configuration);
writer.setTimeUnit(TimeUnit.MILLISECONDS);
for (InfluxDBInsert influxDBInsert : influxDBInserts) {
// Influxdb saves one point at one time. To add another point at same
// time we can use tags otherwise it will override the previous point.
writer.setMeasurement(influxDBInsert.getType());
writer.addField("deviceName" , influxDBInsert.getDeviceName());
writer.addField("msg" , influxDBInsert.getMsg());
writer.addTag("enterpriseId", String.valueOf(influxDBInsert.getEnterpriseId()));
writer.setTime(influxDBInsert.getTime().getTime());
writer.writeData();
}
}
@Override
public InfluxResultSet query(InfluxDBQuery influxDBQuery) throws IOException, URISyntaxException {
Integer current = influxDBQuery.getCurrent();
if (current == null) {
current = 1;
influxDBQuery.setCurrent(current);
}
Integer influxDBQuerySize = influxDBQuery.getSize();
if (influxDBQuerySize == null) {
influxDBQuerySize = 10;
influxDBQuery.setSize(influxDBQuerySize);
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
String condition = " * ";
String countPagesCondition = " count(msg) ";
StringBuffer querySQL = new StringBuffer("select "+condition+" from ");
StringBuffer queryCount = new StringBuffer("select " + countPagesCondition + " from ");
String type = influxDBQuery.getType();
// 类型
querySQL.append("\""+type+"\"").append(" where 1 = 1 ");
queryCount.append("\""+type+"\"").append(" where 1 = 1 ");
/**
* tag索引存储类型为string,使用单引号查值
*/
querySQL.append(" and enterpriseId = '" + influxDBQuery.getEnterpriseId() + "' ");
queryCount.append(" and enterpriseId = '" + influxDBQuery.getEnterpriseId() + "' ");
// 设备名称
String deviceName = influxDBQuery.getDeviceName();
if (deviceName != null) {
querySQL.append(" and deviceName=~/"+deviceName+"/ ");
queryCount.append(" and deviceName=~/"+deviceName+"/ ");
}
// 时间范围
Date beginTime = influxDBQuery.getBeginTime();
Date endTime = influxDBQuery.getEndTime();
if (beginTime == null) {
beginTime = DateUtil.beginOfDay(new Date());
}
if (endTime == null) {
endTime = DateUtil.endOfDay(new Date());
}
querySQL.append(" and time >= " + "'"+simpleDateFormat.format(beginTime)+"'");
queryCount.append(" and time >= " + "'"+simpleDateFormat.format(beginTime)+"'");
querySQL.append(" and time <= " + "'"+simpleDateFormat.format(endTime) + "'");
queryCount.append(" and time <= " + "'"+simpleDateFormat.format(endTime) + "'");
/**
* 分页,offset从0开始
* 排序
*/
influxDBQuery = countPage(influxDBQuery);
querySQL.append(" ORDER BY time DESC ");
querySQL.append(" LIMIT "+influxDBQuery.getCurrent() +" OFFSET " + influxDBQuery.getSize());
// pages 总页数
Query queryPages = new Query();
queryPages.setCustomQuery(String.valueOf(queryCount));
DataReader readerPages = new DataReader(queryPages, configuration);
InfluxResultSet result = readerPages.getResult();
List results = result.getResults();
InfluxResultSet.Result result1 = results.get(0);
List series = result1.getSeries();
InfluxResultSet.Result.Series series1 = series.get(0);
List> values = series1.getValues();
List
写入数据时指定编码格式,参考的开源项目为老外写的,此处改为utf-8,否则存入的中文乱码
package com.wooki.feature.influxdb.entity;
import cn.hutool.core.util.CharsetUtil;
import com.google.gson.Gson;
import com.wooki.feature.influxdb.constant.Constants;
import com.wooki.feature.influxdb.util.TimeUtil;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import static com.wooki.feature.influxdb.constant.Constants.*;
public class DataWriter {
private Configuration configuration;
private String tableName;
private Map fields;
private Map tags;
private TimeUnit timeUnit;
private Long time;
public DataWriter(Configuration configuration) throws Exception {
this.configuration = configuration;
}
public void writeData() throws Exception {
if (tableName == null || tableName.isEmpty() || fields == null || fields.isEmpty()) {
throw new Exception(INSUFFICIENT_INFORMATION_TO_WRITE_DATA);
}
// Sending data in the format of
// tableName,tag_key1=tag_value1,tag_key2=tag_value2 column1=value1,column2=value2,column3=value3 timestamp
StringBuffer sb = new StringBuffer(tableName);
// Adding Tags
if (tags != null && !tags.isEmpty()) {
for (Entry tag : tags.entrySet()) {
sb.append(COMMA).append(tag.getKey()).append(EQUAL).append(tag.getValue());
}
}
sb.append(Constants.SPACE);
Entry e;
// Adding Columns
Iterator> fieldsIterator = fields.entrySet().iterator();
if (fieldsIterator.hasNext()) {
e = fieldsIterator.next();
sb.append(e.getKey()).append(EQUAL).append(parseValue(e.getValue()));
}
while (fieldsIterator.hasNext()) {
e = fieldsIterator.next();
sb.append(COMMA).append(e.getKey()).append(EQUAL).append(parseValue(e.getValue()));
}
sb.append(SPACE);
if (time != null) {
sb.append(time);
} else {
sb.append(System.currentTimeMillis() / 1000);
}
CloseableHttpClient httpClient = null;
try {
// Sending data
httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(getURL());
httpPost.setEntity(new StringEntity(sb.toString(), CharsetUtil.charset("UTF-8")));
CloseableHttpResponse response = httpClient.execute(httpPost);
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() != 204) {
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
InfluxResultSet influxResultSet = new Gson().fromJson(EntityUtils.toString(responseEntity), InfluxResultSet.class);
String error = influxResultSet.getError();
if (error != null && !error.isEmpty()) {
throw new Exception(error);
}
}
}
} finally {
fields.clear();
if (tags != null) {
tags.clear();
}
if (httpClient != null) {
httpClient.close();
}
}
}
private String parseValue(Object value) {
if (value instanceof Integer) {
return String.valueOf(value) + Constants.I;
} else if (value instanceof Double || value instanceof Float) {
return String.valueOf(value);
} else if (value instanceof Boolean) {
return String.valueOf((boolean) value);
} else {
return BACKSLASH_QUOTATION + value + BACKSLASH_QUOTATION;
}
}
// create and get url to send post request
private URI getURL() throws URISyntaxException {
URIBuilder uriBuilder = new URIBuilder();
int port = Integer.parseInt(configuration.getPort());
if (timeUnit == null) {
timeUnit = TimeUnit.SECONDS;
}
uriBuilder.setScheme(configuration.getProtocol()).setHost(configuration.getHost())
.setPort(port).setPath(Constants.WRITE)
.setParameter(Constants.DB, configuration.getDatabase())
.setParameter(Constants.U, configuration.getUsername())
.setParameter(Constants.P, configuration.getPassword())
.setParameter(Constants.PRECISION, TimeUtil.toTimePrecision(timeUnit));
return uriBuilder.build();
}
public void setMeasurement(String measurementName) {
this.tableName = measurementName;
}
@Deprecated
public void setTableName(String tableName) {
this.tableName = tableName;
}
public void setFields(Map fields) {
this.fields = fields;
}
public Map getTags() {
return tags;
}
public void setTags(Map tags) {
this.tags = tags;
}
public void addTag(String tagKey, String tagValue) {
if (tags == null) {
tags = new HashMap();
}
tags.put(tagKey, tagValue);
}
public void setTime(Long time, TimeUnit timeUnit) {
this.time = time;
this.setTimeUnit(timeUnit);
}
/**
* Set time unit, Default is in seconds.
* @param timeUnit
*/
public void setTimeUnit(TimeUnit timeUnit) {
this.timeUnit = timeUnit;
}
public void setTime(Long time) {
this.time = time;
}
public void addField(String columnName, Object value) {
if (fields == null) {
fields = new HashMap();
}
fields.put(columnName, value);
}
}