All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.amazon.awssdk.metrics.internal.cloudwatch.MachineMetricFactory Maven / Gradle / Ivy

/*
 * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.metrics.internal.cloudwatch;

import static software.amazon.awssdk.metrics.internal.cloudwatch.MachineMetric.DaemonThreadCount;
import static software.amazon.awssdk.metrics.internal.cloudwatch.MachineMetric.DeadLockThreadCount;
import static software.amazon.awssdk.metrics.internal.cloudwatch.MachineMetric.FreeMemory;
import static software.amazon.awssdk.metrics.internal.cloudwatch.MachineMetric.OpenFileDescriptorCount;
import static software.amazon.awssdk.metrics.internal.cloudwatch.MachineMetric.PeakThreadCount;
import static software.amazon.awssdk.metrics.internal.cloudwatch.MachineMetric.SpareFileDescriptorCount;
import static software.amazon.awssdk.metrics.internal.cloudwatch.MachineMetric.SpareMemory;
import static software.amazon.awssdk.metrics.internal.cloudwatch.MachineMetric.ThreadCount;
import static software.amazon.awssdk.metrics.internal.cloudwatch.MachineMetric.TotalMemory;
import static software.amazon.awssdk.metrics.internal.cloudwatch.MachineMetric.TotalStartedThreadCount;
import static software.amazon.awssdk.metrics.internal.cloudwatch.MachineMetric.UsedMemory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.jmx.spi.JmxInfoProvider;
import software.amazon.awssdk.metrics.AwsSdkMetrics;
import software.amazon.awssdk.metrics.spi.MetricType;
import software.amazon.awssdk.services.cloudwatch.model.Dimension;
import software.amazon.awssdk.services.cloudwatch.model.MetricDatum;
import software.amazon.awssdk.services.cloudwatch.model.StandardUnit;

class MachineMetricFactory {
    private static final List MEMORY_METRICS = Arrays.asList(
            TotalMemory, FreeMemory, UsedMemory, SpareMemory);
    private static final List THREAD_METRICS = Arrays.asList(
            ThreadCount, DeadLockThreadCount, DaemonThreadCount,
            PeakThreadCount, TotalStartedThreadCount);
    private static final List FD_METRICS = Arrays.asList(
            OpenFileDescriptorCount, SpareFileDescriptorCount);
    private final JmxInfoProvider jmxInfoProvider = JmxInfoProvider.Factory.getJmxInfoProvider();

    /**
     * Add the given list of metrics and corresponding values specified in
     * "metricValues" to the given list of metric datum.
     *
     * @param list
     *            list of metric data
     * @param metricValues
     *            list of metrics and their corresponding values
     */
    private void addMetrics(List list,
                            MetricValues metricValues,
                            StandardUnit unit) {
        List machineMetrics = metricValues.getMetrics();
        List values = metricValues.getValues();
        for (int i = 0; i < machineMetrics.size(); i++) {
            MachineMetric metric = machineMetrics.get(i);
            long val = values.get(i).longValue();
            // skip zero values in some cases
            if (val != 0 || metric.includeZeroValue()) {
                MetricDatum datum = MetricDatum.builder()
                        .metricName(metric.getMetricName())
                        .dimensions(
                                Dimension.builder()
                                        .name(metric.getDimensionName())
                                        .value(metric.name())
                                        .build())
                        .unit(unit)
                        .value((double) val)
                        .build();
                list.add(datum);
            }
        }
    }

    /**
     * Returns the set of custom machine metrics specified in the SDK metrics
     * registry; or an empty set if there is none. Note any machine metrics
     * found in the registry must have been custom specified, as the default
     * behavior is to include all machine metrics when enabled.
     *
     * @return a non-null set of machine metrics. An empty set means no custom
     *         machine metrics have been specified.
     */
    private Set customMachineMetrics() {
        Set customized = new HashSet();
        for (MetricType m : AwsSdkMetrics.getPredefinedMetrics()) {
            if (m instanceof MachineMetric) {
                customized.add((MachineMetric) m);
            }
        }
        return customized;
    }

    /**
     * Returns a subset of the given list of metrics in "defaults" and the
     * corresponding value of each returned metric in the subset. Note if the
     * custom set is empty, the full set of default machine metrics and values
     * will be returned. (In particular, as in set theory, a set is a subset of
     * itself.)
     *
     * @param customSet
     *            custom machine metrics specified in the SDK metrics registry
     * @param defaults
     *            the given default list of metrics
     * @param values
     *            corresponding values of each metric in "defaults"
     */
    private MetricValues metricValues(Set customSet,
                                      List defaults, List values) {
        List actualMetrics = defaults;
        List actualValues = values;
        if (customSet.size() > 0) {
            // custom set of machine metrics specified
            actualMetrics = new ArrayList();
            actualValues = new ArrayList();
            for (int i = 0; i < defaults.size(); i++) {
                MachineMetric mm = defaults.get(i);
                if (customSet.contains(mm)) {
                    actualMetrics.add(mm);
                    actualValues.add(values.get(i));
                }
            }
        }
        return new MetricValues(actualMetrics, actualValues);
    }

    List generateMetrics() {
        if (AwsSdkMetrics.isMachineMetricExcluded()) {
            return Collections.emptyList();
        }
        Set customSet = customMachineMetrics();
        List targetList = new ArrayList(
                MachineMetric.values().length);
        // Memory usage
        addMemoryMetrics(targetList, customSet);
        // Thread related counts
        try {
            addThreadMetrics(targetList, customSet);
        } catch (Throwable t) {
            LoggerFactory.getLogger(getClass()).debug("Ignoring thread metrics", t);
        }
        // File descriptor usage
        try {
            addFileDescriptorMetrics(targetList, customSet);
        } catch (Throwable t) {
            LoggerFactory.getLogger(getClass()).debug("Ignoring file descriptor metrics", t);
        }
        return targetList;
    }

    private void addMemoryMetrics(List targetList,
                                  Set customSet) {
        Runtime rt = Runtime.getRuntime();
        long totalMem = rt.totalMemory();
        long freeMem = rt.freeMemory();
        long usedMem = totalMem - freeMem;
        long spareMem = rt.maxMemory() - usedMem;
        List values = Arrays.asList(totalMem, freeMem, usedMem, spareMem);
        MetricValues metricValues = memoryMetricValues(customSet, values);
        addMetrics(targetList, metricValues, StandardUnit.Bytes);
    }

    private void addFileDescriptorMetrics(List targetList,
                                          Set customSet) {
        JmxInfoProvider provider = JmxInfoProvider.Factory.getJmxInfoProvider();
        long[] fdInfo = provider.getFileDecriptorInfo();

        if (fdInfo != null) {
            long openFdCount = fdInfo[0];
            long maxFdCount = fdInfo[1];
            List values = Arrays.asList(openFdCount, maxFdCount - openFdCount);
            MetricValues metricValues = fdMetricValues(customSet, values);
            addMetrics(targetList, metricValues, StandardUnit.Count);
        }
    }

    private void addThreadMetrics(List targetList,
                                  Set customSet) {
        long threadCount = jmxInfoProvider.getThreadCount();
        long[] ids = jmxInfoProvider.findDeadlockedThreads();
        long deadLockThreadCount = ids == null ? 0 : ids.length;
        long daemonThreadCount = jmxInfoProvider.getDaemonThreadCount();
        long peakThreadCount = jmxInfoProvider.getPeakThreadCount();
        long totalStartedThreadCount = jmxInfoProvider.getTotalStartedThreadCount();
        List values = Arrays.asList(threadCount,
                                          deadLockThreadCount,
                                          daemonThreadCount,
                                          peakThreadCount,
                                          totalStartedThreadCount);
        MetricValues metricValues = threadMetricValues(customSet, values);
        addMetrics(targetList, metricValues, StandardUnit.Count);
    }

    /**
     * Returns the set of memory metrics and the corresponding values based on
     * the default and the customized set of metrics, if any.
     *
     * @param customSet
     *            a non-null customized set of metrics
     * @param values
     *            a non-null list of values corresponding to the list of default
     *            memory metrics
     */
    private MetricValues memoryMetricValues(Set customSet,
                                            List values) {
        return metricValues(customSet, MachineMetricFactory.MEMORY_METRICS,
                            values);
    }

    /**
     * Returns the set of file-descriptor metrics and the corresponding values based on
     * the default and the customized set of metrics, if any.
     *
     * @param customSet
     *            a non-null customized set of metrics
     * @param values
     *            a non-null list of values corresponding to the list of default
     *            file-descriptor metrics
     */
    private MetricValues fdMetricValues(Set customSet,
                                        List values) {
        return metricValues(customSet, MachineMetricFactory.FD_METRICS, values);
    }

    /**
     * Returns the set of thread metrics and the corresponding values based on
     * the default and the customized set of metrics, if any.
     *
     * @param customSet
     *            a non-null customized set of metrics
     * @param values
     *            a non-null list of values corresponding to the list of default
     *            thread metrics
     */
    private MetricValues threadMetricValues(Set customSet,
                                            List values) {
        return metricValues(customSet, MachineMetricFactory.THREAD_METRICS,
                            values);
    }

    // Used to get around the limitation of Java returning at most a single value
    private static class MetricValues {
        private final List metrics;
        private final List values;

        MetricValues(List metrics, List values) {
            this.metrics = metrics;
            this.values = values;
        }

        List getMetrics() {
            return metrics;
        }

        List getValues() {
            return values;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy