package org.ethereum.net.server;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.socket.DatagramPacket;
import org.ethereum.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import static org.ethereum.util.Utils.sizeToStr;
/**
* Created by Anton Nashatyrev on 27.02.2017.
*/
@Component
public class WireTrafficStats implements Runnable {
private final static Logger logger = LoggerFactory.getLogger("net");
private ScheduledExecutorService executor;
public final TrafficStatHandler tcp = new TrafficStatHandler();
public final TrafficStatHandler udp = new TrafficStatHandler();
public WireTrafficStats() {
executor = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setNameFormat("WireTrafficStats-%d").build());
executor.scheduleAtFixedRate(this, 10, 10, TimeUnit.SECONDS);
}
@Override
public void run() {
logger.info("TCP: " + tcp.stats());
logger.info("UDP: " + udp.stats());
}
@PreDestroy
public void close() {
executor.shutdownNow();
}
@ChannelHandler.Sharable
static class TrafficStatHandler extends ChannelDuplexHandler {
long outSizeTot;
long inSizeTot;
AtomicLong outSize = new AtomicLong();
AtomicLong inSize = new AtomicLong();
AtomicLong outPackets = new AtomicLong();
AtomicLong inPackets = new AtomicLong();
long lastTime = System.currentTimeMillis();
public String stats() {
long out = outSize.getAndSet(0);
long outPac = outPackets.getAndSet(0);
long in = inSize.getAndSet(0);
long inPac = inPackets.getAndSet(0);
outSizeTot += out;
inSizeTot += in;
long curTime = System.currentTimeMillis();
long d = (curTime - lastTime);
long outSpeed = out * 1000 / d;
long inSpeed = in * 1000 / d;
lastTime = curTime;
return "Speed in/out " + sizeToStr(inSpeed) + " / " + sizeToStr(outSpeed) +
"(sec), packets in/out " + inPac + "/" + outPac +
", total in/out: " + sizeToStr(inSizeTot) + " / " + sizeToStr(outSizeTot);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
inPackets.incrementAndGet();
if (msg instanceof ByteBuf) {
inSize.addAndGet(((ByteBuf) msg).readableBytes());
} else if (msg instanceof DatagramPacket) {
inSize.addAndGet(((DatagramPacket) msg).content().readableBytes());
}
super.channelRead(ctx, msg);
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
outPackets.incrementAndGet();
if (msg instanceof ByteBuf) {
outSize.addAndGet(((ByteBuf) msg).readableBytes());
} else if (msg instanceof DatagramPacket) {
outSize.addAndGet(((DatagramPacket) msg).content().readableBytes());
}
super.write(ctx, msg, promise);
}
}
}