Using InfluxDB from a Java Enterprise application

InfluxDB is a time series database. Thanks to its high performance datastore it is used as a backing store for any timestamped data, including DevOps monitoring, application metrics, IoT sensor data, and real-time analytics. In this tutorial we will learn how to use it in Java running on the top of WildFly.

As we said, InfluxDB is a database that has been optimized for time series data. Internally its data engine is organized by “time series”, which contain a measured value, like “memory_load” or “temperature”. Time series have zero to many points, one for each discrete sample of the metric. Points consist of time (a timestamp), a measurement (“cpu_load”, for example), at least one key-value field.

In short, you can think of a measurement as an SQL table, where the primary index is always time where the measure is taken. Tags and fields are also columns in the table. The difference with standard Databases is that, with InfluxDB, you can have millions of measurements, you don’t have to define schemas up-front, and null values aren’t stored.

Starting InfluxDB

The download page of InfluxDB contains the possible choices for downloading the product: https://portal.influxdata.com/downloads

To have an instant start, if you have Docker installed, simply launch its image with:

docker run --rm -p 8083:8083 -p 8086:8086 --expose 8090 --expose 8099 --name influxdb tutum/influxdb

Coding a basic application

Now that the database is started, we will code a minimal application which uses it. The Java Client library for InfluxDB is available at: https://github.com/influxdata/influxdb-java/

The simplest way to get started is including the influxdb library in your pom.xml, leaving the default scope so that all required dependencies will be packaged in your application:

<dependency>
        <groupId>org.influxdb</groupId>
        <artifactId>influxdb-java</artifactId>
        <version>2.5</version>
</dependency>

The main interface towards InfluxDB is org.influxdb.InfluxDB which allows connecting through a Factory. A CDI friendly approach which @Produces this class is:

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Model;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Named;

import org.influxdb.InfluxDB;
import org.influxdb.InfluxDBFactory;

@ApplicationScoped
public class Producer {

	private InfluxDB influxDB;

	@Produces
	@Named
	public InfluxDB getInfluxDB() {
		InfluxDB db = InfluxDBFactory.connect("http://172.17.0.2:8086", "root", "root");

		String dbName = "java";

   	        // Create a database
		db.createDatabase(dbName);
		return db;
	}

}

To keep everything simple, we have hardcoded the database IP Address (which is in our case 172.17.0.2) and the database to create. Now that we have a producer, here’s a simple Servlet which uses InfluxDB to insert one point into our Database:

package demo;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.influxdb.InfluxDB;
import org.influxdb.InfluxDBFactory;
import org.influxdb.dto.BatchPoints;
import org.influxdb.dto.Point;
import org.influxdb.dto.Query;
import org.influxdb.dto.QueryResult;

@WebServlet("/Test")
public class Test extends HttpServlet {
	@Inject
	InfluxDB influxDB;;

	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		PrintWriter out = response.getWriter();
		// Create a 'batch' of example 'points'
		BatchPoints batchPoints = BatchPoints.database("java").tag("async", "true").retentionPolicy("autogen")
				.consistency(InfluxDB.ConsistencyLevel.ALL).tag("BatchTag", "BatchTagValue") 
				.build();

		long free = Runtime.getRuntime().freeMemory();
		Point point1 = Point.measurement("memory").time(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
				.addField("free", free).tag("MemoryTag", "MemoryTagValue")  											 
				.build();
		batchPoints.point(point1);

		// Write them to InfluxDB
		influxDB.write(batchPoints);

		Query query = new Query("SELECT * FROM memory", "java");
		QueryResult queryResult = influxDB.query(query);

		// iterate the results and print details
		for (QueryResult.Result result : queryResult.getResults()) {

			// print details of the entire result
			System.out.println(result.toString());

			// iterate the series within the result
			for (QueryResult.Series series : result.getSeries()) {
				out.println("series.getName() = " + series.getName());
				out.println("series.getColumns() = " + series.getColumns());
				out.println("series.getValues() = " + series.getValues());
				out.println("series.getTags() = " + series.getTags());
			}
		}
		out.flush();

	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}


The expected output, is the series which has been just created, which contains the current Free memory in the application server:

series.getName() = memory
series.getColumns() = [time, BatchTag, MemoryTag, async, free]
series.getValues() = [[2017-02-22T14:59:31.14Z, BatchTagValue, MemoryTagValue, true, 7.9285432E7]]
series.getTags() = null

As a proof of concept, jump into the InfluxDB Web application and check the following query:

select * from memory

Here’s our measure just inserted:

Influxdb tutorial java

As side note, in this simple example we haven’t included it, but you are able to remove a database as well with the following method:

 // Delete the database
 influxDB.deleteDatabase("java");

Installing InfluxDB as a module

If you want to reuse InfluxDB across several applications, it might be worthy to install it as a module. You will need, besides the influxdb-java JAR file, all these libraries in your main module folder:

converter-moshi-2.1.0.jar
guava-20.0.jar
influxdb-java-2.5.jar
logging-interceptor-3.5.0.jar
moshi-1.2.0.jar
okhttp-3.5.0.jar
okio-1.11.0.jar
retrofit-2.1.0.jar

And here is the needed module.xml:

<module xmlns="urn:jboss:module:1.1" name="com.influxdb">
   <resources>
      <resource-root path="influxdb-java-2.5.jar" />
      <resource-root path="converter-moshi-2.1.0.jar" />
      <resource-root path="guava-20.0.jar" />
      <resource-root path="logging-interceptor-3.5.0.jar" />
      <resource-root path="moshi-1.2.0.jar" />
      <resource-root path="okhttp-3.5.0.jar" />
      <resource-root path="okio-1.11.0.jar" />
      <resource-root path="retrofit-2.1.0.jar" />
   </resources>
   <dependencies>
      <module name="javax.api" />
   </dependencies>
</module>

As libraries are now available in the server, you can set as “provided” your influxdb-java dependency:

Later we will see how to install the InfluxDB libraries as a module:

<dependency>
        <groupId>org.influxdb</groupId>
        <artifactId>influxdb-java</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
</dependency>

That’s all! In the next tutorial Displaying application server metrics with Grafana we will learn how to use Grafana to display Dashboards from InfluxDB Datasource.

Found the article helpful? if so please follow us on Socials