package com.tacitknowledge.slowlight.proxyserver.metrics; import com.netflix.servo.annotations.DataSourceType; import com.netflix.servo.annotations.Monitor; import com.netflix.servo.monitor.Monitors; import com.tacitknowledge.slowlight.proxyserver.config.HandlerConfig; import com.tacitknowledge.slowlight.proxyserver.handler.AbstractChannelHandler; import io.netty.buffer.ByteBuf; import java.util.Date; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; /** * A {@link io.netty.channel.ChannelHandler} implementation that computes * throughput as bytes per second. The metric is determined at two levels : * * <b>Frame</b> - inside a specified time frame * <b>Channel</b> - throughput determined per test session * * See also : * * {@link com.tacitknowledge.slowlight.proxyserver.metrics.InThroughputHandler} * * and * * {@link com.tacitknowledge.slowlight.proxyserver.metrics.OutThroughputHandler} * * @author Pavel Sorocun (psorocun@tacitknowledge.com) */ public class ThroughputHandler extends AbstractChannelHandler { public static final TimeUnit SECONDS = TimeUnit.SECONDS; public static final TimeUnit MILLISECONDS = TimeUnit.MILLISECONDS; private Date startDate = new Date(); private AtomicLong frameReadBytes = new AtomicLong(0); private AtomicLong channelBytes = new AtomicLong(0); public ThroughputHandler(final HandlerConfig handlerConfig) { super(handlerConfig); Monitors.registerObject(handlerConfig.getName(), this); } protected void updateThroughputMetric(final Object msg) { final long readableBytes = ((ByteBuf) msg).readableBytes(); if(readableBytes > Long.MAX_VALUE - channelBytes.longValue()) { channelBytes.getAndSet(0); } frameReadBytes.getAndAdd(readableBytes); channelBytes.getAndAdd(readableBytes); } @Monitor(name = "FrameThroughput(bytes_per_second)", type = DataSourceType.GAUGE) public long getFrameThroughput() { return getFrameReadBytes() / SECONDS.convert(getFrameTimeElapsed(), MILLISECONDS); } @Monitor(name = "ChannelThroughput(bytes_per_second)", type = DataSourceType.GAUGE) public long getChannelThroughput() { return getChannelBytes() / SECONDS.convert(getSessionTimeElapsed(), MILLISECONDS); } protected void timerCallback() { frameReadBytes.getAndSet(0); } public long getSessionTimeElapsed() { return System.currentTimeMillis() - startDate.getTime(); } public long getFrameTimeElapsed() { return getSessionTimeElapsed() % (MILLISECONDS.convert(getTimeFrame(), SECONDS)); } public long getFrameReadBytes() { return frameReadBytes.longValue(); } public long getChannelBytes() { return channelBytes.longValue(); } }