org.ecloudmanager.monitoring.HaproxyStatsCollector.java Source code

Java tutorial

Introduction

Here is the source code for org.ecloudmanager.monitoring.HaproxyStatsCollector.java

Source

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Altisource Labs
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package org.ecloudmanager.monitoring;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.ecloudmanager.deployment.core.DeploymentObject;
import org.ecloudmanager.deployment.ps.HAProxyDeployer;
import org.ecloudmanager.deployment.ps.ProducedServiceDeployment;
import org.ecloudmanager.deployment.ps.cg.ComponentGroupDeployment;
import org.ecloudmanager.deployment.vm.VMDeployment;
import org.ecloudmanager.monitoring.rrd.RrdDbService;
import org.ecloudmanager.repository.deployment.ApplicationDeploymentRepository;
import org.ecloudmanager.repository.monitoring.HaproxyStatsRepository;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.rrd4j.core.RrdDb;
import org.rrd4j.core.Sample;

import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.inject.Inject;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.InvocationCallback;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

@Startup
@Singleton
public class HaproxyStatsCollector {
    @Inject
    ApplicationDeploymentRepository applicationDeploymentRepository;
    @Inject
    Logger log;
    @Inject
    HaproxyStatsRepository haproxyStatsRepository;
    @Inject
    RrdDbService rrdDbService;

    private Client client = new ResteasyClientBuilder().connectionPoolSize(100).connectionTTL(5, TimeUnit.MINUTES)
            .build();

    @Schedule(second = "*/10", minute = "*", hour = "*", persistent = false)
    private void collect() {
        applicationDeploymentRepository.getAll().stream().flatMap(
                applicationDeployment -> applicationDeployment.children(ProducedServiceDeployment.class).stream())
                .filter(producedServiceDeployment -> {
                    String monitored = producedServiceDeployment.getConfigValue(HAProxyDeployer.HAPROXY_MONITORING);
                    return "true".equals(monitored)
                            && !StringUtils.isEmpty(HAProxyDeployer.getHaproxyIp(producedServiceDeployment));
                }).map(HAProxyDeployer::getHaproxyIp).distinct().forEach(this::collectStats);
    }

    private void collectStats(String haproxyStatsAddr) {
        client.target("http://" + haproxyStatsAddr + ":22002" + "/;csv").request().async()
                .get(new InvocationCallback<Response>() {
                    @Override
                    public void completed(Response response) {
                        if (response.getStatus() == 200) {
                            String csv = response.readEntity(String.class);
                            csv = csv.replaceFirst("# ", "");
                            List<CSVRecord> records = null;
                            try {
                                records = CSVParser.parse(csv, CSVFormat.DEFAULT.withHeader()).getRecords();
                                collectRecords(haproxyStatsAddr, records);
                            } catch (IOException e) {
                                log.error(e);
                            }
                        } else {
                            log.error("Cannot connect to haproxy stats endpoint " + haproxyStatsAddr
                                    + " response code " + response.getStatus());
                        }
                    }

                    @Override
                    public void failed(Throwable throwable) {
                        log.trace("Can't get haproxy stats from " + haproxyStatsAddr, throwable);
                    }
                });
    }

    private void collectRecords(String haproxyStatsAddr, List<CSVRecord> records) {
        applicationDeploymentRepository.getAll().stream().flatMap(
                applicationDeployment -> applicationDeployment.children(ProducedServiceDeployment.class).stream())
                .filter(producedServiceDeployment -> {
                    String monitored = producedServiceDeployment.getConfigValue(HAProxyDeployer.HAPROXY_MONITORING);
                    String haproxyAddr = HAProxyDeployer.getHaproxyIp(producedServiceDeployment);
                    return haproxyStatsAddr.equals(haproxyAddr) && "true".equals(monitored);
                }).forEach(producedServiceDeployment -> {
                    updateRrdDbAndLatestStats(producedServiceDeployment, producedServiceDeployment.getName(),
                            "FRONTEND", records);
                    producedServiceDeployment.children(ComponentGroupDeployment.class)
                            .forEach(componentGroupDeployment -> {
                                updateRrdDbAndLatestStats(componentGroupDeployment,
                                        componentGroupDeployment.getName(), "BACKEND", records);
                            });
                    producedServiceDeployment.stream(VMDeployment.class).forEach(vmDeployment -> {
                        updateRrdDbAndLatestStats(vmDeployment, vmDeployment.getParent().getName(),
                                vmDeployment.getName(), records);
                    });
                });
    }

    private void updateRrdDbAndLatestStats(DeploymentObject deploymentObject, String pxname, String svname,
            List<CSVRecord> records) {
        records.stream()
                .filter(record -> record.get(HaproxyStatsField.PROXY_NAME.getKey()).equals(pxname)
                        && record.get(HaproxyStatsField.SERVICE_NAME.getKey()).startsWith(svname))
                .forEach(record -> {
                    // Update the latest stats
                    HaproxyStats haproxyStats = haproxyStatsRepository.getStats(deploymentObject.getId());
                    if (haproxyStats == null) {
                        haproxyStats = new HaproxyStats();
                        haproxyStats.setDeploymentObjectId(deploymentObject.getId());
                    } else {
                        haproxyStats.setTimestamp(new Date());
                    }
                    haproxyStats.setData(record.toMap());

                    haproxyStatsRepository.save(haproxyStats);

                    // Update rrd db
                    RrdDb rrdDb = rrdDbService.openRrdDb(deploymentObject);
                    try {
                        Sample sample = rrdDb.createSample();
                        Stream.of(sample.getDsNames()).forEach(dsName -> {
                            if (!StringUtils.isEmpty(record.get(dsName))) {
                                sample.setValue(dsName, Double.parseDouble(record.get(dsName)));
                            }
                        });
                        sample.update();
                        rrdDb.close(); // Close flushes data to mongodb, don't need to close when couldn't create sample
                    } catch (IOException e) {
                        log.error("Failed to store sample in rrd db", e);
                    }
                });
    }
}