// Copyright 2016 Twitter. All rights reserved. // // 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 com.twitter.heron.simulator.executors; import java.util.LinkedList; import java.util.List; import java.util.logging.Logger; import com.twitter.heron.common.basics.Communicator; import com.twitter.heron.common.basics.SlaveLooper; import com.twitter.heron.common.basics.WakeableLooper; import com.twitter.heron.common.config.SystemConfig; import com.twitter.heron.common.utils.metrics.JVMMetrics; import com.twitter.heron.common.utils.metrics.MetricsCollector; import com.twitter.heron.proto.system.Metrics; /** * MetricsExecutor would run in a separate thread via WakeableLooper, * and block until it is waken up by metrics pushed from other InstanceExecutor. * <p> * Then it would look up all InstanceExecutor added and invoke * handleExecutorsMetrics(InstanceExecutor instance) to handle the metrics */ public class MetricsExecutor implements Runnable { private static final Logger LOG = Logger.getLogger(InstanceExecutor.class.getName()); private final List<InstanceExecutor> instanceExecutors; private final WakeableLooper looper; // MetricsCollector used to collect internal metrics of MetricsExecutor private final MetricsCollector metricsCollector; // Communicator to be bind with MetricsCollector to collect metrics private final Communicator<Metrics.MetricPublisherPublishMessage> metricsQueue; private final SystemConfig systemConfig; private final String executorId = "Simulator_Metrics_Executor"; public MetricsExecutor(SystemConfig systemConfig) { instanceExecutors = new LinkedList<>(); looper = createWakeableLooper(); this.metricsQueue = new Communicator<Metrics.MetricPublisherPublishMessage>(null, this.looper); this.metricsCollector = new MetricsCollector(this.looper, metricsQueue); this.systemConfig = systemConfig; } public void addInstanceExecutor(InstanceExecutor instanceExecutor) { // Set the InstanceExecutor's metricsOutQueue's consumer instanceExecutor.getMetricsOutQueue().setConsumer(looper); instanceExecutors.add(instanceExecutor); } private void setupJVMMetrics() { JVMMetrics jvmMetrics = new JVMMetrics(); jvmMetrics.registerMetrics(metricsCollector); // Attach sample Runnable to gatewayMetricsCollector this.metricsCollector.registerMetricSampleRunnable(jvmMetrics.getJVMSampleRunnable(), systemConfig.getHeronMetricsExportInterval().dividedBy(2)); } @Override public void run() { Thread.currentThread().setName(executorId); LOG.info("Metrics_Executor starts"); setupJVMMetrics(); addMetricsExecutorTasks(); looper.loop(); } public void stop() { looper.exitLoop(); } protected void addMetricsExecutorTasks() { Runnable metricsExecutorsTasks = new Runnable() { @Override public void run() { for (InstanceExecutor instance : instanceExecutors) { handleExecutorsMetrics(instance); } // Handle internal metrics while (!metricsQueue.isEmpty()) { handleMetricPublisherPublishMessage(executorId, metricsQueue.poll()); } } }; looper.addTasksOnWakeup(metricsExecutorsTasks); } protected void handleExecutorsMetrics(InstanceExecutor instance) { // TODO(mfu): We might also need to handle the instance's info while (!instance.getMetricsOutQueue().isEmpty()) { handleMetricPublisherPublishMessage( instance.getInstanceId(), instance.getMetricsOutQueue().poll()); } } protected void handleMetricPublisherPublishMessage( String instanceId, Metrics.MetricPublisherPublishMessage message) { // TODO(mfu): Currently we just log the metrics; would add more handling in future LOG.info( String.format("Metrics from %s at time %s:\n%s", instanceId, System.currentTimeMillis(), message.toString())); } protected WakeableLooper createWakeableLooper() { return new SlaveLooper(); } }