package com.intrbiz.bergamot.agent.handler; import java.security.SecureRandom; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.Timer; import java.util.TimerTask; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; import org.hyperic.sigar.Humidor; import org.hyperic.sigar.NetInterfaceStat; import org.hyperic.sigar.SigarException; import org.hyperic.sigar.SigarProxy; import com.intrbiz.bergamot.agent.util.SampleRingBuffer; import com.intrbiz.bergamot.model.message.agent.AgentMessage; import com.intrbiz.bergamot.model.message.agent.check.CheckNetIO; import com.intrbiz.bergamot.model.message.agent.stat.NetIOStat; import com.intrbiz.bergamot.model.message.agent.stat.netio.NetIOInfo; import com.intrbiz.bergamot.model.message.agent.stat.netio.NetIORateInfo; public class NetIOHandler extends AbstractAgentHandler { private Logger logger = Logger.getLogger(NetIOHandler.class); private final SigarProxy sigar = Humidor.getInstance().getSigar(); private final Timer timer = new Timer(); private final Map<String, NetIO> registeredInterfaces = new ConcurrentHashMap<String, NetIO>(); public NetIOHandler() { super(); // register polling of known interfaces this.setupInterfaceSampling(); // periodically setup interfaces this.timer.scheduleAtFixedRate(new TimerTask() { public void run() { setupInterfaceSampling(); } }, TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(1)); } @Override public Class<?>[] getMessages() { return new Class[] { CheckNetIO.class }; } @Override public AgentMessage handle(AgentMessage request) { CheckNetIO check = (CheckNetIO) request; NetIOStat stat = new NetIOStat(request); // get stats for our interfaces for (String name : (check.getInterfaces() == null || check.getInterfaces().isEmpty() ? this.registeredInterfaces.keySet() : check.getInterfaces())) { NetIO net = this.registeredInterfaces.get(name); if (net != null) { NetIOInfo info = new NetIOInfo(name); info.setInstantRate(net.instantRate()); info.setFiveMinuteRate(net.fiveMinuteRate()); stat.getIfaces().add(info); } } return stat; } protected void setupInterfaceSampling() { synchronized (this) { try { Set<String> interfaces = new TreeSet<String>(Arrays.asList(this.sigar.getNetInterfaceList())); // add interfaces not yet setup SecureRandom random = new SecureRandom(); for (String interfaceName : interfaces) { if (! this.registeredInterfaces.containsKey(interfaceName)) { // setup NetIO netIO = new NetIO(interfaceName, 60, 5L, TimeUnit.SECONDS); // register this.registeredInterfaces.put(interfaceName, netIO); // schedule long skew = ((long) (netIO.interval * random.nextDouble())); this.timer.scheduleAtFixedRate(netIO, skew, netIO.interval); logger.info("Starting sampling of network IO for interface: " + interfaceName + " every 5 seconds"); } } // remove any interfaces which have gone away for (Iterator<Entry<String, NetIO>> i = this.registeredInterfaces.entrySet().iterator(); i.hasNext(); ) { Entry<String, NetIO> entry = i.next(); // remove ? if (! interfaces.contains(entry.getKey())) { // cancel the task entry.getValue().cancel(); // remove from our registered list i.remove(); logger.info("Stopping sampling of network IO for interface: " + entry.getKey()); } } // clean up the timer this.timer.purge(); } catch (SigarException e) { logger.error("Failed to setup interface sampling", e); } } } protected static double round(double d) { return (((double) Math.round(d * 1000)) / 1000D); } private class NetIO extends TimerTask { private final String interfaceName; private final long interval; private final SampleRingBuffer txBytes; private final SampleRingBuffer rxBytes; private int failCount = 0; public NetIO(String interfaceName, int capacity, long interval, TimeUnit intervalUnit) { this.interfaceName = interfaceName; this.interval = intervalUnit.toMillis(interval); this.txBytes = new SampleRingBuffer(capacity, interval, intervalUnit); this.rxBytes = new SampleRingBuffer(capacity, interval, intervalUnit); } public void addSample(NetInterfaceStat sample) { synchronized (this) { this.txBytes.addSample(sample.getTxBytes()); this.rxBytes.addSample(sample.getRxBytes()); } } public NetIORateInfo instantRate() { synchronized (this) { return new NetIORateInfo( this.txBytes.instantRateSeconds(), this.rxBytes.instantRateSeconds(), this.txBytes.peakRateSeconds(), this.rxBytes.peakRateSeconds() ); } } public NetIORateInfo fiveMinuteRate() { synchronized (this) { return new NetIORateInfo( this.txBytes.averageRateSeconds(), this.rxBytes.averageRateSeconds(), this.txBytes.peakRateSeconds(), this.rxBytes.peakRateSeconds() ); } } @Override public void run() { // sample this interface try { this.addSample(sigar.getNetInterfaceStat(this.interfaceName)); } catch (SigarException e) { this.failCount++; if (this.failCount > 6) { // cancel ourselves this.cancel(); registeredInterfaces.remove(this.interfaceName); logger.warn("Error sampling network interface", e); logger.info("Stopping sampling of network IO for interface: " + this.interfaceName); } } } } }