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

cn.patterncat.metrics.system.OperatingSystemMetricSet Maven / Gradle / Ivy

The newest version!
package cn.patterncat.metrics.system;

import cn.patterncat.metrics.utils.MetricNamingUtil;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricSet;
import com.sun.management.UnixOperatingSystemMXBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

/**
 * monitor os metrics
 * Created by patterncat on 2017-03-05.
 */
public class OperatingSystemMetricSet implements MetricSet {

    private static final Logger logger = LoggerFactory.getLogger(OperatingSystemMetricSet.class);

    private OperatingSystemMXBean operatingSystemMXBean;

    private File rootFilePath;

    private ScheduledExecutorService executorService;
    private AtomicReference ioWaitPercentageHolder;

    private Gauge availableLogicalProcessorsGauge;
    private Gauge systemLoadAverageGauge;
    private Gauge systemLoadAveragePerLogicalProcessorGauge;

    private Gauge jvmCpuBusyPercentageGauge;
    private Gauge systemCpuBusyPercentageGauge;
    private Gauge committedVirtualMemorySizeInBytesGauge;
    private Gauge totalPhysicalMemorySizeInBytesGauge;
    private Gauge freePhysicalMemorySizeInBytesGauge;
    private Gauge usedPhysicalMemoryPercentageGauge;
    private Gauge totalSwapSpaceSizeInBytesGauge;
    private Gauge freeSwapSpaceSizeInBytesGauge;
    private Gauge usedSwapSpacePercentageGauge;

    private Gauge maxFileDescriptorsGauge;
    private Gauge openFileDescriptorsGauge;
    private Gauge usedFileDescriptorsPercentageGauge;

    private Gauge totalDiskSpaceInBytesGauge;
    private Gauge freeDiskSpaceInBytesGauge;
    private Gauge usedDiskSpacePercentageGauge;

    private Gauge ioWaitPercentageGauge;

    private Map metricsByNames;

    private AtomicBoolean shutdown;


    public OperatingSystemMetricSet() {
        this.operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
        this.rootFilePath = new File("/");

        // Set up iowait retrieval job if needed
//        Double ioWaitPercentage = fetchIoWaitPercentage();
//        if (ioWaitPercentage != null) {
//            this.ioWaitPercentageHolder = new AtomicReference<>(ioWaitPercentage);
//
//            this.executorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setNameFormat("OperatingSystemMetricSet-%d").build());
//            this.executorService.scheduleWithFixedDelay(new Runnable() {
//                @Override
//                public void run() {
//                    Double ioWaitPercentage = fetchIoWaitPercentage();
//                    if (ioWaitPercentage != null) {
//                        ioWaitPercentageHolder.set(ioWaitPercentage);
//                    }
//                }
//            }, 5, 10, TimeUnit.SECONDS);
//        }

        // ----- Init and assign metrics -----
        this.metricsByNames = new HashMap<>();

        // Available everywhere
        this.availableLogicalProcessorsGauge = new Gauge() {
            @Override
            public Integer getValue() {
                return operatingSystemMXBean.getAvailableProcessors();
            }
        };
        metricsByNames.put("availableLogicalProcessors", availableLogicalProcessorsGauge);

        if (operatingSystemMXBean.getSystemLoadAverage() >= 0) {    // Where available
            this.systemLoadAverageGauge = new Gauge() {
                @Override
                public Double getValue() {
                    return operatingSystemMXBean.getSystemLoadAverage();
                }
            };
            metricsByNames.put("systemLoadAverage", systemLoadAverageGauge);

            this.systemLoadAveragePerLogicalProcessorGauge = new Gauge() {
                @Override
                public Double getValue() {
                    return operatingSystemMXBean.getSystemLoadAverage() / operatingSystemMXBean.getAvailableProcessors();
                }
            };
            metricsByNames.put("systemLoadAveragePerLogicalProcessor", systemLoadAveragePerLogicalProcessorGauge);
        }

        // Sun JVMs, incl. OpenJDK
        if (com.sun.management.OperatingSystemMXBean.class.isAssignableFrom(operatingSystemMXBean.getClass())) {
            final com.sun.management.OperatingSystemMXBean sunOsMxBean = com.sun.management.OperatingSystemMXBean.class.cast(operatingSystemMXBean);

            if (sunOsMxBean.getProcessCpuLoad() >= 0) {
                this.jvmCpuBusyPercentageGauge = new Gauge() {
                    @Override
                    public Double getValue() {
                        return sunOsMxBean.getProcessCpuLoad() * 100;
                    }
                };
                metricsByNames.put("jvmCpuBusyPercentage", jvmCpuBusyPercentageGauge);
            }

            if (sunOsMxBean.getSystemCpuLoad() >= 0) {
                this.systemCpuBusyPercentageGauge = new Gauge() {
                    @Override
                    public Double getValue() {
                        return sunOsMxBean.getSystemCpuLoad() * 100;
                    }
                };
                metricsByNames.put("systemCpuBusyPercentage", systemCpuBusyPercentageGauge);
            }

            if (sunOsMxBean.getCommittedVirtualMemorySize() >= 0) {
                this.committedVirtualMemorySizeInBytesGauge = new Gauge() {
                    @Override
                    public Long getValue() {
                        return sunOsMxBean.getCommittedVirtualMemorySize();
                    }
                };
                metricsByNames.put("committedVirtualMemorySizeInBytes", committedVirtualMemorySizeInBytesGauge);
            }

            // Physical Memory
            String physicalMemoryNamespace = "physicalMemory";

            this.totalPhysicalMemorySizeInBytesGauge = new Gauge() {
                @Override
                public Long getValue() {
                    return sunOsMxBean.getTotalPhysicalMemorySize();
                }
            };
            metricsByNames.put(MetricNamingUtil.join(physicalMemoryNamespace, "totalInBytes"), totalPhysicalMemorySizeInBytesGauge);

            this.freePhysicalMemorySizeInBytesGauge = new Gauge() {
                @Override
                public Long getValue() {
                    return sunOsMxBean.getFreePhysicalMemorySize();
                }
            };
            metricsByNames.put(MetricNamingUtil.join(physicalMemoryNamespace, "freeInBytes"), freePhysicalMemorySizeInBytesGauge);

            this.usedPhysicalMemoryPercentageGauge = new Gauge() {
                @Override
                public Double getValue() {
                    long totalPhysicalMemorySize = sunOsMxBean.getTotalPhysicalMemorySize();
                    if (totalPhysicalMemorySize == 0) {
                        return 0.0;
                    }

                    long usedPhysicalMemorySize = totalPhysicalMemorySize - sunOsMxBean.getFreePhysicalMemorySize();
                    return Double.valueOf(usedPhysicalMemorySize) / totalPhysicalMemorySize * 100;
                }
            };
            metricsByNames.put(MetricNamingUtil.join(physicalMemoryNamespace, "usedPercentage"), usedPhysicalMemoryPercentageGauge);

            // Swap Space
            String swapSpaceNamespace = "swapSpace";

            this.totalSwapSpaceSizeInBytesGauge = new Gauge() {
                @Override
                public Long getValue() {
                    return sunOsMxBean.getTotalSwapSpaceSize();
                }
            };
            metricsByNames.put(MetricNamingUtil.join(swapSpaceNamespace, "totalInBytes"), totalSwapSpaceSizeInBytesGauge);

            this.freeSwapSpaceSizeInBytesGauge = new Gauge() {
                @Override
                public Long getValue() {
                    return sunOsMxBean.getFreeSwapSpaceSize();
                }
            };
            metricsByNames.put(MetricNamingUtil.join(swapSpaceNamespace, "freeInBytes"), freeSwapSpaceSizeInBytesGauge);

            this.usedSwapSpacePercentageGauge = new Gauge() {
                @Override
                public Double getValue() {
                    long totalSwapSpaceSize = sunOsMxBean.getTotalSwapSpaceSize();
                    if (totalSwapSpaceSize == 0) {
                        return 0.0;
                    }

                    long usedSwapSpaceSize = totalSwapSpaceSize - sunOsMxBean.getFreeSwapSpaceSize();
                    return Double.valueOf(usedSwapSpaceSize) / totalSwapSpaceSize * 100;
                }
            };
            metricsByNames.put(MetricNamingUtil.join(swapSpaceNamespace, "usedPercentage"), usedSwapSpacePercentageGauge);
        }

        // File descriptors (e.g., sockets)
        String fileDescriptorsNamespace = "fileDescriptors";

        if (UnixOperatingSystemMXBean.class.isAssignableFrom(operatingSystemMXBean.getClass())) {
            final UnixOperatingSystemMXBean unixOsMxBean = UnixOperatingSystemMXBean.class.cast(operatingSystemMXBean);

            this.maxFileDescriptorsGauge = new Gauge() {
                @Override
                public Long getValue() {
                    return unixOsMxBean.getMaxFileDescriptorCount();
                }
            };
            metricsByNames.put(MetricNamingUtil.join(fileDescriptorsNamespace, "max"), maxFileDescriptorsGauge);

            this.openFileDescriptorsGauge = new Gauge() {
                @Override
                public Long getValue() {
                    return unixOsMxBean.getOpenFileDescriptorCount();
                }
            };
            metricsByNames.put(MetricNamingUtil.join(fileDescriptorsNamespace, "open"), openFileDescriptorsGauge);

            this.usedFileDescriptorsPercentageGauge = new Gauge() {
                @Override
                public Double getValue() {
                    long maxFileDescriptors = unixOsMxBean.getMaxFileDescriptorCount();
                    if (maxFileDescriptors == 0) {
                        return 0.0;
                    }
                    return Double.valueOf(unixOsMxBean.getOpenFileDescriptorCount()) / maxFileDescriptors * 100;
                }
            };
            metricsByNames.put(MetricNamingUtil.join(fileDescriptorsNamespace, "usedPercentage"), usedFileDescriptorsPercentageGauge);
        }

        // Disk space
        String diskSpaceNamespace = "diskSpace";

        if (rootFilePath.getTotalSpace() > 0) {
            this.totalDiskSpaceInBytesGauge = new Gauge() {
                @Override
                public Long getValue() {
                    return rootFilePath.getTotalSpace();
                }
            };
            metricsByNames.put(MetricNamingUtil.join(diskSpaceNamespace, "totalInBytes"), totalDiskSpaceInBytesGauge);

            this.freeDiskSpaceInBytesGauge = new Gauge() {
                @Override
                public Long getValue() {
                    return rootFilePath.getFreeSpace();
                }
            };
            metricsByNames.put(MetricNamingUtil.join(diskSpaceNamespace, "freeInBytes"), freeDiskSpaceInBytesGauge);

            this.usedDiskSpacePercentageGauge = new Gauge() {
                @Override
                public Double getValue() {
                    long totalDiskSpace = rootFilePath.getTotalSpace();
                    if (totalDiskSpace == 0) {
                        return 0.0;
                    }

                    long usedDiskSpace = totalDiskSpace - rootFilePath.getFreeSpace();
                    return Double.valueOf(usedDiskSpace) / totalDiskSpace * 100;
                }
            };
            metricsByNames.put(MetricNamingUtil.join(diskSpaceNamespace, "usedPercentage"), usedDiskSpacePercentageGauge);
        }

        // CPU IO Wait
        if (ioWaitPercentageHolder != null) {
            this.ioWaitPercentageGauge = new Gauge() {
                @Override
                public Double getValue() {
                    return ioWaitPercentageHolder.get();
                }
            };
            metricsByNames.put("ioWaitPercentage", ioWaitPercentageGauge);
        }

        this.shutdown = new AtomicBoolean(false);
    }


