/* * Copyright (c) 2010-2016. Axon Framework * * 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 org.axonframework.metrics; import com.codahale.metrics.*; import org.axonframework.messaging.Message; import org.axonframework.monitoring.MessageMonitor; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; /** * Calculates capacity by tracking, within the configured time window, the average message processing time * and multiplying that by the amount of messages processed. * * The capacity can be more than 1 if the monitored * message handler processes the messages in parallel. The capacity for a single threaded message handler will be * a value between 0 and 1. * * If the value for a single threaded message handler is 1 the component is active 100% of the time. This means * that messages will have to wait to be processed. * * @author Marijn van Zelst * @since 3.0 */ public class CapacityMonitor implements MessageMonitor<Message<?>>, MetricSet { private final Histogram processedDurationHistogram; private final TimeUnit timeUnit; private final long window; private final Clock clock; private final Metric capacity; /** * Creates a capacity monitor with the default time window 10 minutes */ public CapacityMonitor() { this(10, TimeUnit.MINUTES); } /** * Creates a capacity monitor with the default time window 10 minutes * * @param window The length of the window to measure the capacity over * @param timeUnit The time unit of the time window */ public CapacityMonitor(long window, TimeUnit timeUnit) { this(window, timeUnit, Clock.defaultClock()); } /** * Creates a capacity monitor with the given time window. Uses the provided clock * to measure process time per message. * * @param window The length of the window to measure the capacity over * @param timeUnit The time unit of the time window * @param clock The clock used to measure the process time per message */ public CapacityMonitor(long window, TimeUnit timeUnit, Clock clock) { SlidingTimeWindowReservoir slidingTimeWindowReservoir = new SlidingTimeWindowReservoir(window, timeUnit, clock); this.processedDurationHistogram = new Histogram(slidingTimeWindowReservoir); this.timeUnit = timeUnit; this.window = window; this.clock = clock; this.capacity = new CapacityGauge(); } @Override public MonitorCallback onMessageIngested(Message<?> message) { final long start = clock.getTime(); return new MonitorCallback() { @Override public void reportSuccess() { processedDurationHistogram.update(clock.getTime() - start); } @Override public void reportFailure(Throwable cause) { processedDurationHistogram.update(clock.getTime() - start); } @Override public void reportIgnored() { processedDurationHistogram.update(clock.getTime() - start); } }; } @Override public Map<String, Metric> getMetrics() { Map<String, Metric> metrics = new HashMap<>(); metrics.put("capacity", capacity); return metrics; } private class CapacityGauge implements Gauge<Double> { @Override public Double getValue() { Snapshot snapshot = processedDurationHistogram.getSnapshot(); double meanProcessTime = snapshot.getMean(); int numProcessed = snapshot.getValues().length; return (numProcessed * meanProcessTime) / timeUnit.toMillis(window); } } }