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) {
List<T> objects = new ArrayList<>();
Set<File> pythonModuleDirs = new HashSet<>();
PythonInterpreter interpreter = new PythonInterpreter();
// add python modules from 'autospy/build/cluster/InternalPythonModules' folder
// 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
String className = line.substring(6, line.indexOf("("));
try {
objects.add( createObjectFromScript(script, className, interfaceClass));
objects.add( createObjectFromScript(interpreter, script, className, interfaceClass));
} catch (Exception ex) {
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().
@ -112,23 +113,23 @@ public final class JythonModuleLoader {
return objects;
}
private static <T> T createObjectFromScript(File script, String className, Class<T> interfaceClass) {
// Make a "fresh" interpreter every time to avoid name collisions, etc.
PythonInterpreter interpreter = new PythonInterpreter();
private static <T> T createObjectFromScript(PythonInterpreter interpreter, File script, String className, Class<T> interfaceClass) {
// Add the directory where the Python script resides to the Python
// module search path to allow the script to use other scripts bundled
// with it.
interpreter.exec("import sys"); //NON-NLS
String path = Matcher.quoteReplacement(script.getParent());
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.
interpreter.exec("from " + script.getName().replaceAll(".py", "") + " import " + className);
interpreter.exec("from " + moduleName + " import " + className);
interpreter.exec("obj = " + className + "()"); //NON-NLS
T obj = interpreter.get("obj", interfaceClass); //NON-NLS
// 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
import jarray
import inspect
from java.lang import System
from java.util.logging import Level
from org.sleuthkit.datamodel import SleuthkitCase
@ -58,11 +59,11 @@ from org.sleuthkit.autopsy.casemodule.services import FileManager
class SampleJythonDataSourceIngestModuleFactory(IngestModuleFactoryAdapter):
# 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):
return self.moduleName
# TODO: Give it a description
def getModuleDescription(self):
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.
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):
self.context = None
@ -93,8 +99,7 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
self.context = context
# Throw an IngestModule.IngestModuleException exception if there was a problem setting up
# raise IngestModuleException(IngestModule(), "Oh No!")
# Where the analysis is done.
# 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
@ -104,8 +109,6 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
def process(self, dataSource, progressBar):
if self.context.isJobCancelled():
return IngestModule.ProcessResult.OK
logger = Logger.getLogger(SampleJythonDataSourceIngestModuleFactory.moduleName)
# we don't know how much work there is yet
progressBar.switchToIndeterminate()
@ -115,13 +118,13 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
services = Services(sleuthkitCase)
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"
# in the name and then count and read them
files = fileManager.findFiles(dataSource, "%test%")
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)
fileCount = 0;
for file in files:
@ -130,7 +133,7 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
if self.context.isJobCancelled():
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
# 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")
art.addAttribute(att)
# To further the example, this code will read the contents of the file and count the number of bytes
inputStream = ReadContentInputStream(file)
buffer = jarray.zeros(1024, "b")
@ -159,4 +162,4 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
"Sample Jython Data Source Ingest Module", "Found %d files" % fileCount)
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
import jarray
import inspect
from java.lang import System
from java.util.logging import Level
from org.sleuthkit.datamodel import SleuthkitCase
@ -84,12 +85,16 @@ class SampleJythonFileIngestModuleFactory(IngestModuleFactoryAdapter):
# Looks at the attributes of the passed in file.
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
# '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
# TODO: Add any setup code that you need here.
def startUp(self, context):
self.logger = Logger.getLogger(SampleJythonFileIngestModuleFactory.moduleName)
self.filesFound = 0
# 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
# TODO: Add your analysis code in here.
def process(self, file):
# 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)):
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.
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
# 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:
attributeList = artifact.getAttributes();
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
inputStream = ReadContentInputStream(file)
@ -143,4 +147,4 @@ class SampleJythonFileIngestModule(FileIngestModule):
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)
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 inspect
from java.lang import System
from java.util.logging import Level
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.
moduleName = "Sample Data Source Module with UI"
def getModuleDisplayName(self):
return self.moduleName
# TODO: Give it a description
def getModuleDescription(self):
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.
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
def __init__(self, settings):
self.local_settings = settings
@ -117,14 +123,12 @@ class SampleFileIngestModuleWithUI(FileIngestModule):
# Where any setup and configuration is done
# TODO: Add any setup code that you need here.
def startUp(self, context):
self.logger = Logger.getLogger(SampleFileIngestModuleWithUIFactory.moduleName)
# As an example, determine if user configured a flag in UI
if self.local_settings.getFlag():
self.logger.logp(Level.INFO, SampleFileIngestModuleWithUI.__name__, "startUp", "flag is set")
self.log(Level.INFO, "flag is set")
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
# raise IngestModuleException(IngestModule(), "Oh No!")
pass
@ -171,7 +175,7 @@ class SampleFileIngestModuleWithUISettingsPanel(IngestModuleIngestJobSettingsPan
# is present, it creates a read-only 'settings' property. This auto-
# generated read-only property overshadows the instance-variable -
# 'settings'
# We get passed in a previous version of the settings so that we can
# prepopulate the UI
# TODO: Update this for your UI
@ -179,7 +183,7 @@ class SampleFileIngestModuleWithUISettingsPanel(IngestModuleIngestJobSettingsPan
self.local_settings = settings
self.initComponents()
self.customizeComponents()
# TODO: Update this for your UI
def checkBoxEvent(self, event):
if self.checkbox.isSelected():
@ -201,4 +205,3 @@ class SampleFileIngestModuleWithUISettingsPanel(IngestModuleIngestJobSettingsPan
def getSettings(self):
return self.local_settings