package com.tinkerpop.rexster.server.metrics; import com.codahale.metrics.ConsoleReporter; import com.codahale.metrics.JmxReporter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.ganglia.GangliaReporter; import com.codahale.metrics.graphite.GraphiteReporter; import com.tinkerpop.rexster.server.RexsterProperties; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.XMLConfiguration; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.TimeUnit; /** * This class is responsible for configuring the metric reporting options in Rexster. This class takes the contents * of the <i>metrics</i> section of rexster.xml to enable different reporting outs such as ganglia, jmx, graphite, etc. * * The <i>http</i> reporter does not initialize by way of the enable() method. It is initialized through a servlet * configured into the HTTP server in Rexster. If Rexster's HTTP is disabled then this reporter will not be accessible. * * @author Stephen Mallette (http://stephen.genoprime.com) */ public class ReporterConfig { private static final Logger logger = Logger.getLogger(ReporterConfig.class); private RexsterProperties properties; private JmxReporter jmxReporter = null; private HttpReporterConfig httpReporterConfig = null; private final MetricRegistry metricRegistry; private final List<AbstractReporterConfig> reporters = new ArrayList<AbstractReporterConfig>(); /** * Create a configuration class from items at the metrics.reporter element of rexster.xml. It reads the * <i>type</i> element from each <i>reporter</i> element and constructs the appropriate config class for * that particular type. */ public ReporterConfig(final RexsterProperties properties, final MetricRegistry metricRegistry) { this.properties = properties; this.metricRegistry = metricRegistry; this.updateSettings(); this.enable(); properties.addListener(new RexsterProperties.RexsterPropertiesListener() { @Override public void propertiesChanged(final XMLConfiguration configuration) { updateSettings(); enable(); } }); } public void updateSettings() { reset(); final Iterator<HierarchicalConfiguration> it = properties.getReporterConfigurations().iterator(); while (it.hasNext()) { final HierarchicalConfiguration reporterConfig = it.next(); final String reporterType = reporterConfig.getString("type"); if (reporterType != null) { if (reporterType.equals("jmx") || reporterType.equals(JmxReporter.class.getCanonicalName())) { // only initializes this once...this shouldn't be generated multiple times. if (jmxReporter == null) { jmxReporter = JmxReporter.forRegistry(metricRegistry).build(); } } else if (reporterType.equals("http")) { // only initializes this once...this shouldn't be generated multiple times. if (httpReporterConfig == null) { httpReporterConfig = new HttpReporterConfig(reporterConfig); } } else if (reporterType.equals("console") || reporterType.equals(ConsoleReporter.class.getCanonicalName())) { reporters.add(new ConsoleReporterConfig(reporterConfig, metricRegistry)); } else if (reporterType.equals("ganglia") || reporterType.equals(GangliaReporter.class.getCanonicalName())) { reporters.add(new GangliaReporterConfig(reporterConfig, metricRegistry)); } else if (reporterType.equals("graphite") || reporterType.equals(GraphiteReporter.class.getCanonicalName())) { reporters.add(new GraphiteReporterConfig(reporterConfig, metricRegistry)); } else { logger.warn(String.format("The configured reporter [%s] is not valid", reporterType)); } } else { logger.warn("A metric reporter was not configured properly. Check rexster.xml as the 'type' attribute was not set."); } } // push overrides into the properties so that they are accessible to the http server. this helps unify // the definition of reporters in rexster.xml this.properties.addOverride("http-reporter-enabled", isHttpReporterEnabled()); this.properties.addOverride("http-reporter-duration", getDurationTimeUnitConversion()); this.properties.addOverride("http-reporter-convert", getRateTimeUnitConversion()); } private void reset() { if (jmxReporter != null) { jmxReporter.stop(); jmxReporter = null; } for (AbstractReporterConfig reporter : reporters) { reporter.disable(); } reporters.clear(); if (httpReporterConfig != null) { httpReporterConfig = null; } this.properties.removeOverride("http-reporter-enabled"); this.properties.removeOverride("http-reporter-duration"); this.properties.removeOverride("http-reporter-convert"); } public boolean isHttpReporterEnabled() { return httpReporterConfig != null; } public String getRateTimeUnitConversion() { return isHttpReporterEnabled() ? httpReporterConfig.getRealRateTimeUnitConversion().toString() : TimeUnit.SECONDS.toString(); } public String getDurationTimeUnitConversion() { return isHttpReporterEnabled() ? httpReporterConfig.getRealDurationTimeUnitConversion().toString() : TimeUnit.SECONDS.toString(); } public void enable() { if (jmxReporter != null) { jmxReporter.start(); } for (AbstractReporterConfig reporter : reporters) { reporter.enable(); } } }