dropship.agent.statsd.SnitchService.java Source code

Java tutorial

Introduction

Here is the source code for dropship.agent.statsd.SnitchService.java

Source

/*
 * Copyright (C) 2014 zulily, Inc.
 *
 * 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 dropship.agent.statsd;

import com.google.common.base.CharMatcher;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.AbstractScheduledService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;

import javax.inject.Inject;
import javax.inject.Named;
import java.io.File;
import java.lang.management.ClassLoadingMXBean;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadMXBean;
import java.net.InetAddress;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static com.google.common.base.Preconditions.checkNotNull;

abstract class SnitchService extends AbstractScheduledService {

    private static final Joiner KEY_JOINER = Joiner.on('.').useForNull("null");

    private static String getHostname() {
        String defaultHostname = "localhost";
        try {
            return Iterables.getFirst(Splitter.on('.').split(InetAddress.getLocalHost().getHostName()),
                    defaultHostname);
        } catch (Exception e) {
            return defaultHostname;
        }
    }

    private final ImmutableList<String> gavKeys;
    private final ImmutableList<String> hostKeys;
    private final ImmutableList<String> methodKeys;

    SnitchService(Properties properties, String groupArtifactId, Class mainClass) {
        checkNotNull(properties, "properties");
        this.gavKeys = ImmutableList.copyOf(
                Iterables.limit(Splitter.on(':').split(CharMatcher.is('.').replaceFrom(groupArtifactId, '-')), 2));
        this.hostKeys = ImmutableList.of(getHostname());
        String simplifiedMainClassName = Iterables.getLast(Splitter.on('.').split(mainClass.getName()));
        this.methodKeys = ImmutableList.of(simplifiedMainClassName);
    }

    @Override
    protected final Scheduler scheduler() {
        return Scheduler.newFixedRateSchedule(0L, 1L, TimeUnit.SECONDS);
    }

    @Override
    protected final ScheduledExecutorService executor() {
        final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(
                new ThreadFactoryBuilder().setNameFormat(serviceName()).setDaemon(true).build());
        addListener(new Listener() {
            @Override
            public void starting() {
            }

            @Override
            public void running() {
            }

            @Override
            public void stopping(State from) {
            }

            @Override
            public void terminated(State from) {
                executor.shutdown();
            }

            @Override
            public void failed(State from, Throwable failure) {
                executor.shutdown();
            }
        }, MoreExecutors.sameThreadExecutor());
        return executor;
    }

    protected String key(String key) {
        return KEY_JOINER.join(Iterables.concat(baseKey(), ImmutableList.of(key)));
    }

    private Iterable<String> baseKey() {
        return Iterables.concat(ImmutableList.of("dropship"), hostKeys, gavKeys, methodKeys);
    }

    static final class GarbageCollectionSnitch extends SnitchService {

        private final StatsdStatsLogger logger;
        private final ImmutableList<GarbageCollectorMXBean> mxBeans;
        private final Map<String, Long> collectionTimes;
        private final Map<String, Long> collectionCounts;

        @Inject
        public GarbageCollectionSnitch(StatsdStatsLogger logger, Properties properties, @Named("gav") String gav,
                @Named("main") Class mainClass) {
            super(properties, gav, mainClass);

            this.logger = checkNotNull(logger);
            this.mxBeans = ImmutableList.copyOf(ManagementFactory.getGarbageCollectorMXBeans());
            this.collectionTimes = Maps.newHashMapWithExpectedSize(mxBeans.size());
            this.collectionCounts = Maps.newHashMapWithExpectedSize(mxBeans.size());
        }

        @Override
        public void runOneIteration() {
            for (GarbageCollectorMXBean mxBean : mxBeans) {
                String gcName = mxBean.getName();

                long time = mxBean.getCollectionTime();
                if (collectionTimes.containsKey(gcName)) {
                    long delta = time - collectionTimes.get(gcName);
                    collectionTimes.put(gcName, time);
                    time = delta;
                } else {
                    collectionTimes.put(gcName, time);
                }

                logger.increment(key("gc-" + gcName + "-time-ms"), time);

                long count = mxBean.getCollectionCount();
                if (collectionCounts.containsKey(gcName)) {
                    long delta = count - collectionCounts.get(gcName);
                    collectionCounts.put(gcName, count);
                    count = delta;
                } else {
                    collectionCounts.put(gcName, count);
                }

                logger.increment(key("gc-" + gcName + "-count"), count);
            }
        }
    }

    static final class ThreadSnitch extends SnitchService {

        private final StatsdStatsLogger logger;
        private final ThreadMXBean mxBean;
        private final boolean skipCpu;

        private long lastCpuTimeNanos = 0L;

        @Inject
        public ThreadSnitch(StatsdStatsLogger logger, Properties properties, @Named("gav") String gav,
                @Named("main") Class mainClass) {
            super(properties, gav, mainClass);

            this.logger = checkNotNull(logger);
            this.mxBean = ManagementFactory.getThreadMXBean();

            if (mxBean.isThreadCpuTimeSupported()) {
                mxBean.setThreadCpuTimeEnabled(true);
                skipCpu = false;
            } else {
                System.err.println("Thread CPU time snitching is not supported");
                skipCpu = true;
            }
        }

        @Override
        public void runOneIteration() {
            long[] threadIds = mxBean.getAllThreadIds();

            logger.increment(key("daemon-threads"), mxBean.getDaemonThreadCount());
            logger.increment(key("peak-threads"), mxBean.getPeakThreadCount());
            logger.increment(key("all-threads"), mxBean.getThreadCount());
            logger.increment(key("total-threads"), mxBean.getTotalStartedThreadCount());

            if (skipCpu) {
                logger.increment(key("cpu-time-ms"), 0L);
            } else {
                long totalCpuTimeNanos = 0L;
                for (long thread : threadIds) {
                    long threadCpuTimeNanos = mxBean.getThreadCpuTime(thread);
                    if (threadCpuTimeNanos > 0) {
                        totalCpuTimeNanos += threadCpuTimeNanos;
                    }
                }

                long ms = TimeUnit.NANOSECONDS.toMillis(totalCpuTimeNanos - lastCpuTimeNanos);
                if (ms > 0) {
                    lastCpuTimeNanos = totalCpuTimeNanos;
                }
                logger.increment(key("cpu-time-ms"), Math.max(0, ms));
            }
        }
    }

    static final class MemorySnitch extends SnitchService {

        private final StatsdStatsLogger logger;
        private final MemoryMXBean mxBean;

        @Inject
        public MemorySnitch(StatsdStatsLogger logger, Properties properties, @Named("gav") String gav,
                @Named("main") Class mainClass) {
            super(properties, gav, mainClass);

            this.logger = checkNotNull(logger);
            this.mxBean = ManagementFactory.getMemoryMXBean();
        }

        @Override
        public void runOneIteration() {
            MemoryUsage heap = mxBean.getHeapMemoryUsage();
            long heapCommitted = heap.getCommitted();
            long heapInit = heap.getInit();
            long heapMax = heap.getMax();
            long heapUsed = heap.getUsed();

            MemoryUsage nonHeap = mxBean.getNonHeapMemoryUsage();
            long nonHeapCommitted = nonHeap.getCommitted();
            long nonHeapInit = nonHeap.getInit();
            long nonHeapMax = nonHeap.getMax();
            long nonHeapUsed = nonHeap.getUsed();

            long pending = mxBean.getObjectPendingFinalizationCount();

            logger.increment(key("heap-committed"), heapCommitted);
            logger.increment(key("heap-init"), heapInit);
            logger.increment(key("heap-max"), heapMax);
            logger.increment(key("heap-used"), heapUsed);

            logger.increment(key("nonheap-committed"), nonHeapCommitted);
            logger.increment(key("nonheap-init"), nonHeapInit);
            logger.increment(key("nonheap-max"), nonHeapMax);
            logger.increment(key("nonheap-used"), nonHeapUsed);

            logger.increment(key("pending-finalization"), pending);
        }
    }

    static final class ClassLoadingSnitch extends SnitchService {

        private final StatsdStatsLogger logger;
        private final ClassLoadingMXBean mxBean;

        @Inject
        public ClassLoadingSnitch(StatsdStatsLogger logger, Properties properties, @Named("gav") String gav,
                @Named("main") Class mainClass) {
            super(properties, gav, mainClass);

            this.logger = checkNotNull(logger);
            this.mxBean = ManagementFactory.getClassLoadingMXBean();
        }

        @Override
        public void runOneIteration() {
            int loaded = mxBean.getLoadedClassCount();
            long totalLoaded = mxBean.getTotalLoadedClassCount();
            long unloaded = mxBean.getUnloadedClassCount();

            logger.increment(key("classes-loaded"), loaded);
            logger.increment(key("classes-loaded-total"), totalLoaded);
            logger.increment(key("classes-unloaded"), unloaded);
        }
    }

    static final class DiskSpaceSnitch extends SnitchService {

        private final StatsdStatsLogger logger;

        private final File cwd;

        @Inject
        public DiskSpaceSnitch(StatsdStatsLogger logger, Properties properties, @Named("gav") String gav,
                @Named("main") Class mainClass) {
            super(properties, gav, mainClass);

            this.logger = checkNotNull(logger);
            this.cwd = new File(".");
        }

        @Override
        public void runOneIteration() {
            long totalSpace = cwd.getTotalSpace();
            long freeSpace = cwd.getFreeSpace();
            long usableSpace = cwd.getUsableSpace();

            logger.increment(key("total-disk"), totalSpace, 1D);
            logger.increment(key("usable-disk"), usableSpace, 1D);
            logger.increment(key("free-disk"), freeSpace, 1D);
        }
    }

    static final class UptimeSnitch extends SnitchService {

        private final StatsdStatsLogger logger;
        private final RuntimeMXBean mxBean;

        @Inject
        public UptimeSnitch(StatsdStatsLogger logger, Properties properties, @Named("gav") String gav,
                @Named("main") Class mainClass) {
            super(properties, gav, mainClass);

            this.logger = checkNotNull(logger);
            this.mxBean = ManagementFactory.getRuntimeMXBean();
        }

        @Override
        public void runOneIteration() {
            logger.increment(key("uptime-ms"), mxBean.getUptime(), 1D);
            logger.increment(key("ticks"), 1L, 1D);
        }
    }

    static class NoOp extends SnitchService {

        @Inject
        NoOp(Properties properties, @Named("gav") String gav, @Named("main") Class mainClass) {
            super(properties, gav, mainClass);
        }

        @Override
        protected void runOneIteration() {
        }
    }
}