eu.tango.energymodeller.datasourceclient.WattsUpMeterDataSourceAdaptor.java Source code

Java tutorial

Introduction

Here is the source code for eu.tango.energymodeller.datasourceclient.WattsUpMeterDataSourceAdaptor.java

Source

/**
 * Copyright 2014 University of Leeds
 *
 * 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 eu.tango.energymodeller.datasourceclient;

import eu.ascetic.ioutils.io.Settings;
import static eu.tango.energymodeller.datasourceclient.KpiList.POWER_KPI_NAME;
import eu.tango.energymodeller.types.energyuser.ApplicationOnHost;
import eu.tango.energymodeller.types.energyuser.ApplicationOnHost.JOB_STATUS;
import eu.tango.energymodeller.types.energyuser.EnergyUsageSource;
import eu.tango.energymodeller.types.energyuser.GeneralPurposePowerConsumer;
import eu.tango.energymodeller.types.energyuser.Host;
import eu.tango.energymodeller.types.energyuser.VmDeployed;
import eu.tango.energymodeller.types.usage.CurrentUsageRecord;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.input.Tailer;
import org.apache.commons.io.input.TailerListenerAdapter;
import org.hyperic.sigar.CpuPerc;
import org.hyperic.sigar.Mem;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.SigarProxy;
import org.hyperic.sigar.SigarProxyCache;
import wattsup.jsdk.core.data.WattsUpConfig;
import wattsup.jsdk.core.data.WattsUpPacket;
import wattsup.jsdk.core.event.WattsUpDataAvailableEvent;
import wattsup.jsdk.core.event.WattsUpDisconnectEvent;
import wattsup.jsdk.core.event.WattsUpMemoryCleanEvent;
import wattsup.jsdk.core.event.WattsUpStopLoggingEvent;
import wattsup.jsdk.core.listener.WattsUpDataAvailableListener;
import wattsup.jsdk.core.listener.WattsUpDisconnectListener;
import wattsup.jsdk.core.listener.WattsUpMemoryCleanListener;
import wattsup.jsdk.core.listener.WattsUpStopLoggingListener;
import wattsup.jsdk.core.meter.WattsUp;

/**
 * The aim of this class is initially to take data from the Watts Up meter and
 * to place it into a format that is suitable for the Energy modeller.
 *
 * @author Richard Kavanagh
 */
public class WattsUpMeterDataSourceAdaptor implements HostDataSource {

    private static final String VOLTAGE_KPI_NAME = "Voltage";
    private static final String CURRENT_KPI_NAME = "Current";
    private final Host host;
    private WattsUp meter;
    private WattsUpTailer fileTailer;
    private Tailer tailer;
    private static SigarProxy sigar = getSigar();
    private int sigarFailCounter = 0;
    private HostMeasurement lowest = null;
    private HostMeasurement highest = null;
    private HostMeasurement current = null;
    private final LinkedList<CPUUtilisation> cpuMeasure = new LinkedList<>();
    private final Settings settings = new Settings("energy-modeller-watts-up-meter.properties");

    /**
     * SingletonHolder is loaded on the first execution of
     * Singleton.getInstance() or the first access to SingletonHolder.INSTANCE,
     * not before.
     */
    private static class SingletonHolder {

        private static final WattsUpMeterDataSourceAdaptor INSTANCE = new WattsUpMeterDataSourceAdaptor();
    }

    /**
     * This creates a new instance of the WattsUp Meter data source adaptor.
     * This adaptor is intended for using the energy modeller on a local
     * machine.
     *
     * @return A singleton instance of a WattsUp? meter data source adaptor.
     */
    public static WattsUpMeterDataSourceAdaptor getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     * This creates a new WattsUp Meter data source adaptor, that is capable of
     * taking data from a WattsUp Meter, for use inside the ASCETiC
     * architecture.
     *
     */
    private WattsUpMeterDataSourceAdaptor() {
        String port = settings.getString("energy.modeller.wattsup.port", "COM9");
        int hostId = settings.getInt("energy.modeller.wattsup.hostId", 1);
        String hostname = settings.getString("energy.modeller.wattsup.hostname", "localhost");
        if (settings.isChanged()) {
            settings.save("energy-modeller-watts-up-meter.properties");
        }
        host = new Host(hostId, hostname);
        startup(port, -1, 1);
        try {
            Mem mem = sigar.getMem();
            host.setRamMb((int) (Double.valueOf(mem.getTotal()) / 1048576));
        } catch (SigarException ex) {
            Logger.getLogger(WattsUpMeterDataSourceAdaptor.class.getName()).log(Level.SEVERE,
                    "A problem occured with Sigar", ex);
        }

    }

