Skip to content

Commit

Permalink
PORT-187 #58 Updated the auditor to support filtering on direction,
Browse files Browse the repository at this point in the history
message type and fom class type
  • Loading branch information
timpokorny committed Jan 7, 2015
1 parent af0176c commit 8a25b57
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 32 deletions.
16 changes: 16 additions & 0 deletions codebase/resources/dist/common/RTI.rid
Expand Up @@ -267,3 +267,19 @@
#
# portico.jgroups.auditor.enabled = false

# (4.13) JGroups Traffic Audit Filtering
# Federates can generate a lot of messages. Sometimes you really just want to zero in
# on a particular type of message, or messages for a particular FOM type. These filters
# let you do that. These filters work in combination. For example, consider the following:
# - action = sent
# - type = UpdateAttributes
# - fomtype = Lifeform, GroundVehicle
#
# Given this, only attribute updates for the FOM classes "Lifeform" and "GroundVehicle"
# that the local federate sends will be logged. Leaving a value empty, or using the
# keyword "all" will cause no filtering for that type to be applied.
#
# portico.jgroups.auditor.filter.direction =
# portico.jgroups.auditor.filter.message =
# portico.jgroups.auditor.filter.fomtype =

162 changes: 130 additions & 32 deletions codebase/src/java/portico/org/portico/bindings/jgroups/Auditor.java
Expand Up @@ -73,7 +73,12 @@ public class Auditor

// counters and metrics
private Map<String,MessageMetrics> metrics;


// filters to restrict what we log
private List<String> directionFilters;
private List<String> messageFilters;
private List<String> fomtypeFilters;

//----------------------------------------------------------
// CONSTRUCTORS
//----------------------------------------------------------
Expand All @@ -92,6 +97,11 @@ public Auditor()

// counters and metrics
this.metrics = new HashMap<String,MessageMetrics>();

// filters
this.directionFilters = new ArrayList<String>();
this.messageFilters = new ArrayList<String>();
this.fomtypeFilters = new ArrayList<String>();
}

//----------------------------------------------------------
Expand All @@ -110,6 +120,10 @@ public void sent( PorticoMessage message, int size )
if( !recording )
return;

// does this need to be filtered out?
if( shouldFilter(message,"sent") )
return;

// who are we sending this to?
String federateName = getFederateName( message.getTargetFederate() );
if( federateName.startsWith("unknown") )
Expand Down Expand Up @@ -159,6 +173,10 @@ public void received( PorticoMessage message, int size )
if( !recording )
return;

// does this need to be filtered out?
if( shouldFilter(message,"received") )
return;

// discard our own messages as they're not coming from the network
if( message.getSourceFederate() == lrc.getState().getFederateHandle() )
return;
Expand Down Expand Up @@ -304,38 +322,11 @@ private MessageMetrics getFomSpecificMetrics( PorticoMessage message )
if( parent == null )
return null;

// get the HLA object/interaction class that message is representing
if( message instanceof UpdateAttributes )
{
int objectHandle = ((UpdateAttributes)message).getObjectId();
OCInstance object = getObject( objectHandle );
if( object != null )
{
String className = getClassName( object.getRegisteredClassHandle() );
return parent.getOrAdd( className );
}
}
else if( message instanceof SendInteraction )
{
int classHandle = ((SendInteraction)message).getInteractionId();
String className = getFom().getInteractionClass(classHandle).getLocalName();
String className = getClassName( message );
if( className.equals("Unknown") == false )
return parent.getOrAdd( className );
}
else if( message instanceof DiscoverObject )
{
int classHandle = ((DiscoverObject)message).getClassHandle();
String className = getFom().getObjectClass(classHandle).getLocalName();
return parent.getOrAdd( className );
}
else if( message instanceof DeleteObject )
{
OCInstance object = getObject( ((DeleteObject)message).getObjectHandle() );
String className = getClassName( object.getRegisteredClassHandle() );
return parent.getOrAdd( className );
}

// if we get here, the message type is not one we're interested in, so just return null
return null;
else
return null;
}

/**
Expand Down Expand Up @@ -366,6 +357,101 @@ private final String getClassName( int classHandle )
{
return lrcState.getFOM().getObjectClass(classHandle).getLocalName();
}

/** Get appropriate object/interaction class name for this message type, or return "Unknown" */
private final String getClassName( PorticoMessage message )
{
if( message instanceof UpdateAttributes )
{
int objectHandle = ((UpdateAttributes)message).getObjectId();
OCInstance object = getObject( objectHandle );
if( object != null )
return getClassName( object.getRegisteredClassHandle() );
}
else if( message instanceof SendInteraction )
{
int classHandle = ((SendInteraction)message).getInteractionId();
return getFom().getInteractionClass(classHandle).getLocalName();
}
else if( message instanceof DiscoverObject )
{
int classHandle = ((DiscoverObject)message).getClassHandle();
return getFom().getObjectClass(classHandle).getLocalName();
}
else if( message instanceof DeleteObject )
{
OCInstance object = getObject( ((DeleteObject)message).getObjectHandle() );
return getClassName( object.getRegisteredClassHandle() );
}

return "Unknown";
}