    @Override
    public Map getMetrics() {
        return Collections.unmodifiableMap(metricsByNames);
    }

    public void shutdown() {
        if (shutdown.getAndSet(true)) {
            return;
        }

        if (executorService != null) {
            try {
                executorService.shutdown();
                executorService.awaitTermination(1, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

//    private static Double fetchIoWaitPercentage() {
//        // Only Linux is supported
//        if (!OS.IS_LINUX) {
//            return null;
//        }
//
//        try {
//            // Take the second sample from iostat, as the first one is a static value acquired at the machine start-up
//            Process process = Runtime.getRuntime().exec(new String[] {"bash", "-c", "iostat -c 1 2 | awk '/^ /{print $4}'"});
//
//            BufferedReader errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));
//            BufferedReader resultStream = new BufferedReader(new InputStreamReader(process.getInputStream()));
//
//            List outputLines = new ArrayList<>();
//            String line = null;
//            while ((line = resultStream.readLine()) != null) {
//                outputLines.add(line);
//            }
//
//            boolean error = false;
//            while (errorStream.readLine() != null) {
//                error = true;
//            }
//
//            errorStream.close();
//            resultStream.close();
//
//            try {
//                int result = process.waitFor();
//                if (result != 0) {
//                    logger.debug("iostat failed with return code {}", result);
//                }
//            } catch (InterruptedException e) {
//                logger.debug("iostat was interrupted");
//            }
//
//            if (!error && outputLines.size() == 2) {
//                String iowaitPercentStr = outputLines.get(outputLines.size() - 1);
//                try {
//                    return Double.parseDouble(iowaitPercentStr);
//                } catch (NumberFormatException e) {
//                    logger.debug("Error parsing iowait value from {}", iowaitPercentStr);
//                }
//            }
//        } catch (Exception e) {
//            logger.debug("Exception occurred while executing iostat command", e);
//
//            if (InterruptedException.class.isInstance(e)) {
//                Thread.currentThread().interrupt();
//            }
//        }
//
//        return null;
//    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy