blob: 88d8d50a533124071fa85d60c8be2c37b0ff90aa [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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 org.apache.edgent.metrics;
import java.io.File;
import java.lang.management.ManagementFactory;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import javax.management.MBeanServer;
import org.apache.edgent.execution.services.ServiceContainer;
import org.apache.edgent.function.BiConsumer;
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.CsvReporter;
import com.codahale.metrics.JmxReporter;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricFilter;
import com.codahale.metrics.MetricRegistry;
/**
* Utility helpers for configuring and starting a Metric {@code JmxReporter}
* or a {@code ConsoleReporter}.
* <p>
* This class is not thread safe.
*/
public class MetricsSetup {
private static final TimeUnit durationsUnit = TimeUnit.MILLISECONDS;
private static final TimeUnit ratesUnit = TimeUnit.SECONDS;
private static final String FOLDER_METRICS = "/metrics";
private final MetricRegistry metricRegistry;
private MBeanServer mBeanServer;
/**
* Returns a new {@link MetricsSetup} for configuring metrics.
*
* @param services ServiceContainer to use to add services to
* @param registry the registry to use for the application
* @return a {@link MetricsSetup} instance
*/
public static MetricsSetup withRegistry(ServiceContainer services, MetricRegistry registry) {
final MetricsSetup setup = new MetricsSetup(registry);
services.addService(MetricRegistry.class, registry);
services.addCleaner(setup.new MetricOpletCleaner());
return setup;
}
/**
* Use the specified {@code MBeanServer} with this metric setup.
*
* @param mBeanServer the MBean server used by the metric JMX reporter
* @return this
*/
public MetricsSetup registerWith(MBeanServer mBeanServer) {
this.mBeanServer = mBeanServer;
return this;
}
/**
* Starts the metric {@code JMXReporter}. If no MBeanServer was set, use
* the virtual machine's platform MBeanServer.
* @param jmxDomainName JMX domain name to use when creating JMX MXBean object names.
* @return this
*/
public MetricsSetup startJMXReporter(String jmxDomainName) {
final JmxReporter reporter = JmxReporter.forRegistry(registry()).
registerWith(mbeanServer())
.inDomain(jmxDomainName).createsObjectNamesWith(new MetricObjectNameFactory())
.convertDurationsTo(durationsUnit).convertRatesTo(ratesUnit)
.filter(MetricFilter.ALL).build();
reporter.start();
return this;
}
/**
* Starts the metric {@code CsvReporter}. If no MBeanServer was set, use the
* virtual machine's platform MBeanServer.
*
* @param pathMetrics
* pathname where the metric files are stored. If the path does
* not exist or is null is created in a standard directory,
* called metrics
* @return this
*/
public MetricsSetup startCSVReporter(String pathMetrics) {
if (pathMetrics == null) { // pathMetrics is NULL
pathMetrics = createDefaultDirectory();
} else {
File directory = new File(pathMetrics);
if (!directory.exists() && !directory.mkdirs()) {
pathMetrics = createDefaultDirectory();
}
}
final CsvReporter reporter = CsvReporter.forRegistry(registry()).formatFor(Locale.US).convertRatesTo(ratesUnit)
.convertDurationsTo(durationsUnit).build(new File(pathMetrics));
reporter.start(1, TimeUnit.SECONDS);
return this;
}
/**
* Starts the metric {@code ConsoleReporter} polling every second.
* @return this
*/
public MetricsSetup startConsoleReporter() {
ConsoleReporter reporter = ConsoleReporter.forRegistry(registry()).convertRatesTo(ratesUnit)
.convertDurationsTo(durationsUnit).build();
reporter.start(1, TimeUnit.SECONDS);
return this;
}
private MetricsSetup(MetricRegistry registry) {
this.metricRegistry = registry;
}
private MetricRegistry registry() {
return metricRegistry;
}
private MBeanServer mbeanServer() {
if (mBeanServer == null) {
mBeanServer = ManagementFactory.getPlatformMBeanServer();
}
return mBeanServer;
}
/**
* Creates a default directory for metrics.
*
* @return directory.getPath()
*/
private String createDefaultDirectory() {
Path currentRelativePath = Paths.get("");
String pathMetrics = currentRelativePath.toAbsolutePath().toString() + FOLDER_METRICS;
File directory = new File(pathMetrics);
if (!directory.mkdirs()) {
// Log: "Could not create the directory log"
} else {
// Log: "The directory was created successfully: "
}
return directory.getPath();
}
private class MetricOpletCleaner implements BiConsumer<String, String> {
// Use the project's BiConsumer (serializable) implementation to avoid
// a dependency on Java 8's functional interfaces.
private static final long serialVersionUID = 1L;
@Override
public void accept(String jobId, String opletId) {
// TODO logging System.err.println("CLEANING:" + jobId + " --" + opletId);
registry().removeMatching(new MetricFilter() {
@Override
public boolean matches(String name, Metric metric) {
return name.endsWith(
new StringBuilder().append('.').append(jobId).append('.').append(opletId).toString());
}
});
}
}
}