////////////////////////////////////////////////////////////////////////////////
/////////////////////////////// Filter Methods ///////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* @return True if we should filter out this message - false otherwise
*/
private boolean shouldFilter( PorticoMessage message, String direction )
{
// The filter lists contain information about which types should be let through,
// so if something isn't in the list, it shouldn't get through. If the list is
// empty it means we have no filters, so let everything through

// check the direction
if( directionFilters.isEmpty() == false )
{
if( this.directionFilters.contains(direction) == false )
return true; // FILTER IT!
}

// check the message type
if( messageFilters.isEmpty() == false )
{
String type = message.getClass().getSimpleName();
if( this.messageFilters.contains(type) == false )
return true; // FILTER IT!
}

if( fomtypeFilters.isEmpty() == false )
{
String fomtype = getClassName(message);
if( this.fomtypeFilters.contains(fomtype) == false )
return true; // FILTER IT!
}

// let it through
return false;
}

/** Populate our filter list from configuration */
private void populateFilters()
{
this.directionFilters = JGroupsProperties.getAuditorDirectionFilters();
this.messageFilters = JGroupsProperties.getAuditorMessageFilters();
this.fomtypeFilters = JGroupsProperties.getAuditorFomtypeFilters();

// if "all" is set, clear the filter
if( shouldDisableFilter(directionFilters) )
directionFilters.clear();
if( shouldDisableFilter(messageFilters) )
messageFilters.clear();
if( shouldDisableFilter(fomtypeFilters) )
fomtypeFilters.clear();
}

/** If the list contains "all", true is returned indicating we shouldn't filter anything */
private boolean shouldDisableFilter( List<String> list )
{
for( String temp : list )
{
if( temp.equals("all") )
return true;
}

return false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////// Lifecycle Methods /////////////////////////////
Expand Down Expand Up @@ -399,10 +485,17 @@ public void startAuditing( String federationName, String federateName, LRC lrc )
turnLoggerOn();
this.recording = true;

// get our filters
populateFilters();

// log a startup message with some useful information
logger.info( "Starting Audit log for federate ["+federateName+"] in federation ["+
federationName );
logger.info( "Portico "+PorticoConstants.RTI_VERSION + " - JGroups "+Version.description );
logger.info( "Active Filters:" );
logger.info( " direction: "+directionFilters );
logger.info( " message: "+messageFilters );
logger.info( " fomtype: "+fomtypeFilters );
logger.info( "" );
}

Expand Down Expand Up @@ -454,6 +547,11 @@ public void stopAuditing()
// turn the logger off
this.logger.removeAppender( appender );
this.appender.close();

// clear the filter lists
this.directionFilters.clear();
this.messageFilters.clear();
this.fomtypeFilters.clear();
}

///////////////////////////////////////////////////////////////////////////////
Expand Down
Expand Up @@ -14,6 +14,10 @@
*/
package org.portico.bindings.jgroups;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

/**
* All configuration information is stored in system properties as keys. This class
* provides statics that can be used to identify the specific keys.
Expand Down Expand Up @@ -42,9 +46,15 @@ public class JGroupsProperties
that there is no existing co-ordinator and appointing ourselves to that lofty title */
public static String PROP_JGROUPS_GMS_TIMEOUT = "portico.jgroups.gms.jointimeout";

///// auditor settings
/** Whether or not the auditor is enabled */
public static String PROP_JGROUPS_AUDITOR_ENABLED = "portico.jgroups.auditor.enabled";

/** Auditor filtering settings */
public static String PROP_JGROUPS_AUDITOR_FILTER_DIR = "portico.jgroups.auditor.filter.direction";
public static String PROP_JGROUPS_AUDITOR_FILTER_MSG = "portico.jgroups.auditor.filter.message";
public static String PROP_JGROUPS_AUDITOR_FILTER_FOM = "portico.jgroups.auditor.filter.fomtype";

///// jgroups properties /////////////////////////////////////////////////////////////////
/** The amount of time (in milliseconds) to wait for a response to a request, defaults to 1000,
controllable through system property {@link #PROP_JGROUPS_TIMEOUT} */
Expand Down Expand Up @@ -92,5 +102,54 @@ public static final boolean isAuditorEnabled()
{
return Boolean.valueOf( System.getProperty(PROP_JGROUPS_AUDITOR_ENABLED,"false") );
}

/**
* @return A list of all the configured direction filters. If no configuration is provided,
* list will contain one entry - "all". These will be converted to lower case before
* being returned.
*/
public static List<String> getAuditorDirectionFilters()
{
String value = System.getProperty( PROP_JGROUPS_AUDITOR_FILTER_DIR,"all");
return explode( value, "," );
}

/**
* @return A list of all the configured message filters. If no configuration is provided,
* list will contain one entry - "all". These will be converted to lower case before
* being returned.
*/
public static List<String> getAuditorMessageFilters()
{
String value = System.getProperty( PROP_JGROUPS_AUDITOR_FILTER_MSG,"all");
return explode( value, "," );
}

/**
* @return A list of all the configured fomtype filters. If no configuration is provided,
* list will contain one entry - "all". These will be converted to lower case before
* being returned.
*/
public static List<String> getAuditorFomtypeFilters()
{
String value = System.getProperty( PROP_JGROUPS_AUDITOR_FILTER_FOM,"all");
return explode( value, "," );
}

private static List<String> explode( String string, String delimiter )
{
List<String> list = new ArrayList<String>();
StringTokenizer tokenizer = new StringTokenizer( string, delimiter );
while( tokenizer.hasMoreTokens() )
{
String temp = tokenizer.nextToken().trim();
if( temp.equals("") )
continue;
else
list.add( temp );
}

return list;
}

}

0 comments on commit 8a25b57

Please sign in to comment.