org.perfcake.reporting.destination.InfluxDbDestination.java Source code

Java tutorial

Introduction

Here is the source code for org.perfcake.reporting.destination.InfluxDbDestination.java

Source

/*
 * -----------------------------------------------------------------------\
 * PerfCake
 * 
 * Copyright (C) 2010 - 2016 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * -----------------------------------------------------------------------/
 */
package org.perfcake.reporting.destination;

import org.perfcake.PerfCakeConst;
import org.perfcake.PerfCakeException;
import org.perfcake.common.PeriodType;
import org.perfcake.reporting.Measurement;
import org.perfcake.reporting.Quantity;
import org.perfcake.reporting.ReportingException;
import org.perfcake.util.SslSocketFactoryFactory;
import org.perfcake.util.StringUtil;
import org.perfcake.util.properties.MandatoryProperty;

import com.google.gson.JsonArray;
import com.squareup.okhttp.OkHttpClient;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.influxdb.InfluxDB;
import org.influxdb.InfluxDBFactory;
import org.influxdb.dto.Point;
import retrofit.client.OkClient;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLSocketFactory;

/**
 * Writes the resulting data to InfluxDb using a simple HTTP REST client.
 * The reported data have information about the test progress (time in milliseconds since start, percentage and iteration),
 * real time of each result, and the complete results map. Quantities are stored without their unit.
 * Supports SSL connection. The database is by default created on connection.
 *
 * @author <a href="mailto:marvenec@gmail.com">Martin Ve?ea</a>
 */
public class InfluxDbDestination extends AbstractDestination {

    private static final Logger log = LogManager.getLogger(InfluxDbDestination.class);

    /**
     * InfluxDb server including protocol and port number. Supports SSL.
     */
    @MandatoryProperty
    private String serverUrl = "";

    /**
     * Name of InfluxDb database.
     */
    private String database = "perfcake";

    /**
     * Creates the database when connected. Requires admin privileges in InfluxDb.
     */
    private boolean createDatabase = true;

    /**
     * Name of the measurement in InfluxDb, serves as a database table.
     */
    private String measurement = "results";

    /**
     * InfluxDb user name.
     */
    @MandatoryProperty
    private String userName = "admin";

    /**
     * InfluxDb password.
     */
    @MandatoryProperty
    private String password = "admin";

    /**
     * Comma separated list of tags to be added to results.
     */
    private String tags = "";

    /**
     * SSL key store location.
     */
    private String keyStore;

    /**
     * SSL key store password.
     */
    private String keyStorePassword;

    /**
     * SSL trust store location.
     */
    private String trustStore;

    /**
     * SSL trust store password.
     */
    private String trustStorePassword;

    /**
     * Initialized SSL factory.
     */
    private SSLSocketFactory sslFactory = null;

    /**
     * Cached array with tags.
     */
    private JsonArray tagsArray = new JsonArray();

    /**
     * InfluxDb client.
     */
    private InfluxDB influxDb = null;

    @Override
    public void open() {
        Arrays.stream(tags.split(",")).map(StringUtil::trim).forEach(tagsArray::add);

        try {
            if ((keyStore != null && !"".equals(keyStore)) || (trustStore != null && !"".equals(trustStore))) {
                sslFactory = SslSocketFactoryFactory.newSslSocketFactory(keyStore, keyStorePassword, trustStore,
                        trustStorePassword);
            }
        } catch (PerfCakeException e) {
            log.warn("Unable to initialize SSL socket factory: ", e);
        }

        try {
            if (sslFactory != null) {
                final OkHttpClient client = new OkHttpClient();
                client.setSslSocketFactory(sslFactory);
                client.setHostnameVerifier((hostname, session) -> true);
                influxDb = InfluxDBFactory.connect(serverUrl, userName, password, new OkClient(client));
            } else {
                influxDb = InfluxDBFactory.connect(serverUrl, userName, password);
            }
            if (createDatabase) {
                influxDb.createDatabase(database);
            }
            influxDb.enableBatch(100, 500, TimeUnit.MILLISECONDS);
        } catch (RuntimeException rte) {
            influxDb = null;
            log.error("Unable to connect to InfluxDb: ", rte);
        }
    }

    @Override
    public void close() {
        if (influxDb != null) {
            influxDb.disableBatch(); // flushes batch
        }
    }

    @Override
    public void report(final Measurement measurement) throws ReportingException {
        if (influxDb == null) {
            throw new ReportingException("Not connected to InfluxDb.");
        }

        Point.Builder pBuilder = Point.measurement(this.measurement).time(System.currentTimeMillis(),
                TimeUnit.MILLISECONDS);

        pBuilder.addField(PeriodType.TIME.toString().toLowerCase(), measurement.getTime());
        pBuilder.addField(PeriodType.ITERATION.toString().toLowerCase(), measurement.getIteration());
        pBuilder.addField(PeriodType.PERCENTAGE.toString().toLowerCase(), measurement.getPercentage());
        pBuilder.addField(PerfCakeConst.TAGS_TAG, tagsArray.toString());

        measurement.getAll().forEach((k, v) -> {
            if (v instanceof Number) {
                pBuilder.addField(k, (Number) v);
            } else if (v instanceof Quantity) {
                pBuilder.addField(k, ((Quantity) v).getNumber());
            } else {
                pBuilder.addField(k, v.toString());
            }
        });

        influxDb.write(database, "default", pBuilder.build());
    }