    /**
     * This creates a new Sigar instance.
     */
    private static SigarProxy getSigar() {
        return SigarProxyCache.newInstance(new Sigar(), 8);
    }

    /**
     * This creates a new WattsUp Meter data source adaptor, that is capable of
     * taking data from a WattsUp Meter, for use inside the ASCETiC
     * architecture.
     *
     * @param port The port to connect to
     * @param duration The duration to connect for (< 0 means forever) 
     * @param interval The interval at which to take logging data.
     */
    public WattsUpMeterDataSourceAdaptor(String port, int duration, int interval) {
        host = new Host(1, "localhost");
        startup(port, duration, interval);
    }

    /**
     * This is the generic startup code for the WattsUp data source adaptor
     *
     * @param port The port to connect to
     * @param duration The duration to connect for (< 0 means forever) 
     * @param interval The interval at which to take logging data.
     */
    public final void startup(String port, int duration, int interval) {
        if (port.equalsIgnoreCase("file")) {
            String filename = settings.getString("energy.modeller.wattsup.scrape.file", "testnodex-wattsup.log");
            if (settings.isChanged()) {
                settings.save("energy-modeller-watts-up-meter.properties");
            }
            File scrapeFile = new File(filename);
            fileTailer = new WattsUpTailer();
            tailer = Tailer.create(scrapeFile, fileTailer, (interval * 1000) / 16, true);
            Thread tailerThread = new Thread(tailer);
            tailerThread.setDaemon(true);
            tailerThread.start();
            System.out.println("Scraping from WattsUp meter file");
        } else {
            try {
                WattsUpConfig config = new WattsUpConfig().withPort(port).scheduleDuration(duration)
                        .withInternalLoggingInterval(interval).withExternalLoggingInterval(interval);
                meter = new WattsUp(config);
                System.out.println("WattsUp Meter Created");
                registerEventListeners(meter);
                System.out.println("WattsUp Meter Connecting");
                meter.connect(false);
                meter.setLoggingModeSerial(1);
                System.out.println("WattsUp Meter Connected " + meter.isConnected());
            } catch (IOException ex) {
                Logger.getLogger(WattsUpMeterDataSourceAdaptor.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * This registers the required meters for the energy modeller.
     *
     * @param meter The meter to register the event listeners for
     */
    private void registerEventListeners(WattsUp meter) {
        meter.registerListener(new WattsUpDataAvailableListener() {
            @Override
            public void processDataAvailable(final WattsUpDataAvailableEvent event) {
                GregorianCalendar calander = new GregorianCalendar();
                long clock = TimeUnit.MILLISECONDS.toSeconds(calander.getTimeInMillis());
                HostMeasurement measurement = new HostMeasurement(host, clock);
                WattsUpPacket[] values = event.getValue();
                String watts = values[0].get("watts").getValue();
                String volts = values[0].get("volts").getValue();
                String amps = values[0].get("amps").getValue();
                String wattskwh = values[0].get("wattskwh").getValue();
                watts = "" + changeOrderOfMagnitude(watts, 1);
                volts = "" + changeOrderOfMagnitude(volts, 1);
                amps = "" + changeOrderOfMagnitude(amps, 3);
                measurement
                        .addMetric(new MetricValue(KpiList.POWER_KPI_NAME, KpiList.POWER_KPI_NAME, watts, clock));
                measurement.addMetric(
                        new MetricValue(KpiList.ENERGY_KPI_NAME, KpiList.ENERGY_KPI_NAME, wattskwh, clock));
                measurement.addMetric(new MetricValue(VOLTAGE_KPI_NAME, VOLTAGE_KPI_NAME, volts, clock));
                measurement.addMetric(new MetricValue(CURRENT_KPI_NAME, CURRENT_KPI_NAME, amps, clock));
                try {
                    CpuPerc cpu = sigar.getCpuPerc();
                    cpuMeasure.add(new CPUUtilisation(clock, cpu));
                    Mem mem = sigar.getMem();
                    measurement.addMetric(new MetricValue(KpiList.CPU_IDLE_KPI_NAME, KpiList.CPU_IDLE_KPI_NAME,
                            cpu.getIdle() * 100 + "", clock));
                    measurement.addMetric(new MetricValue(KpiList.CPU_INTERUPT_KPI_NAME,
                            KpiList.CPU_INTERUPT_KPI_NAME, cpu.getIrq() * 100 + "", clock));
                    measurement.addMetric(new MetricValue(KpiList.CPU_IO_WAIT_KPI_NAME,
                            KpiList.CPU_IO_WAIT_KPI_NAME, cpu.getWait() * 100 + "", clock));
                    measurement.addMetric(new MetricValue(KpiList.CPU_NICE_KPI_NAME, KpiList.CPU_NICE_KPI_NAME,
                            cpu.getNice() * 100 + "", clock));
                    measurement.addMetric(new MetricValue(KpiList.CPU_SOFT_IRQ_KPI_NAME,
                            KpiList.CPU_SOFT_IRQ_KPI_NAME, cpu.getIrq() * 100 + "", clock));
                    measurement.addMetric(new MetricValue(KpiList.CPU_STEAL_KPI_NAME, KpiList.CPU_STEAL_KPI_NAME,
                            cpu.getStolen() * 100 + "", clock));
                    measurement.addMetric(new MetricValue(KpiList.CPU_SYSTEM_KPI_NAME, KpiList.CPU_SYSTEM_KPI_NAME,
                            cpu.getSys() * 100 + "", clock));
                    measurement.addMetric(new MetricValue(KpiList.CPU_USER_KPI_NAME, KpiList.CPU_USER_KPI_NAME,
                            cpu.getUser() * 100 + "", clock));

                    measurement.addMetric(
                            new MetricValue(KpiList.MEMORY_AVAILABLE_KPI_NAME, KpiList.MEMORY_AVAILABLE_KPI_NAME,
                                    (int) (Double.valueOf(mem.getActualFree()) / 1048576) + "", clock));
                    measurement
                            .addMetric(new MetricValue(KpiList.MEMORY_TOTAL_KPI_NAME, KpiList.MEMORY_TOTAL_KPI_NAME,
                                    (int) (Double.valueOf(mem.getTotal()) / 1048576) + "", clock));

                } catch (SigarException ex) {
                    Logger.getLogger(WattsUpMeterDataSourceAdaptor.class.getName()).log(Level.SEVERE, null, ex);
                }
                current = measurement;
                if (lowest == null || measurement.getPower() < lowest.getPower()) {
                    lowest = measurement;
                }
                if (highest == null || measurement.getPower() > highest.getPower()) {
                    highest = measurement;
                }
            }
        });

        meter.registerListener(new WattsUpMemoryCleanListener() {
            @Override
            public void processWattsUpReset(WattsUpMemoryCleanEvent event) {
                System.out.println("WattsUp Meter Memory Just Cleaned");
            }
        });

        meter.registerListener(new WattsUpStopLoggingListener() {
            @Override
            public void processStopLogging(WattsUpStopLoggingEvent event) {
                System.out.println("WattsUp Meter Logging Stopped");
            }
        });

        meter.registerListener(new WattsUpDisconnectListener() {
            @Override
            public void onDisconnect(WattsUpDisconnectEvent event) {
                System.out.println("WattsUp Meter Client Exiting");
            }
        });
    }

    /**
     * The output of a WattsUp? meter has no decimal places. This shifts the
     * output by the correct magnitude in order that the value makes sense.
     *
     * @param meterOutput The output from the WattsUp? meter.
     * @param position The order of magnitude to reduce the size of the value
     * by.
     * @return The double value of the meters output string.
     */
    private static double changeOrderOfMagnitude(String meterOutput, int position) {
        double answer = Double.valueOf(meterOutput);
        if (position > 0) {
            answer = answer / Math.pow(10, position);
        }
        return answer;
    }

    @Override
    public Host getHostByName(String hostname) {
        //ignore hostname and just return the current localhost
        if (hostname.equals(host.getHostName())) {
            return host;
        } else {
            return new Host(1, hostname);
        }
    }

    @Override
    public GeneralPurposePowerConsumer getGeneralPowerConsumerByName(String hostname) {
        return null;
    }

    @Override
    public VmDeployed getVmByName(String name) {
        return null;
    }

    @Override
    public List<Host> getHostList() {
        List<Host> answer = new ArrayList<>();
        answer.add(host);
        return answer;
    }

    @Override
    public List<GeneralPurposePowerConsumer> getGeneralPowerConsumerList() {
        return new ArrayList<>();
    }

    @Override
    public List<VmDeployed> getVmList() {
        return new ArrayList<>();
    }

    @Override
    public List<EnergyUsageSource> getHostAndVmList() {
        List<EnergyUsageSource> answer = new ArrayList<>();
        answer.add(host);
        return answer;
    }

    @Override
    public List<ApplicationOnHost> getHostApplicationList(JOB_STATUS state) {
        return new ArrayList<>();
    }

    @Override
    public List<ApplicationOnHost> getHostApplicationList() {
        return new ArrayList<>();
    }

    @Override
    public HostMeasurement getHostData(Host host) {
        while (current == null) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException ex) {
                Logger.getLogger(WattsUpMeterDataSourceAdaptor.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return current;
    }

    @Override
    public List<HostMeasurement> getHostData() {
        List<HostMeasurement> answer = new ArrayList<>();
        answer.add(getHostData(host));
        return answer;
    }

    @Override
    public List<HostMeasurement> getHostData(List<Host> hostList) {
        List<HostMeasurement> answer = new ArrayList<>();
        if (hostList.contains(host)) {
            answer.add(getHostData(host));
        }
        return answer;
    }

    @Override
    public VmMeasurement getVmData(VmDeployed vm) {
        return null;
    }

    @Override
    public List<VmMeasurement> getVmData() {
        return new ArrayList<>();
    }

    @Override
    public List<VmMeasurement> getVmData(List<VmDeployed> vmList) {
        return new ArrayList<>();
    }

    @Override
    public CurrentUsageRecord getCurrentEnergyUsage(Host host) {
        CurrentUsageRecord answer = new CurrentUsageRecord(host);
        HostMeasurement measurement = getHostData(host);
        answer.setPower(measurement.getMetric(POWER_KPI_NAME).getValue());
        answer.setVoltage(current.getMetric(VOLTAGE_KPI_NAME).getValue());
        answer.setCurrent(current.getMetric(CURRENT_KPI_NAME).getValue());
        return answer;
    }

    @Override
    public double getLowestHostPowerUsage(Host host) {
        return lowest.getPower();
    }

    @Override
    public double getHighestHostPowerUsage(Host host) {
        return highest.getPower();
    }

    @Override
    public synchronized double getCpuUtilisation(Host host, int lastNSeconds) {
        double count = 0.0;
        double sumOfUtil = 0.0;
        GregorianCalendar cal = new GregorianCalendar();
        long now = TimeUnit.MILLISECONDS.toSeconds(cal.getTimeInMillis());
        long nowMinustime = now - lastNSeconds;
        CopyOnWriteArrayList<CPUUtilisation> list = new CopyOnWriteArrayList<>();
        list.addAll(cpuMeasure);
        for (Iterator<CPUUtilisation> it = list.iterator(); it.hasNext();) {
            CPUUtilisation util = it.next();
            if (util.isOlderThan(nowMinustime)) {
                list.remove(util);
                cpuMeasure.remove(util);
            } else {
                sumOfUtil = sumOfUtil + util.getCpuBusy();
                count = count + 1;
            }
        }
        if (count == 0) {
            return 0.0;
        }
        return sumOfUtil / count;
    }

    /**
     * This is a CPU utilisation record for the WattsUp Meter data source
     * adaptor.
     */
    private class CPUUtilisation {

        private final long clock;
        private final CpuPerc cpu;

        /**
         * This creates a new CPU Utilisation record
         *
         * @param clock the time when the CPU Utilisation was taken
         * @param cpu The CPU utilisation record.
         */
        public CPUUtilisation(long clock, CpuPerc cpu) {
            this.clock = clock;
            this.cpu = cpu;
        }

        /**
         * The time when this record was taken
         *
         * @return The UTC time for this record.
         */
        public long getClock() {
            return clock;
        }

        /**
         * This returns the Sigar object representing CPU load information.
         *
         * @return The sigar CPU object
         */
        public CpuPerc getCpu() {
            return cpu;
        }

        /**
         * This returns the percentage of time the CPU was idle.
         *
         * @return 0..1 for how idle the CPU was at a specified time frame.
         */
        public double getCpuIdle() {
            return cpu.getIdle();
        }

        /**
         * This returns the percentage of time the CPU was busy.
         *
         * @return 0..1 for how busy the CPU was at a specified time frame.
         */
        public double getCpuBusy() {
            return 1 - cpu.getIdle();
        }

        /**
         * This indicates if this CPU utilisation object is older than a
         * specified time.
         *
         * @param time The UTC time to compare to
         * @return If the current item is older than the date specified.
         */
        public boolean isOlderThan(long time) {
            return clock < time;
        }

    }

    /**
     * In the event the WattsUp Meter port is captured already and the output is
     * being placed in a log file this can read the file and get the required
     * data.
     */
    private class WattsUpTailer extends TailerListenerAdapter {

        @Override
        public void handle(String line) {
            try {
                //This avoids looking at the header of the file
                if (line.startsWith("W")) {
                    return;
                }
                boolean valid = true;
                GregorianCalendar calander = new GregorianCalendar();
                long clock = TimeUnit.MILLISECONDS.toSeconds(calander.getTimeInMillis());
                CpuPerc cpu = sigar.getCpuPerc();
                /**
                 * Test an arbritrary value to check to see if NaN has been
                 * produced. This occurs when Sigar's internal state has not
                 * been prepared sufficiently quickly. i.e. concurrency issues.
                 */
                if (Double.isNaN(cpu.getSys())) {
                    try {
                        //Delay for a short while and retry
                        Thread.sleep(500);
                        cpu = sigar.getCpuPerc();
                        if (Double.isNaN(cpu.getSys())) {
                            System.out.println("The measurement taken was invalid - Sigar getCPU");
                            restartSigar();
                            return;
                        }
                    } catch (InterruptedException ex) {
                        Logger.getLogger(WattsUpMeterDataSourceAdaptor.class.getName()).log(Level.INFO,
                                "The thread sleep was interupted", ex);
                    }
                }
                Mem mem = sigar.getMem();
                cpuMeasure.add(new CPUUtilisation(clock, cpu));
                String[] values = line.split(",");
                /**
                 * The Watts up meter column order is: W,V, A, WH, COST, WH/Mo,
                 * Cost/Mo, Wmax, Vmax, Amax, Wmin, Vmin, Amin, PF, DC, PC, Hz,
                 * VA
                 */
                String watts = values[0];
                String volts = values[1];
                String amps = values[2];
                String wattskwh = values[3];

                HostMeasurement measurement = new HostMeasurement(host, clock);
                measurement
                        .addMetric(new MetricValue(KpiList.POWER_KPI_NAME, KpiList.POWER_KPI_NAME, watts, clock));
                measurement.addMetric(
                        new MetricValue(KpiList.ENERGY_KPI_NAME, KpiList.ENERGY_KPI_NAME, wattskwh, clock));
                measurement.addMetric(new MetricValue(VOLTAGE_KPI_NAME, VOLTAGE_KPI_NAME, volts, clock));
                measurement.addMetric(new MetricValue(CURRENT_KPI_NAME, CURRENT_KPI_NAME, amps, clock));
                valid = valid && validatedAddMetric(measurement, new MetricValue(KpiList.CPU_IDLE_KPI_NAME,
                        KpiList.CPU_IDLE_KPI_NAME, cpu.getIdle() * 100 + "", clock));
                if (!valid) {
                    System.out.println("The measurement taken was invalid - Sigar");
                    /**
                     * This quickly exits if Sigar produces a Double.NaN value
                     * due to its internal state not been ready.
                     */
                    restartSigar();
                    return;
                }
                valid = valid && validatedAddMetric(measurement, new MetricValue(KpiList.CPU_INTERUPT_KPI_NAME,
                        KpiList.CPU_INTERUPT_KPI_NAME, cpu.getIrq() * 100 + "", clock));
                valid = valid && validatedAddMetric(measurement, new MetricValue(KpiList.CPU_IO_WAIT_KPI_NAME,
                        KpiList.CPU_IO_WAIT_KPI_NAME, cpu.getWait() * 100 + "", clock));
                valid = valid && validatedAddMetric(measurement, new MetricValue(KpiList.CPU_NICE_KPI_NAME,
                        KpiList.CPU_NICE_KPI_NAME, cpu.getNice() * 100 + "", clock));
                valid = valid && validatedAddMetric(measurement, new MetricValue(KpiList.CPU_SOFT_IRQ_KPI_NAME,
                        KpiList.CPU_SOFT_IRQ_KPI_NAME, cpu.getIrq() * 100 + "", clock));
                valid = valid && validatedAddMetric(measurement, new MetricValue(KpiList.CPU_STEAL_KPI_NAME,
                        KpiList.CPU_STEAL_KPI_NAME, cpu.getStolen() * 100 + "", clock));
                valid = valid && validatedAddMetric(measurement, new MetricValue(KpiList.CPU_SYSTEM_KPI_NAME,
                        KpiList.CPU_SYSTEM_KPI_NAME, cpu.getSys() * 100 + "", clock));
                valid = valid && validatedAddMetric(measurement, new MetricValue(KpiList.CPU_USER_KPI_NAME,
                        KpiList.CPU_USER_KPI_NAME, cpu.getUser() * 100 + "", clock));

                valid = valid && validatedAddMetric(measurement,
                        new MetricValue(KpiList.MEMORY_AVAILABLE_KPI_NAME, KpiList.MEMORY_AVAILABLE_KPI_NAME,
                                (int) (Double.valueOf(mem.getActualFree()) / 1048576) + "", clock));
                valid = valid && validatedAddMetric(measurement,
                        new MetricValue(KpiList.MEMORY_TOTAL_KPI_NAME, KpiList.MEMORY_TOTAL_KPI_NAME,
                                (int) (Double.valueOf(mem.getTotal()) / 1048576) + "", clock));
                if (!valid) {
                    restartSigar();
                    return;
                }
                current = measurement;
                if (lowest == null || measurement.getPower() < lowest.getPower()) {
                    lowest = measurement;
                }
                if (highest == null || measurement.getPower() > highest.getPower()) {
                    highest = measurement;
                }
            } catch (NumberFormatException ex) {
                //Ignore these errors and carry on. It may just be the header line.
                Logger.getLogger(WattsUpMeterDataSourceAdaptor.class.getName()).log(Level.INFO,
                        "The parsing of metric data failed", ex);
            } catch (SigarException ex) {
                Logger.getLogger(WattsUpMeterDataSourceAdaptor.class.getName()).log(Level.SEVERE,
                        "An exception occured when obtaining data from Sigar", ex);
            }
        }

        /**
         * This ensures that metric values are not added in cases where NaN etc
         * is given as an output from Sigar.
         *
         * @param measurement The measurement to add the value to
         * @param value The value to add.
         * @return The measurement with the added metric only in cases where the
         * values correct.
         */
        private boolean validatedAddMetric(Measurement measurement, MetricValue value) {
            if (Double.isNaN(value.getValue()) || Double.isInfinite(value.getValue())) {
                return false;
            }
            measurement.addMetric(value);
            return true;
        }
    }

    /**
     * This corrects Sigar in cases where its internal state becomes an issue.
     * The result of which is that this adaptor no longer reports out data, without
     * Sigar been restarted.
     */
    private void restartSigar() {
        sigarFailCounter = sigarFailCounter + 1;
        System.out.println("The measurement taken was invalid - Sigar getCPU");
        if (sigarFailCounter >= 2) {
            System.out.println("Sigar reset");
            sigar = getSigar();
            sigarFailCounter = 0;
        }
    }

}