| /* |
| 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()); |
| } |
| }); |
| } |
| } |
| } |