    /**
     * Gets InfluxDb server including protocol and port number. Supports SSL.
     *
     * @return InfluxDb server including protocol and port number.
     */
    public String getServerUrl() {
        return serverUrl;
    }

    /**
     * Sets InfluxDb server including protocol and port number. Supports SSL.
     *
     * @param serverUrl
     *       InfluxDb server including protocol and port number.
     * @return Instance of this to support fluent API.
     */
    public InfluxDbDestination setServerUrl(final String serverUrl) {
        this.serverUrl = serverUrl;
        return this;
    }

    /**
     * Gets the name of InfluxDb database.
     *
     * @return The name of InfluxDb database.
     */
    public String getDatabase() {
        return database;
    }

    /**
     * Sets the name of InfluxDb database.
     *
     * @param database
     *       The name of InfluxDb database.
     * @return Instance of this to support fluent API.
     */
    public InfluxDbDestination setDatabase(final String database) {
        this.database = database;
        return this;
    }

    /**
     * Should the database be created upon connecting to InfluxDb? Defaults to true.
     *
     * @return True if and only if the database should be created when connected to InfluxDb.
     */
    public boolean isCreateDatabase() {
        return createDatabase;
    }

    /**
     * Sets whether the database should be created upon connecting to InfluxDb. Dafaults to true.
     *
     * @param createDatabase
     *       True if and only if the database should be created when connected to InfluxDb.
     * @return Instance of this to support fluent API.
     */
    public InfluxDbDestination setCreateDatabase(final boolean createDatabase) {
        this.createDatabase = createDatabase;
        return this;
    }

    /**
     * Gets the name of the measurement in InfluxDb, serves as a database table.
     *
     * @return The name of the measurement in InfluxDb, serves as a database table.
     */
    public String getMeasurement() {
        return measurement;
    }

    /**
     * Sets the name of the measurement in InfluxDb, serves as a database table.
     *
     * @param measurement
     *       The name of the measurement in InfluxDb, serves as a database table.
     * @return Instance of this to support fluent API.
     */
    public InfluxDbDestination setMeasurement(final String measurement) {
        this.measurement = measurement;
        return this;
    }

    /**
     * Gets the name of InfluxDb user.
     *
     * @return The name of InfluxDb user.
     */
    public String getUserName() {
        return userName;
    }

    /**
     * Sets the name of InfluxDb user.
     *
     * @param userName
     *       The name of InfluxDb user.
     * @return Instance of this to support fluent API.
     */
    public InfluxDbDestination setUserName(final String userName) {
        this.userName = userName;
        return this;
    }

    /**
     * Gets the InfluxDb user password.
     *
     * @return The InfluxDb user password.
     */
    public String getPassword() {
        return password;
    }

    /**
     * Sets the InfluxDb user password.
     *
     * @param password
     *       The InfluxDb user password.
     * @return Instance of this to support fluent API.
     */
    public InfluxDbDestination setPassword(final String password) {
        this.password = password;
        return this;
    }

    /**
     * Gets a comma separated list of tags to be added to results.
     *
     * @return The comma separated list of tags to be added to results.
     */
    public String getTags() {
        return tags;
    }

    /**
     * Sets a comma separated list of tags to be added to results.
     *
     * @param tags
     *       The comma separated list of tags to be added to results.
     * @return Instance of this to support fluent API.
     */
    public InfluxDbDestination setTags(final String tags) {
        this.tags = tags;
        return this;
    }

    /**
     * Gets the SSL key store location.
     *
     * @return The SSL key store location.
     */
    public String getKeyStore() {
        return keyStore;
    }

    /**
     * Sets the SSL key store location.
     *
     * @param keyStore
     *       The SSL key store location.
     * @return Instance of this to support fluent API.
     */
    public InfluxDbDestination setKeyStore(final String keyStore) {
        this.keyStore = keyStore;
        return this;
    }

    /**
     * Gets the SSL key store password.
     *
     * @return The SSL key store password.
     */
    public String getKeyStorePassword() {
        return keyStorePassword;
    }

    /**
     * Sets the SSL key store password.
     *
     * @param keyStorePassword
     *       The SSL key store password.
     * @return Instance of this to support fluent API.
     */
    public InfluxDbDestination setKeyStorePassword(final String keyStorePassword) {
        this.keyStorePassword = keyStorePassword;
        return this;
    }

    /**
     * Gets the SSL trust store location.
     *
     * @return The SSL trust store location.
     */
    public String getTrustStore() {
        return trustStore;
    }

    /**
     * Sets the SSL trust store location.
     *
     * @param trustStore
     *       The SSL trust store location.
     * @return Instance of this to support fluent API.
     */
    public InfluxDbDestination setTrustStore(final String trustStore) {
        this.trustStore = trustStore;
        return this;
    }

    /**
     * Gets the SSL trust store password.
     *
     * @return The SSL trust store password.
     */
    public String getTrustStorePassword() {
        return trustStorePassword;
    }

    /**
     * Sets the SSL trust store password.
     *
     * @param trustStorePassword
     *       The SSL trust store password.
     * @return Instance of this to support fluent API.
     */
    public InfluxDbDestination setTrustStorePassword(final String trustStorePassword) {
        this.trustStorePassword = trustStorePassword;
        return this;
    }
}