/*
* Copyright 2010 NCHOVY
*
* 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.krakenapps.sentry.windows.logger;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.krakenapps.log.api.AbstractLogger;
import org.krakenapps.log.api.Log;
import org.krakenapps.log.api.LoggerFactory;
import org.krakenapps.log.api.LoggerSpecification;
import org.krakenapps.log.api.SimpleLog;
import org.krakenapps.winapi.PerformanceCounter;
import org.slf4j.Logger;
public class NetworkUsageLogger extends AbstractLogger {
private final Logger logger = org.slf4j.LoggerFactory.getLogger(NetworkUsageLogger.class.getName());
private long[] lastRxErrors;
private long[] lastTxErrors;
private long[] lastRxDiscards;
private long[] lastTxDiscards;
private long lastCheckTime;
public NetworkUsageLogger(LoggerSpecification spec, LoggerFactory loggerFactory) {
super(spec.getName(), spec.getDescription(), loggerFactory);
List<String> instances = PerformanceCounter.getInstances("Network Interface");
int length = instances.size();
lastRxErrors = new long[length];
lastTxErrors = new long[length];
lastRxDiscards = new long[length];
lastTxDiscards = new long[length];
lastCheckTime = new Date().getTime();
}
@Override
protected void runOnce() {
try {
check();
} catch (InterruptedException e) {
}
}
private void check() throws InterruptedException {
List<String> instances = PerformanceCounter.getInstances("Network Interface");
Counters[] countersArray = new Counters[instances.size()];
int i = 0;
for (String instance : instances) {
countersArray[i] = new Counters();
countersArray[i].instanceName = instance;
i++;
}
try {
openAll(countersArray);
Thread.sleep(1000);
checkAll(countersArray);
} catch (Exception e) {
logger.warn("kraken windows sentry: check nic usage failed", e);
} finally {
closeAll(countersArray);
}
}
private PerformanceCounter open(String counter, String instanceName) {
return new PerformanceCounter("Network Interface", counter, instanceName);
}
private void closeAll(Counters[] countersArray) {
for (int i = 0; i < countersArray.length; i++) {
Counters c = countersArray[i];
close(c.bandwidth);
close(c.inBytesPerSec);
close(c.outBytesPerSec);
close(c.inUcastPktsPerSec);
close(c.outUcastPktsPerSec);
close(c.inNUcastPktsPerSec);
close(c.outNUcastPktsPerSec);
close(c.inErrors);
close(c.outErrors);
close(c.inDiscards);
close(c.outDiscards);
}
}
private void close(PerformanceCounter c) {
if (c != null)
try {
c.close();
} catch (Exception e) {
}
}
private void openAll(Counters[] countersArray) {
for (int i = 0; i < countersArray.length; i++) {
Counters c = countersArray[i];
String instanceName = c.instanceName;
String macAddress = getMacAddress(instanceName);
if (isFiltered(instanceName, macAddress))
continue;
c.bandwidth = open("Current Bandwidth", instanceName);
c.inBytesPerSec = open("Bytes Received/sec", instanceName);
c.outBytesPerSec = open("Bytes Sent/sec", instanceName);
c.inUcastPktsPerSec = open("Packets Received Unicast/sec", instanceName);
c.outUcastPktsPerSec = open("Packets Sent Unicast/sec", instanceName);
c.inNUcastPktsPerSec = open("Packets Received Non-Unicast/sec", instanceName);
c.outNUcastPktsPerSec = open("Packets Sent Non-Unicast/sec", instanceName);
c.inErrors = open("Packets Received Errors", instanceName);
c.outErrors = open("Packets Outbound Errors", instanceName);
c.inDiscards = open("Packets Received Discarded", instanceName);
c.outDiscards = open("Packets Outbound Discarded", instanceName);
// set baseline
c.inBytesPerSec.nextValue();
c.outBytesPerSec.nextValue();
c.inUcastPktsPerSec.nextValue();
c.outUcastPktsPerSec.nextValue();
c.inNUcastPktsPerSec.nextValue();
c.outNUcastPktsPerSec.nextValue();
}
}
public void checkAll(Counters[] countersArray) throws InterruptedException {
List<Log> logs = new ArrayList<Log>();
long now = new Date().getTime();
long interval = now - lastCheckTime;
int seconds = Math.round(interval / 1000);
lastCheckTime = now;
for (int i = 0; i < countersArray.length; i++) {
Counters c = countersArray[i];
String instanceName = c.instanceName;
String macAddress = getMacAddress(instanceName);
logger.trace("kraken windows sentry: nic counter instance [{}], mac [{}]", instanceName, macAddress);
if (isFiltered(instanceName, macAddress)) {
logger.trace("kraken windows sentry: filtered nic counter instance [{}], mac [{}]", instanceName,
macAddress);
continue;
}
// fetch all
long rxBytesDelta = Math.round(c.inBytesPerSec.nextValue() * seconds);
long txBytesDelta = Math.round(c.outBytesPerSec.nextValue() * seconds);
long rxUcastPktsDelta = Math.round(c.inUcastPktsPerSec.nextValue() * seconds);
long txUcastPktsDelta = Math.round(c.outUcastPktsPerSec.nextValue() * seconds);
long rxNUcastPktsDelta = Math.round(c.inNUcastPktsPerSec.nextValue() * seconds);
long txNUcastPktsDelta = Math.round(c.outNUcastPktsPerSec.nextValue() * seconds);
long rxErrors = (long) c.inErrors.nextValue();
long txErrors = (long) c.outErrors.nextValue();
long rxDiscards = (long) c.inDiscards.nextValue();
long txDiscards = (long) c.outDiscards.nextValue();
long rxErrorsDelta = rxErrors - lastRxErrors[i];
long txErrorsDelta = txErrors - lastTxErrors[i];
long rxDiscardsDelta = rxDiscards - lastRxDiscards[i];
long txDiscardsDelta = txDiscards - lastTxDiscards[i];
lastRxErrors[i] = rxErrors;
lastTxErrors[i] = txErrors;
lastRxDiscards[i] = rxDiscards;
lastTxDiscards[i] = txDiscards;
long bandwidth = (long) c.bandwidth.nextValue();
Map<String, Object> data = new HashMap<String, Object>();
data.put("scope", "device");
data.put("interval", interval);
data.put("index", i);
data.put("type", getType(instanceName));
data.put("description", instanceName);
data.put("mtu", getMtu(instanceName));
data.put("mac", macAddress);
data.put("bandwidth", bandwidth);
data.put("rx_bytes_delta", rxBytesDelta);
data.put("tx_bytes_delta", txBytesDelta);
data.put("rx_ucast_pkts_delta", rxUcastPktsDelta);
data.put("tx_ucast_pkts_delta", txUcastPktsDelta);
data.put("rx_nucast_pkts_delta", rxNUcastPktsDelta);
data.put("tx_nucast_pkts_delta", txNUcastPktsDelta);
data.put("rx_errors_delta", rxErrorsDelta);
data.put("tx_errors_delta", txErrorsDelta);
data.put("rx_discards_delta", rxDiscardsDelta);
data.put("tx_discards_delta", txDiscardsDelta);
long rxBps = rxBytesDelta * 8 / seconds;
long txBps = txBytesDelta * 8 / seconds;
long rxFps = (rxUcastPktsDelta + rxNUcastPktsDelta) * 8 / seconds;
long txFps = (txUcastPktsDelta + txNUcastPktsDelta) * 8 / seconds;
int rxUsage = 0;
int txUsage = 0;
if (bandwidth > 0) {
rxUsage = (int) (rxBps * 100 / bandwidth);
txUsage = (int) (txBps * 100 / bandwidth);
}
String rxBpsText = addUnit(rxBps, "bps");
String txBpsText = addUnit(txBps, "bps");
String rxFpsText = addUnit(rxFps, "fps");
String txFpsText = addUnit(txFps, "fps");
String msg = String.format("network usage: %s (%s), RX[%d%%, %s, %s], TX[%d%%, %s, %s]", instanceName,
macAddress, rxUsage, rxBpsText, rxFpsText, txUsage, txBpsText, txFpsText);
Log log = new SimpleLog(new Date(), getFullName(), "device", msg, data);
write(log);
logs.add(log);
}
Log max = findMax(logs);
String description;
String mac;
int networkUsage;
if (max != null) {
description = (String) max.getParams().get("description");
mac = (String) max.getParams().get("mac");
networkUsage = getNetworkUsage(max);
} else {
description = "-";
mac = "-";
networkUsage = 0;
}
Map<String, Object> m = new HashMap<String, Object>();
m.put("scope", "total");
m.put("max_usage", networkUsage);
m.put("description", description);
m.put("mac", mac);
String msg = String.format("network usage: max network usage [%s (%s) - %d%%]", description, mac, networkUsage);
Log log = new SimpleLog(new Date(), getFullName(), "total", msg, m);
write(log);
}
private Log findMax(List<Log> logs) {
Log selected = null;
int maxUsage = 0;
for (Log log : logs) {
int usage = getNetworkUsage(log);
if (usage >= maxUsage) {
selected = log;
maxUsage = usage;
}
}
return selected;
}
private int getNetworkUsage(Log log) {
int seconds = Math.round((Long) log.getParams().get("interval") / 1000);
long bandwidth = (Long) log.getParams().get("bandwidth");
long rxBytesDelta = (Long) log.getParams().get("rx_bytes_delta");
long txBytesDelta = (Long) log.getParams().get("tx_bytes_delta");
long rxBps = rxBytesDelta * 8 / seconds;
long txBps = txBytesDelta * 8 / seconds;
int rxUsage = (int) (rxBps * 100 / bandwidth);
int txUsage = (int) (txBps * 100 / bandwidth);
int usage = Math.max(rxUsage, txUsage);
return usage;
}
private String addUnit(long value, String postfix) {
String level = "";
if (value > 1000) {
value = value / 1000;
level = "K";
if (value > 1000) {
value = value / 1000;
level = "M";
if (value > 1000) {
value = value / 1000;
level = "G";
}
}
}
return value + level + postfix;
}
private NetworkInterface findNetworkInterface(String name) {
try {
Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces();
while (nics.hasMoreElements()) {
NetworkInterface ni = nics.nextElement();
if (match(ni.getDisplayName(), name))
return ni;
}
return null;
} catch (Exception e) {
return null;
}
}
private boolean match(String lhs, String rhs) {
lhs = lhs.replaceAll("[#()-/_\\[\\]]", " ");
rhs = rhs.replaceAll("[#()-/_\\[\\]]", " ");
String[] lTokens = lhs.split(" ");
String[] rTokens = rhs.split(" ");
if (lTokens.length != rTokens.length)
return false;
for (int i = 0; i < lTokens.length; i++)
if (!lTokens[i].equals(rTokens[i]))
return false;
return true;
}
private Integer getType(String name) {
NetworkInterface ni = findNetworkInterface(name);
if (ni == null)
return null;
if (ni.getName().startsWith("eth"))
return 6;
return null;
}
private String getMacAddress(String name) {
try {
NetworkInterface ni = findNetworkInterface(name);
if (ni == null)
return null;
byte[] b = ni.getHardwareAddress();
if (b == null || b.length != 6)
return null;
return String.format("%02x:%02x:%02x:%02x:%02x:%02x", b[0], b[1], b[2], b[3], b[4], b[5]);
} catch (SocketException e) {
}
return null;
}
private Integer getMtu(String name) {
try {
NetworkInterface ni = findNetworkInterface(name);
if (ni == null)
return 0;
return ni.getMTU();
} catch (SocketException e) {
}
return null;
}
private static boolean isFiltered(String name, String macAddress) {
if (macAddress == null)
return true;
if (name.startsWith("isatap."))
return true;
if (name.equals("Built-in Infrared Device"))
return true;
return false;
}
private static class Counters {
String instanceName;
PerformanceCounter bandwidth;
PerformanceCounter inBytesPerSec;
PerformanceCounter outBytesPerSec;
PerformanceCounter inUcastPktsPerSec;
PerformanceCounter outUcastPktsPerSec;
PerformanceCounter inNUcastPktsPerSec;
PerformanceCounter outNUcastPktsPerSec;
PerformanceCounter inErrors;
PerformanceCounter outErrors;
PerformanceCounter inDiscards;
PerformanceCounter outDiscards;
}
}