Merge pull request #1315 from sidheshenator/python_module_reload_and_logging

Python module reload and logging
This commit is contained in:
Brian Carrier 2015-06-05 13:16:16 -04:00
commit fd70adfc55
4 changed files with 47 additions and 36 deletions

View File

@ -70,6 +70,7 @@ public final class JythonModuleLoader {
private static <T> List<T> getInterfaceImplementations(LineFilter filter, Class<T> interfaceClass) { private static <T> List<T> getInterfaceImplementations(LineFilter filter, Class<T> interfaceClass) {
List<T> objects = new ArrayList<>(); List<T> objects = new ArrayList<>();
Set<File> pythonModuleDirs = new HashSet<>(); Set<File> pythonModuleDirs = new HashSet<>();
PythonInterpreter interpreter = new PythonInterpreter();
// add python modules from 'autospy/build/cluster/InternalPythonModules' folder // add python modules from 'autospy/build/cluster/InternalPythonModules' folder
// which are copied from 'autopsy/*/release/InternalPythonModules' folders. // which are copied from 'autopsy/*/release/InternalPythonModules' folders.
@ -90,7 +91,7 @@ public final class JythonModuleLoader {
if (line.startsWith("class ") && filter.accept(line)) { //NON-NLS if (line.startsWith("class ") && filter.accept(line)) { //NON-NLS
String className = line.substring(6, line.indexOf("(")); String className = line.substring(6, line.indexOf("("));
try { try {
objects.add( createObjectFromScript(script, className, interfaceClass)); objects.add( createObjectFromScript(interpreter, script, className, interfaceClass));
} catch (Exception ex) { } catch (Exception ex) {
logger.log(Level.SEVERE, String.format("Failed to load %s from %s", className, script.getAbsolutePath()), ex); //NON-NLS logger.log(Level.SEVERE, String.format("Failed to load %s from %s", className, script.getAbsolutePath()), ex); //NON-NLS
// NOTE: using ex.toString() because the current version is always returning null for ex.getMessage(). // NOTE: using ex.toString() because the current version is always returning null for ex.getMessage().
@ -112,23 +113,23 @@ public final class JythonModuleLoader {
return objects; return objects;
} }
private static <T> T createObjectFromScript(File script, String className, Class<T> interfaceClass) { private static <T> T createObjectFromScript(PythonInterpreter interpreter, File script, String className, Class<T> interfaceClass) {
// Make a "fresh" interpreter every time to avoid name collisions, etc.
PythonInterpreter interpreter = new PythonInterpreter();
// Add the directory where the Python script resides to the Python // Add the directory where the Python script resides to the Python
// module search path to allow the script to use other scripts bundled // module search path to allow the script to use other scripts bundled
// with it. // with it.
interpreter.exec("import sys"); //NON-NLS interpreter.exec("import sys"); //NON-NLS
String path = Matcher.quoteReplacement(script.getParent()); String path = Matcher.quoteReplacement(script.getParent());
interpreter.exec("sys.path.append('" + path + "')"); //NON-NLS interpreter.exec("sys.path.append('" + path + "')"); //NON-NLS
String moduleName = script.getName().replaceAll(".py", ""); //NON-NLS
// reload the module so that the changes made to it can be loaded.
interpreter.exec("import " + moduleName); //NON-NLS
interpreter.exec("reload(" + moduleName + ")"); //NON-NLS
// Execute the script and create an instance of the desired class.
interpreter.execfile(script.getAbsolutePath());
// Importing the appropriate class from the Py Script which contains multiple classes. // Importing the appropriate class from the Py Script which contains multiple classes.
interpreter.exec("from " + script.getName().replaceAll(".py", "") + " import " + className); interpreter.exec("from " + moduleName + " import " + className);
interpreter.exec("obj = " + className + "()"); //NON-NLS interpreter.exec("obj = " + className + "()"); //NON-NLS
T obj = interpreter.get("obj", interfaceClass); //NON-NLS T obj = interpreter.get("obj", interfaceClass); //NON-NLS
// Remove the directory where the Python script resides from the Python // Remove the directory where the Python script resides from the Python

View File

@ -32,6 +32,7 @@
# See http://sleuthkit.org/autopsy/docs/api-docs/3.1/index.html for documentation # See http://sleuthkit.org/autopsy/docs/api-docs/3.1/index.html for documentation
import jarray import jarray
import inspect
from java.lang import System from java.lang import System
from java.util.logging import Level from java.util.logging import Level
from org.sleuthkit.datamodel import SleuthkitCase from org.sleuthkit.datamodel import SleuthkitCase
@ -58,11 +59,11 @@ from org.sleuthkit.autopsy.casemodule.services import FileManager
class SampleJythonDataSourceIngestModuleFactory(IngestModuleFactoryAdapter): class SampleJythonDataSourceIngestModuleFactory(IngestModuleFactoryAdapter):
# TODO: give it a unique name. Will be shown in module list, logs, etc. # TODO: give it a unique name. Will be shown in module list, logs, etc.
moduleName = "Sample Data Source Module" moduleName = "Sample Data Source Module"
def getModuleDisplayName(self): def getModuleDisplayName(self):
return self.moduleName return self.moduleName
# TODO: Give it a description # TODO: Give it a description
def getModuleDescription(self): def getModuleDescription(self):
return "Sample module that does X, Y, and Z." return "Sample module that does X, Y, and Z."
@ -82,6 +83,11 @@ class SampleJythonDataSourceIngestModuleFactory(IngestModuleFactoryAdapter):
# TODO: Rename this to something more specific. Could just remove "Factory" from above name. # TODO: Rename this to something more specific. Could just remove "Factory" from above name.
class SampleJythonDataSourceIngestModule(DataSourceIngestModule): class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
_logger = Logger.getLogger(SampleJythonDataSourceIngestModuleFactory.moduleName)
def log(self, level, msg):
self._logger.logp(level, self.__class__.__name__, inspect.stack()[1][3], msg)
def __init__(self): def __init__(self):
self.context = None self.context = None
@ -93,8 +99,7 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
self.context = context self.context = context
# Throw an IngestModule.IngestModuleException exception if there was a problem setting up # Throw an IngestModule.IngestModuleException exception if there was a problem setting up
# raise IngestModuleException(IngestModule(), "Oh No!") # raise IngestModuleException(IngestModule(), "Oh No!")
# Where the analysis is done. # Where the analysis is done.
# The 'dataSource' object being passed in is of type org.sleuthkit.datamodel.Content. # The 'dataSource' object being passed in is of type org.sleuthkit.datamodel.Content.
# See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/interfaceorg_1_1sleuthkit_1_1datamodel_1_1_content.html # See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/interfaceorg_1_1sleuthkit_1_1datamodel_1_1_content.html
@ -104,8 +109,6 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
def process(self, dataSource, progressBar): def process(self, dataSource, progressBar):
if self.context.isJobCancelled(): if self.context.isJobCancelled():
return IngestModule.ProcessResult.OK return IngestModule.ProcessResult.OK
logger = Logger.getLogger(SampleJythonDataSourceIngestModuleFactory.moduleName)
# we don't know how much work there is yet # we don't know how much work there is yet
progressBar.switchToIndeterminate() progressBar.switchToIndeterminate()
@ -115,13 +118,13 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
services = Services(sleuthkitCase) services = Services(sleuthkitCase)
fileManager = services.getFileManager() fileManager = services.getFileManager()
# For our example, we will use FileManager to get all # For our example, we will use FileManager to get all
# files with the word "test" # files with the word "test"
# in the name and then count and read them # in the name and then count and read them
files = fileManager.findFiles(dataSource, "%test%") files = fileManager.findFiles(dataSource, "%test%")
numFiles = len(files) numFiles = len(files)
logger.logp(Level.INFO, SampleJythonDataSourceIngestModule.__name__, "process", "found " + str(numFiles) + " files") self.log(Level.INFO, "found " + str(numFiles) + " files")
progressBar.switchToDeterminate(numFiles) progressBar.switchToDeterminate(numFiles)
fileCount = 0; fileCount = 0;
for file in files: for file in files:
@ -130,7 +133,7 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
if self.context.isJobCancelled(): if self.context.isJobCancelled():
return IngestModule.ProcessResult.OK return IngestModule.ProcessResult.OK
logger.logp(Level.INFO, SampleJythonDataSourceIngestModule.__name__, "process", "Processing file: " + file.getName()) self.log(Level.INFO, "Processing file: " + file.getName())
fileCount += 1 fileCount += 1
# Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of # Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of
@ -139,7 +142,7 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
att = BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), SampleJythonDataSourceIngestModuleFactory.moduleName, "Test file") att = BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), SampleJythonDataSourceIngestModuleFactory.moduleName, "Test file")
art.addAttribute(att) art.addAttribute(att)
# To further the example, this code will read the contents of the file and count the number of bytes # To further the example, this code will read the contents of the file and count the number of bytes
inputStream = ReadContentInputStream(file) inputStream = ReadContentInputStream(file)
buffer = jarray.zeros(1024, "b") buffer = jarray.zeros(1024, "b")
@ -159,4 +162,4 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
"Sample Jython Data Source Ingest Module", "Found %d files" % fileCount) "Sample Jython Data Source Ingest Module", "Found %d files" % fileCount)
IngestServices.getInstance().postMessage(message) IngestServices.getInstance().postMessage(message)
return IngestModule.ProcessResult.OK; return IngestModule.ProcessResult.OK;

View File

@ -32,6 +32,7 @@
# See http://sleuthkit.org/autopsy/docs/api-docs/3.1/index.html for documentation # See http://sleuthkit.org/autopsy/docs/api-docs/3.1/index.html for documentation
import jarray import jarray
import inspect
from java.lang import System from java.lang import System
from java.util.logging import Level from java.util.logging import Level
from org.sleuthkit.datamodel import SleuthkitCase from org.sleuthkit.datamodel import SleuthkitCase
@ -84,12 +85,16 @@ class SampleJythonFileIngestModuleFactory(IngestModuleFactoryAdapter):
# Looks at the attributes of the passed in file. # Looks at the attributes of the passed in file.
class SampleJythonFileIngestModule(FileIngestModule): class SampleJythonFileIngestModule(FileIngestModule):
_logger = Logger.getLogger(SampleJythonFileIngestModuleFactory.moduleName)
def log(self, level, msg):
self._logger.logp(level, self.__class__.__name__, inspect.stack()[1][3], msg)
# Where any setup and configuration is done # Where any setup and configuration is done
# 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext. # 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext.
# See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html # See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html
# TODO: Add any setup code that you need here. # TODO: Add any setup code that you need here.
def startUp(self, context): def startUp(self, context):
self.logger = Logger.getLogger(SampleJythonFileIngestModuleFactory.moduleName)
self.filesFound = 0 self.filesFound = 0
# Throw an IngestModule.IngestModuleException exception if there was a problem setting up # Throw an IngestModule.IngestModuleException exception if there was a problem setting up
@ -101,7 +106,6 @@ class SampleJythonFileIngestModule(FileIngestModule):
# See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/classorg_1_1sleuthkit_1_1datamodel_1_1_abstract_file.html # See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/classorg_1_1sleuthkit_1_1datamodel_1_1_abstract_file.html
# TODO: Add your analysis code in here. # TODO: Add your analysis code in here.
def process(self, file): def process(self, file):
# Skip non-files # Skip non-files
if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) or (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) or (file.isFile() == False)): if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) or (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) or (file.isFile() == False)):
return IngestModule.ProcessResult.OK return IngestModule.ProcessResult.OK
@ -109,7 +113,7 @@ class SampleJythonFileIngestModule(FileIngestModule):
# For an example, we will flag files with .txt in the name and make a blackboard artifact. # For an example, we will flag files with .txt in the name and make a blackboard artifact.
if file.getName().find(".txt") != -1: if file.getName().find(".txt") != -1:
self.logger.logp(Level.INFO, SampleJythonFileIngestModule.__name__, "process", "Found a text file: " + file.getName()) self.log(Level.INFO, "Found a text file: " + file.getName())
self.filesFound+=1 self.filesFound+=1
# Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of # Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of
@ -125,7 +129,7 @@ class SampleJythonFileIngestModule(FileIngestModule):
for artifact in artifactList: for artifact in artifactList:
attributeList = artifact.getAttributes(); attributeList = artifact.getAttributes();
for attrib in attributeList: for attrib in attributeList:
self.logger.logp(Level.INFO, SampleJythonFileIngestModule.__name__, "process", attrib.toString()) self.log(Level.INFO, attrib.toString())
# To further the example, this code will read the contents of the file and count the number of bytes # To further the example, this code will read the contents of the file and count the number of bytes
inputStream = ReadContentInputStream(file) inputStream = ReadContentInputStream(file)
@ -143,4 +147,4 @@ class SampleJythonFileIngestModule(FileIngestModule):
def shutDown(self): def shutDown(self):
# As a final part of this example, we'll send a message to the ingest inbox with the number of files found (in this thread) # As a final part of this example, we'll send a message to the ingest inbox with the number of files found (in this thread)
message = IngestMessage.createMessage(IngestMessage.MessageType.DATA, SampleJythonFileIngestModuleFactory.moduleName, str(self.filesFound) + " files found") message = IngestMessage.createMessage(IngestMessage.MessageType.DATA, SampleJythonFileIngestModuleFactory.moduleName, str(self.filesFound) + " files found")
ingestServices = IngestServices.getInstance().postMessage(message) ingestServices = IngestServices.getInstance().postMessage(message)

