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

com.tinkerpop.gremlin.server.util.MetricManager Maven / Gradle / Ivy

The newest version!
package com.tinkerpop.gremlin.server.util;

import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.Counter;
import com.codahale.metrics.CsvReporter;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.JmxReporter;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricFilter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Slf4jReporter;
import com.codahale.metrics.Timer;
import com.codahale.metrics.ganglia.GangliaReporter;
import com.codahale.metrics.graphite.Graphite;
import com.codahale.metrics.graphite.GraphiteReporter;
import info.ganglia.gmetric4j.gmetric.GMetric;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * Singleton that contains and configures Gremlin Server's {@code MetricRegistry}. Borrowed from Titan's approach to
 * managing Metrics.
 *
 * @author Stephen Mallette (http://stephen.genoprime.com)
 */
public enum MetricManager {
    INSTANCE;

    private static final Logger log = LoggerFactory.getLogger(MetricManager.class);

    private final MetricRegistry registry = new MetricRegistry();
    private ConsoleReporter consoleReporter = null;
    private CsvReporter csvReporter = null;
    private JmxReporter jmxReporter = null;
    private Slf4jReporter slf4jReporter = null;
    private GangliaReporter gangliaReporter = null;
    private GraphiteReporter graphiteReporter = null;

    /**
     * Return the Titan Metrics registry.
     *
     * @return the single {@code MetricRegistry} used for all of Titan's Metrics
     * monitoring
     */
    public MetricRegistry getRegistry() {
        return registry;
    }

    /**
     * Create a {@link ConsoleReporter} attached to the Titan Metrics registry.
     *
     * @param reportIntervalInMS milliseconds to wait between dumping metrics to the console
     */
    public synchronized void addConsoleReporter(final long reportIntervalInMS) {
        if (null != consoleReporter) {
            log.debug("Metrics ConsoleReporter already active; not creating another");
            return;
        }

        consoleReporter = ConsoleReporter.forRegistry(getRegistry()).build();
        consoleReporter.start(reportIntervalInMS, TimeUnit.MILLISECONDS);

        log.info("Configured Metrics ConsoleReporter configured with report interval={}ms", reportIntervalInMS);
    }

    /**
     * Stop a {@link ConsoleReporter} previously created by a call to
     * {@link #addConsoleReporter(long)} and release it for GC. Idempotent
     * between calls to the associated add method. Does nothing before the first
     * call to the associated add method.
     */
    public synchronized void removeConsoleReporter() {
        if (null != consoleReporter)
            consoleReporter.stop();

        consoleReporter = null;
    }

    /**
     * Create a {@link CsvReporter} attached to the Titan Metrics registry.
     * 

* The {@code output} argument must be non-null but need not exist. If it * doesn't already exist, this method attempts to create it by calling * {@link File#mkdirs()}. * * @param reportIntervalInMS milliseconds to wait between dumping metrics to CSV files in * the configured directory * @param output the path to a directory into which Metrics will periodically * write CSV data */ public synchronized void addCsvReporter(final long reportIntervalInMS, final String output) { File outputDir = new File(output); if (null != csvReporter) { log.debug("Metrics CsvReporter already active; not creating another"); return; } if (!outputDir.exists()) { if (!outputDir.mkdirs()) { log.warn("Failed to create CSV metrics dir {}", outputDir); } } csvReporter = CsvReporter.forRegistry(getRegistry()).build(outputDir); csvReporter.start(reportIntervalInMS, TimeUnit.MILLISECONDS); log.info("Configured Metrics CsvReporter configured with report interval={}ms to fileName={}", reportIntervalInMS, output); } /** * Stop a {@link CsvReporter} previously created by a call to * {@link #addCsvReporter(long, String)} and release it for GC. Idempotent * between calls to the associated add method. Does nothing before the first * call to the associated add method. */ public synchronized void removeCsvReporter() { if (null != csvReporter) csvReporter.stop(); csvReporter = null; } /** * Create a {@link JmxReporter} attached to the Titan Metrics registry. *

* If {@code domain} or {@code agentId} is null, then Metrics's uses its own * internal default value(s). *

* If {@code agentId} is non-null, then * MBeanServerFactory#findMBeanServer(agentId) must return exactly * one {@code MBeanServer}. The reporter will register with that server. If * the {@code findMBeanServer(agentId)} call returns no or multiple servers, * then this method logs an error and falls back on the Metrics default for * {@code agentId}. * * @param domain the JMX domain in which to continuously expose metrics * @param agentId the JMX agent ID */ public synchronized void addJmxReporter(final String domain, final String agentId) { if (null != jmxReporter) { log.debug("Metrics JmxReporter already active; not creating another"); return; } JmxReporter.Builder b = JmxReporter.forRegistry(getRegistry()); if (null != domain) { b.inDomain(domain); } if (null != agentId) { List servs = MBeanServerFactory.findMBeanServer(agentId); if (null != servs && 1 == servs.size()) { b.registerWith(servs.get(0)); } else { log.error("Metrics Slf4jReporter agentId {} does not resolve to a single MBeanServer", agentId); } } jmxReporter = b.build(); jmxReporter.start(); log.info("Configured Metrics JmxReporter configured with domain={} and agentId={}", Optional.ofNullable(domain).orElse(""), Optional.ofNullable(agentId).orElse("")); } /** * Stop a {@link JmxReporter} previously created by a call to * {@link #addJmxReporter(String, String)} and release it for GC. Idempotent * between calls to the associated add method. Does nothing before the first * call to the associated add method. */ public synchronized void removeJmxReporter() { if (null != jmxReporter) jmxReporter.stop(); jmxReporter = null; } /** * Create a {@link Slf4jReporter} attached to the Titan Metrics registry. *

* If {@code loggerName} is null, or if it is non-null but * LoggerFactory.getLogger(loggerName) returns null, then Metrics's * default Slf4j logger name is used instead. * * @param reportIntervalInMS milliseconds to wait between writing metrics to the Slf4j * logger * @param loggerName the name of the Slf4j logger that receives metrics */ public synchronized void addSlf4jReporter(final long reportIntervalInMS, final String loggerName) { if (null != slf4jReporter) { log.debug("Metrics Slf4jReporter already active; not creating another"); return; } Slf4jReporter.Builder b = Slf4jReporter.forRegistry(getRegistry()); if (null != loggerName) { Logger l = LoggerFactory.getLogger(loggerName); if (null != l) { b.outputTo(l); } else { log.error("Logger with name {} could not be obtained", loggerName); } } slf4jReporter = b.build(); slf4jReporter.start(reportIntervalInMS, TimeUnit.MILLISECONDS); log.info("Configured Metrics Slf4jReporter configured with interval={}ms and loggerName={}", reportIntervalInMS, loggerName); } /** * Stop a {@link Slf4jReporter} previously created by a call to * {@link #addSlf4jReporter(long, String)} and release it for GC. Idempotent * between calls to the associated add method. Does nothing before the first * call to the associated add method. */ public synchronized void removeSlf4jReporter() { if (null != slf4jReporter) slf4jReporter.stop(); slf4jReporter = null; } /** * Create a {@link GangliaReporter} attached to the Titan Metrics registry. *

* {@code groupOrHost} and {@code addressingMode} must be non-null. The * remaining non-primitive arguments may be null. If {@code protocol31} is * null, then true is assumed. Null values of {@code hostUUID} or * {@code spoof} are passed into the {@link GMetric} constructor, which * causes Ganglia to use its internal logic for generating a default UUID * and default reporting hostname (respectively). * * @param groupOrHost the multicast group or unicast hostname to which Ganglia * events are sent * @param port the port to which events are sent * @param addressingMode whether to send events with multicast or unicast * @param ttl multicast ttl (ignored for unicast) * @param protocol31 true to use Ganglia protocol version 3.1, false to use 3.0 * @param hostUUID uuid for the host * @param spoof override this machine's IP/hostname as it appears on the * Ganglia server * @param reportIntervalInMS milliseconds to wait before sending data to the ganglia * unicast host or multicast group * @throws IOException when a {@link GMetric} can't be instantiated using the * provided arguments */ public synchronized void addGangliaReporter(final String groupOrHost, final int port, final GMetric.UDPAddressingMode addressingMode, final int ttl, final Boolean protocol31, final UUID hostUUID, final String spoof, final long reportIntervalInMS) throws IOException { if (null == groupOrHost || groupOrHost.isEmpty()) throw new IllegalArgumentException("groupOrHost cannot be null or empty"); if (null == addressingMode) throw new IllegalArgumentException("addressing mode cannot be null"); if (null != gangliaReporter) { log.debug("Metrics GangliaReporter already active; not creating another"); return; } final boolean protocol = null == protocol31 ? true : protocol31; GMetric ganglia = new GMetric(groupOrHost, port, addressingMode, ttl, protocol, hostUUID, spoof); GangliaReporter.Builder b = GangliaReporter.forRegistry(getRegistry()); gangliaReporter = b.build(ganglia); gangliaReporter.start(reportIntervalInMS, TimeUnit.MILLISECONDS); log.info("Configured Ganglia Metrics reporter host={} interval={}ms port={} addrmode={} ttl={} proto31={} uuid={} spoof={}", new Object[]{groupOrHost, reportIntervalInMS, port, addressingMode, ttl, protocol31, hostUUID, spoof}); } /** * Stop a {@link GangliaReporter} previously created by a call to * addGangliaReporter(String, int, GMetric.UDPAddressingMode, int, Boolean, UUID, long) * and release it for GC. Idempotent between calls to the associated add * method. Does nothing before the first call to the associated add method. */ public synchronized void removeGangliaReporter() { if (null != gangliaReporter) gangliaReporter.stop(); gangliaReporter = null; } /** * Create a {@link GraphiteReporter} attached to the Titan Metrics registry. *

* If {@code prefix} is null, then Metrics's internal default prefix is used * (empty string at the time this comment was written). * * @param host the host to which Graphite reports are sent * @param port the port to which Graphite reports are sent * @param prefix the optional metrics prefix * @param reportIntervalInMS milliseconds to wait between sending metrics to the configured * Graphite host and port */ public synchronized void addGraphiteReporter(final String host, final int port, final String prefix, final long reportIntervalInMS) { if (host == null || host.isEmpty()) throw new IllegalArgumentException("Host cannot be null or empty"); Graphite graphite = new Graphite(new InetSocketAddress(host, port)); GraphiteReporter.Builder b = GraphiteReporter .forRegistry(getRegistry()); if (null != prefix) b.prefixedWith(prefix); b.filter(MetricFilter.ALL); graphiteReporter = b.build(graphite); graphiteReporter.start(reportIntervalInMS, TimeUnit.MILLISECONDS); log.info("Configured Graphite reporter host={} interval={}ms port={} prefix={}", new Object[]{host, reportIntervalInMS, port, prefix}); } /** * Stop a {@link GraphiteReporter} previously created by a call to * {@link #addGraphiteReporter(String, int, String, long)} and release it * for GC. Idempotent between calls to the associated add method. Does * nothing before the first call to the associated add method. */ public synchronized void removeGraphiteReporter() { if (null != graphiteReporter) graphiteReporter.stop(); graphiteReporter = null; } /** * Remove all Titan Metrics reporters previously configured through the * {@code add*} methods on this class. */ public synchronized void removeAllReporters() { removeConsoleReporter(); removeCsvReporter(); removeJmxReporter(); removeSlf4jReporter(); removeGangliaReporter(); removeGraphiteReporter(); } public Counter getCounter(final String name) { return getRegistry().counter(name); } public Counter getCounter(final String prefix, final String... names) { return getRegistry().counter(MetricRegistry.name(prefix, names)); } public Gauge getGuage(final Gauge gauge, final String name) { return getRegistry().register(name, gauge); } public Gauge getGuage(final Gauge gauge, final String prefix, final String... names) { return getRegistry().register(MetricRegistry.name(prefix, names), gauge); } public Meter getMeter(final String name) { return getRegistry().meter(name); } public Meter getMeter(final String prefix, final String... names) { return getRegistry().meter(MetricRegistry.name(prefix, names)); } public Timer getTimer(final String name) { return getRegistry().timer(name); } public Timer getTimer(final String prefix, final String... names) { return getRegistry().timer(MetricRegistry.name(prefix, names)); } public Histogram getHistogram(final String name) { return getRegistry().histogram(name); } public Histogram getHistogram(final String prefix, final String... names) { return getRegistry().histogram(MetricRegistry.name(prefix, names)); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy