/*
* Sun Public License
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the SLAMD Distributed Load Generation Engine.
* The Initial Developer of the Original Code is Neil A. Wilson.
* Portions created by Neil A. Wilson are Copyright (C) 2004-2010.
* Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): Neil A. Wilson, Geoffrey Said
*/
package com.slamd.resourcemonitor;
import java.util.*;
import com.slamd.common.*;
import com.slamd.job.*;
import com.slamd.stat.*;
import com.slamd.resourcemonitor.netstat.NetStatCollector;
import com.slamd.resourcemonitor.netstat.InterfaceStatistics;
import com.slamd.resourcemonitor.netstat.SingleInterfaceStatistics;
import com.slamd.resourcemonitor.netstat.AggregateInterfaceStatistics;
/**
* This class defines a SLAMD resource monitor that uses command-line utilities
* to monitor network traffic volumes.
*
*
* @author Neil A. Wilson
*/
public class NetStatResourceMonitor
extends ResourceMonitor
{
/**
* The display name of the stat tracker used to keep track of the number of
* bytes received.
*/
public static final String STAT_TRACKER_BYTES_RECEIVED =
"Network Bytes Received";
/**
* The display name of the stat tracker used to keep track of the number of
* bytes transmitted.
*/
public static final String STAT_TRACKER_BYTES_TRANSMITTED =
"Network Bytes Transmitted";
/**
* The configuration property name used to specify the list of monitored
* network interfaces.
*/
public static final String PROPERTY_MONITOR_INTERFACES =
"monitor_interfaces";
/**
* The configuration property name used to specify if the network interface
* statistics should be aggregated.
*/
public static final String PROPERTY_MONITOR_AGGREGATE_STATISTICS =
"monitor_aggregate_statistics";
// A flag that indicates whether we will try to report real-time statistics.
boolean enableRealTimeStats;
// The stat trackers used to keep track of the amount of traffic transferred.
private InterfaceStatistics[] interfaceStatistics;
// The frequency that we should use when collecting statistics.
int collectionInterval;
// Names of the monitored interfaces.
private String[] monitoredInterfaces;
// Flag to indicate if the network interface statistics are aggregated.
private boolean aggregateStats;
/**
* Performs any initialization specific to this resource monitor.
*
* @throws SLAMDException If a problem occurs while performing the
* initialization.
*/
@Override()
public void initializeMonitor()
throws SLAMDException
{
String monitorInterfacesProp = getProperty(PROPERTY_MONITOR_INTERFACES);
if (monitorInterfacesProp != null && monitorInterfacesProp.length() > 0)
{
monitoredInterfaces =
monitorInterfacesProp.replaceAll("[ \t]*", "").split(",");
}
aggregateStats = getProperty(PROPERTY_MONITOR_AGGREGATE_STATISTICS, false);
if ((monitoredInterfaces == null) || (monitoredInterfaces.length == 0))
{
// We will always aggregate stats if no specific interfaces are defined.
monitoredInterfaces = null;
aggregateStats = true;
}
}
/**
* Indicates whether the current client system is supported for this resource
* monitor.
*
* @return <CODE>true</CODE> if the current client system is supported for
* this resource monitor, or <CODE>false</CODE> if not.
*/
@Override()
public boolean clientSupported()
{
int osType = getClientOS();
switch (osType)
{
case OS_TYPE_SOLARIS:
case OS_TYPE_LINUX:
case OS_TYPE_HPUX:
case OS_TYPE_AIX:
case OS_TYPE_WINDOWS:
return true;
default:
return false;
}
}
/**
* Creates a new instance of this resource monitor thread. Note that the
* <CODE>initialize()</CODE> method should have been called on the new
* instance before it is returned.
*
* @return A new instance of this resource monitor thread.
*
* @throws SLAMDException If a problem occurs while creating or initializing
* the resource monitor.
*/
@Override()
public ResourceMonitor newInstance()
throws SLAMDException
{
NetStatResourceMonitor monitor = new NetStatResourceMonitor();
monitor.initialize(getMonitorClient(), getMonitorProperties());
return monitor;
}
/**
* Initializes the stat trackers maintained by this resource monitor.
*
* @param clientID The client ID to use for the stubs.
* @param threadID The thread ID to use for the stubs.
* @param collectionInterval The collection interval to use for the stubs.
*/
@Override()
public void initializeStatistics(String clientID, String threadID,
int collectionInterval)
{
this.collectionInterval = collectionInterval;
if (aggregateStats)
{
interfaceStatistics = new InterfaceStatistics[1];
interfaceStatistics[0]=
new AggregateInterfaceStatistics(
new LongValueTracker(clientID, threadID, clientID + ' ' +
STAT_TRACKER_BYTES_RECEIVED, collectionInterval
),
new LongValueTracker(clientID, threadID, clientID + ' ' +
STAT_TRACKER_BYTES_TRANSMITTED, collectionInterval
)
);
}
else
{
interfaceStatistics = new InterfaceStatistics[monitoredInterfaces.length];
int i = 0;
for (String nic : monitoredInterfaces)
{
interfaceStatistics[i++] =
new SingleInterfaceStatistics(
nic,
new LongValueTracker(clientID, threadID, clientID + ' ' +
' ' + nic + ' ' + STAT_TRACKER_BYTES_RECEIVED,
collectionInterval
),
new LongValueTracker(clientID, threadID, clientID + ' ' +
' ' + nic + ' ' + STAT_TRACKER_BYTES_TRANSMITTED,
collectionInterval
)
);
}
}
}
/**
* Retrieves the name to use for this resource monitor.
*
* @return The name to use for this resource monitor.
*/
@Override()
public String getMonitorName()
{
return "NetStat";
}
/**
* Retrieves the statistical data collected by this resource monitor.
*
* @return The statistical data collected by this resource monitor.
*/
@Override()
public StatTracker[] getResourceStatistics()
{
// Sort the trackers by their display name
final List<LongValueTracker> trackers = new ArrayList<LongValueTracker>();
for (InterfaceStatistics stats : this.interfaceStatistics)
{
trackers.add(stats.getReceivedBytes());
trackers.add(stats.getSentBytes());
}
return trackers.toArray(new StatTracker[trackers.size()]);
}
/**
* Performs the work of actually collecting resource statistics. This method
* should periodically call the <CODE>shouldStop()</CODE> method to determine
* whether to stop collecting statistics.
*
* @return A value that indicates the status of the monitor when it
* completed.
*/
@Override()
public int runMonitor()
{
// Determine whether to enable real-time statistics collection. If so, then
// we'll actually capture the data twice -- once for real-time reporting and
// then again for what we actually report back to the server.
ResourceMonitorJob monitorJob = getMonitorJob();
if ((monitorJob != null) && (monitorJob.enableRealTimeStats()))
{
String jobID = monitorJob.getJobID();
RealTimeStatReporter statReporter = monitorJob.getStatReporter();
enableRealTimeStats = true;
for (InterfaceStatistics stats : interfaceStatistics)
{
stats.enableRealTimeStats();
final LongValueTracker sentBytesTracker = stats.getSentBytes();
sentBytesTracker.startTracker();
sentBytesTracker.enableRealTimeStats(statReporter, jobID);
final LongValueTracker receivedBytesTracker = stats.getReceivedBytes();
receivedBytesTracker.startTracker();
receivedBytesTracker.enableRealTimeStats(statReporter, jobID);
}
}
if (!clientSupported())
{
logMessage("Unsupported client OS (" + getClientOS() + ')');
return Constants.JOB_STATE_STOPPED_DUE_TO_ERROR;
}
final NetStatCollector.Builder builder = new NetStatCollector.Builder();
builder.setAggregateStatistics(this.aggregateStats);
builder.setCollectionIntervalSecs(this.collectionInterval);
builder.setInterfaceStatistics(this.interfaceStatistics);
builder.setMonitorAllInterfaces(this.monitoredInterfaces == null);
builder.setInterfaceNames(this.monitoredInterfaces);
builder.setMonitor(this);
builder.setOSType(getClientOS());
final NetStatCollector collector = builder.build();
try
{
collector.initialize();
}
catch (Exception e)
{
logMessage(
"Failed to initialize network statistics collection, reason: "
+ e.getLocalizedMessage()
);
return Constants.JOB_STATE_STOPPED_DUE_TO_ERROR;
}
while (! shouldStop())
{
long stopSleepTime = System.currentTimeMillis() +
(1000 * collectionInterval);
try
{
collector.collect();
}
catch (Exception e)
{
writeVerbose("Caught an exception: " + e);
writeVerbose(JobClass.stackTraceToString(e));
}
long sleepTime = stopSleepTime - System.currentTimeMillis();
if (sleepTime > 0)
{
try
{
Thread.sleep(sleepTime);
}
catch (Exception e)
{
// ignore
}
}
}
// If we were capturing real-time statistics, then stop so that we can
// replace the data with what will actually be reported.
if (enableRealTimeStats)
{
for (InterfaceStatistics stats : interfaceStatistics)
{
final LongValueTracker sentBytesTracker = stats.getSentBytes();
sentBytesTracker.stopTracker();
final LongValueTracker receivedBytesTracker = stats.getReceivedBytes();
receivedBytesTracker.stopTracker();
}
}
collector.finalizeCollection();
return Constants.JOB_STATE_COMPLETED_SUCCESSFULLY;
}
}