View File

@ -39,6 +39,7 @@
import jarray import jarray
import inspect
from java.lang import System from java.lang import System
from java.util.logging import Level from java.util.logging import Level
from javax.swing import JCheckBox from javax.swing import JCheckBox
@ -68,10 +69,10 @@ class SampleFileIngestModuleWithUIFactory(IngestModuleFactoryAdapter):
# TODO: give it a unique name. Will be shown in module list, logs, etc. # TODO: give it a unique name. Will be shown in module list, logs, etc.
moduleName = "Sample Data Source Module with UI" moduleName = "Sample Data Source Module with UI"
def getModuleDisplayName(self): def getModuleDisplayName(self):
return self.moduleName return self.moduleName
# TODO: Give it a description # TODO: Give it a description
def getModuleDescription(self): def getModuleDescription(self):
return "Sample module that does X, Y, and Z." return "Sample module that does X, Y, and Z."
@ -109,6 +110,11 @@ class SampleFileIngestModuleWithUIFactory(IngestModuleFactoryAdapter):
# Looks at the attributes of the passed in file. # Looks at the attributes of the passed in file.
class SampleFileIngestModuleWithUI(FileIngestModule): class SampleFileIngestModuleWithUI(FileIngestModule):
_logger = Logger.getLogger(SampleFileIngestModuleWithUIFactory.moduleName)
def log(self, level, msg):
self._logger.logp(level, self.__class__.__name__, inspect.stack()[1][3], msg)
# Autopsy will pass in the settings from the UI panel # Autopsy will pass in the settings from the UI panel
def __init__(self, settings): def __init__(self, settings):
self.local_settings = settings self.local_settings = settings
@ -117,14 +123,12 @@ class SampleFileIngestModuleWithUI(FileIngestModule):
# Where any setup and configuration is done # Where any setup and configuration is done
# TODO: Add any setup code that you need here. # TODO: Add any setup code that you need here.
def startUp(self, context): def startUp(self, context):
self.logger = Logger.getLogger(SampleFileIngestModuleWithUIFactory.moduleName)
# As an example, determine if user configured a flag in UI # As an example, determine if user configured a flag in UI
if self.local_settings.getFlag(): if self.local_settings.getFlag():
self.logger.logp(Level.INFO, SampleFileIngestModuleWithUI.__name__, "startUp", "flag is set") self.log(Level.INFO, "flag is set")
else: else:
self.logger.logp(Level.INFO, SampleFileIngestModuleWithUI.__name__, "startUp", "flag is not set") self.log(Level.INFO, "flag is not set")
# Throw an IngestModule.IngestModuleException exception if there was a problem setting up # Throw an IngestModule.IngestModuleException exception if there was a problem setting up
# raise IngestModuleException(IngestModule(), "Oh No!") # raise IngestModuleException(IngestModule(), "Oh No!")
pass pass
@ -171,7 +175,7 @@ class SampleFileIngestModuleWithUISettingsPanel(IngestModuleIngestJobSettingsPan
# is present, it creates a read-only 'settings' property. This auto- # is present, it creates a read-only 'settings' property. This auto-
# generated read-only property overshadows the instance-variable - # generated read-only property overshadows the instance-variable -
# 'settings' # 'settings'
# We get passed in a previous version of the settings so that we can # We get passed in a previous version of the settings so that we can
# prepopulate the UI # prepopulate the UI
# TODO: Update this for your UI # TODO: Update this for your UI
@ -179,7 +183,7 @@ class SampleFileIngestModuleWithUISettingsPanel(IngestModuleIngestJobSettingsPan
self.local_settings = settings self.local_settings = settings
self.initComponents() self.initComponents()
self.customizeComponents() self.customizeComponents()
# TODO: Update this for your UI # TODO: Update this for your UI
def checkBoxEvent(self, event): def checkBoxEvent(self, event):
if self.checkbox.isSelected(): if self.checkbox.isSelected():
@ -201,4 +205,3 @@ class SampleFileIngestModuleWithUISettingsPanel(IngestModuleIngestJobSettingsPan
def getSettings(self): def getSettings(self):
return self.local_settings return self.local_settings