From mboxrd@z Thu Jan 1 00:00:00 1970 From: Andrew Price Date: Wed, 19 Dec 2012 15:36:54 +0000 Subject: [Cluster-devel] [PATCH] gfs2_trace: Added a script called gfs2_trace for kernel tracing debugging. In-Reply-To: <1355930071-13316-1-git-send-email-sbradley@redhat.com> References: <1355930071-13316-1-git-send-email-sbradley@redhat.com> Message-ID: <50D1DF16.4090408@redhat.com> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Hi Shane, Looks good to me, Andy On 19/12/12 15:14, sbradley at redhat.com wrote: > From: Shane Bradley > > The script gfs2_trace is a tool used for debugging kernel tracing events. The > script can enabled or disable all or selected GFS2 kernel tracing events. The > script can capture the trace events and write them to a specific file which will > be tarred up after the file is written. > > Signed-off-by: Shane Bradley > --- > gfs2/man/Makefile.am | 3 +- > gfs2/man/gfs2_trace.8 | 45 +++ > gfs2/scripts/Makefile.am | 2 +- > gfs2/scripts/gfs2_trace | 790 +++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 838 insertions(+), 2 deletions(-) > create mode 100644 gfs2/man/gfs2_trace.8 > create mode 100644 gfs2/scripts/gfs2_trace > > diff --git a/gfs2/man/Makefile.am b/gfs2/man/Makefile.am > index 8655a76..82eab9a 100644 > --- a/gfs2/man/Makefile.am > +++ b/gfs2/man/Makefile.am > @@ -8,4 +8,5 @@ dist_man_MANS = fsck.gfs2.8 \ > gfs2_jadd.8 \ > mkfs.gfs2.8 \ > tunegfs2.8 \ > - gfs2_lockcapture.8 > + gfs2_lockcapture.8 \ > + gfs2_trace.8 > diff --git a/gfs2/man/gfs2_trace.8 b/gfs2/man/gfs2_trace.8 > new file mode 100644 > index 0000000..dd98072 > --- /dev/null > +++ b/gfs2/man/gfs2_trace.8 > @@ -0,0 +1,45 @@ > +.TH gfs2_trace 8 > + > +.SH NAME > +gfs2_trace \- can enable trace events, disable trace events, and capture data from GFS2 trace events. > + > +.SH SYNOPSIS > +.B gfs2_trace \fR[-dqEN] [-e \fItrace event name]\fR [-n \fItrace event name]\fR [-o \fIoutput filename]\fR > +.PP > + > +.SH DESCRIPTION > +\fIgfs2_trace\fR can enabled and disable trace events on all trace events or selected trace events. \fIgfs2_trace\fR can > +capture the output of the trace events and write the output to a file. When capturing trace events, the script will exit > +when control-c is pressed. The trace events will be then written to the selected file. > +.PP > + > +.SH OPTIONS > +.TP > +\fB-h, --help\fP > +Prints out a short usage message and exits. > +.TP > +\fB-d, --debug\fP > +enables debug logging. > +.TP > +\fB-q, --quiet\fP > +disables logging to console. > +.TP > +\fB-l, --list\fP > +lists the enabled state and filters for the GFS2 trace events > +.TP > +\fB-E, --enable_all_trace_events\fP > +enables all trace_events for GFS2 > +.TP > +\fB-e \fI, \fB----enable_trace_event\fR=\fI\fP > +selected trace_events that will be enabled for GFS2 > +.TP > +\fB-N, --disable_all_trace_events\fP > +disables all trace_events for GFS2 > +.TP > +\fB-n \fI, \fB----disable_trace_event\fR=\fI\fP > +selected trace_events that will be enabled for GFS2 > +.TP > +\fB-c \fI, \fB--capture\fR=\fI\fP > +enables capturing of trace events and will save the data to a file > +. > +.SH SEE ALSO > diff --git a/gfs2/scripts/Makefile.am b/gfs2/scripts/Makefile.am > index b88580e..2c51222 100644 > --- a/gfs2/scripts/Makefile.am > +++ b/gfs2/scripts/Makefile.am > @@ -9,4 +9,4 @@ sbindir := $(shell rpl=0; test '$(exec_prefix):$(sbindir)' = /usr:/usr/sbin \ > test $$rpl = 1 && echo /sbin || echo '$(exec_prefix)/sbin') > > > -dist_sbin_SCRIPTS = gfs2_lockcapture > +dist_sbin_SCRIPTS = gfs2_lockcapture gfs2_trace > diff --git a/gfs2/scripts/gfs2_trace b/gfs2/scripts/gfs2_trace > new file mode 100644 > index 0000000..38b3d18 > --- /dev/null > +++ b/gfs2/scripts/gfs2_trace > @@ -0,0 +1,790 @@ > +#!/usr/bin/env python > +""" > +This script will enable or disable trace events for GFS2. The script can capture > +trace events and write the trace events captured to a file. > + > +When capturing events, hit "control-c" to exit and then the capture events will be > +written to a file. A file will be created by reading this pipe: > +/sys/kernel/debug/tracing/trace_pipe > + > +The debug directory is required to be mounted which will be mounted if not > +mounted. The trace events are located in this directory > +/sys/kernel/debug/tracing/events/gfs2. > + > +The file that can be used to validate what fields are valid for "filters" is > +described in the format file. For example: > +/sys/kernel/debug/tracing/events/gfs2/*/format > + > + at author : Shane Bradley > + at contact : sbradley at redhat.com > + at version : 0.9 > + at copyright : GPLv2 > +""" > +import sys > +import os > +import os.path > +import logging > +import platform > +import fileinput > +import tarfile > +import subprocess > +from optparse import OptionParser, Option > + > +# ##################################################################### > +# Global Vars: > +# ##################################################################### > +""" > + at cvar VERSION_NUMBER: The version number of this script. > + at type VERSION_NUMBER: String > + at cvar MAIN_LOGGER_NAME: The name of the logger. > + at type MAIN_LOGGER_NAME: String > + at cvar PATH_TO_DEBUG_DIR: The path to the debug directory for the linux kernel. > + at type PATH_TO_DEBUG_DIR: String > + at cvar PATH_TO_PID_FILENAME: The path to the pid file that will be used to make > +sure only 1 instance of this script is running at any time. > + at type PATH_TO_PID_FILENAME: String > + at cvar PATH_TO_GFS2_TRACE_EVENTS_DIR: The path to the directory that contains > +all the GFS2 trace events. > + at type PATH_TO_GFS2_TRACE_EVENTS_DIR: String > + at cvar PATH_TO_TRACE_PIPE: The path to the tracing pipe. > + at type PATH_TO_TRACE_PIPE: String > +""" > +VERSION_NUMBER = "0.9-1" > +MAIN_LOGGER_NAME = "gfs2trace" > +PATH_TO_DEBUG_DIR="/sys/kernel/debug" > +PATH_TO_PID_FILENAME = "/var/run/%s.pid" %(os.path.basename(sys.argv[0])) > +PATH_TO_GFS2_TRACE_EVENTS_DIR="%s/tracing/events/gfs2" %(PATH_TO_DEBUG_DIR) > +PATH_TO_TRACE_PIPE="%s/tracing/trace_pipe" %(PATH_TO_DEBUG_DIR) > + > +class FileUtils: > + """ > + A class that provides static functions for files such as reading and > + writing. > + """ > + def getDataFromFile(pathToSrcFile) : > + """ > + This function will return the data in an array. Where each newline in file > + is a seperate item in the array. This should really just be used on > + relatively small files. > + > + None is returned if no file is found. > + > + @return: Returns an array of Strings, where each newline in file is an item > + in the array. > + @rtype: Array > + > + @param pathToSrcFile: The path to the file which will be read. > + @type pathToSrcFile: String > + """ > + if (len(pathToSrcFile) > 0) : > + try: > + fin = open(pathToSrcFile, "r") > + data = fin.readlines() > + fin.close() > + return data > + except (IOError, os.error): > + message = "An error occured reading the file: %s." %(pathToSrcFile) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + return None > + getDataFromFile = staticmethod(getDataFromFile) > + > + def writeToFile(pathToFilename, data, appendToFile=True, createFile=False): > + """ > + This function will write a string to a file. > + > + @return: Returns True if the string was successfully written to the file, > + otherwise False is returned. > + @rtype: Boolean > + > + @param pathToFilename: The path to the file that will have a string written > + to it. > + @type pathToFilename: String > + @param data: The string that will be written to the file. > + @type data: String > + @param appendToFile: If True then the data will be appened to the file, if > + False then the data will overwrite the contents of the file. > + @type appendToFile: Boolean > + @param createFile: If True then the file will be created if it does not > + exists, if False then file will not be created if it does not exist > + resulting in no data being written to the file. > + @type createFile: Boolean > + """ > + [parentDir, filename] = os.path.split(pathToFilename) > + if (os.path.isfile(pathToFilename) or (os.path.isdir(parentDir) and createFile)): > + try: > + filemode = "w" > + if (appendToFile): > + filemode = "a" > + fout = open(pathToFilename, filemode) > + fout.write(data + "\n") > + fout.close() > + return True > + except UnicodeEncodeError, e: > + message = "There was a unicode encode error writing to the file: %s." %(pathToFilename) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + return False > + except IOError: > + message = "There was an error writing to the file: %s." %(pathToFilename) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + return False > + return False > + writeToFile = staticmethod(writeToFile) > + > +class TraceEvent: > + """ > + A class that reprensents a trace event. > + """ > + def __init__(self, pathToTraceEvent): > + """ > + @param pathToTraceEvent: The path to the trace event directory. > + @type pathToTraceEvent: String > + """ > + self.__pathToTraceEvent = pathToTraceEvent > + > + def __str__(self): > + """ > + Returns a string representation of a TraceEvent. > + > + @return: Returns a string representation of a TraceEvent. > + @rtype: String > + """ > + return "%s: %s" %(self.getName(), self.getEnable()) > + > + def __getEventPathItem(self, pathToFilename): > + """ > + Returns the data contain in the file. If file does not exist then empty > + array is returned. > + > + @return: Returns the data contained in the file. If file does not exist > + then empty array is returned. > + @rtype: Array > + > + @param pathToFilename: The path to the filename of the file in the trace > + event's directory. > + @type pathToFilename: String > + """ > + output = FileUtils.getDataFromFile(pathToFilename) > + if (output == None): > + return [] > + return output > + > + def __setEventPathItem(self, pathToFilename, contentsOfEventItem, appendToFile=True): > + """ > + This function will write data to a file in the trace event's directory. > + > + @return: Returns True is data was successfully written. > + @rtype: Boolean > + """ > + return FileUtils.writeToFile(pathToFilename, contentsOfEventItem, appendToFile) > + > + def getPathToTraceEvent(self): > + """ > + Returns the path to the trace event directory. > + > + @return: Returns the path to the trace event directory. > + @rtype: String > + """ > + return self.__pathToTraceEvent > + > + def getName(self): > + """ > + Returns the shortname of the trace event. > + > + @return: Returns the shortname of the trace event. > + @rtype: String > + """ > + return os.path.basename(self.getPathToTraceEvent()) > + > + def getEnable(self): > + """ > + Returns the contents of the file "enable" in the trace event directory. > + > + @return: Returns the contents of the file "enable" in the trace event > + directory. > + @rtype: String > + """ > + fileContents = self.__getEventPathItem(os.path.join(self.getPathToTraceEvent(), "enable")) > + if (len(fileContents) > 0): > + return fileContents[0].rstrip() > + else: > + return "" > + > + def getFilter(self): > + """ > + Returns the contents of the file "filter" in the trace event > + directory. Each line in the file is appened to an array that will be > + returned. > + > + @return: Returns the contents of the file "filter" in the trace event > + directory. > + @rtype: Array > + """ > + return self.__getEventPathItem(os.path.join(self.getPathToTraceEvent(), "filter")) > + > + def getFormat(self): > + """ > + Returns the contents of the file "format" in the trace event > + directory. Each line in the file is appened to an array that will be > + returned. > + > + @return: Returns the contents of the file "format" in the trace event > + directory. > + @rtype: Array > + """ > + return self.__getEventPathItem(os.path.join(self.getPathToTraceEvent(), "format")) > + > + def getID(self): > + """ > + Returns the contents of the file "id" in the trace event directory. > + > + @return: Returns the contents of the file "id" in the trace event > + directory. > + @rtype: String > + """ > + fileContents = self.__getEventPathItem(os.path.join(self.getPathToTraceEvent(), "id")) > + if (len(fileContents) > 0): > + return fileContents[0].rstrip() > + else: > + return "" > + > + def setEventEnable(self, eventEnableString): > + """ > + Set the trace event to either enabled(1) or disabled(0) by writing to > + the trace event's "enable" file. > + > + @param eventEnableString: The value of the string should be 1 for > + enabled or 0 for disabled. > + @param eventEnableString: String > + """ > + if ((eventEnableString == "0") or (eventEnableString == "1")): > + self.__setEventPathItem(os.path.join(self.getPathToTraceEvent(), "enable"), eventEnableString, appendToFile=False) > + else: > + message = "The trace event \"enable\" file only accepts the values of 0 or 1. The value %s will not be written: %s." %(eventEnableString) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + > +class TraceEvents: > + """ > + A class that is a container for multiple trace events that are located in a > + directory. > + """ > + def __init__(self, pathToTraceEvents): > + """ > + @param pathToTraceEvents: The path to the directory that contains trace > + events. > + @type pathToTraceEvents: String > + """ > + self.__pathToTraceEvents = pathToTraceEvents > + self.__traceEventsMap = self.__generateTraceEvents() > + > + def __generateTraceEvents(self): > + """ > + Generates a map of all the trace events. > + > + @return: Returns a map of all the TraceEvent found. > + @rtype: Dict > + """ > + traceEventsMap = {} > + if (not os.path.exists(self.__pathToTraceEvents)): > + message = "The path does not exist: %s" %(self.__pathToTraceEvents) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + return traceEventsMap > + elif (os.path.isdir(self.__pathToTraceEvents)): > + dirlist = [] > + try: > + dirlist = os.listdir(self.__pathToTraceEvents) > + except OSError: > + message = "There was error listing contents of the directory: %s" %(self.__pathToTraceEvents) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + for item in dirlist: > + pathToItem = os.path.join(PATH_TO_GFS2_TRACE_EVENTS_DIR, item) > + if (os.path.isdir(pathToItem)): > + traceEvent = TraceEvent(pathToItem) > + traceEventsMap[traceEvent.getName()] = traceEvent > + return traceEventsMap > + > + def getPathToTraceEvents(self): > + """ > + Returns the path to the directory that contains all the trace events. > + > + @return: Return the path to the directory that contains all the trace > + events. > + @rtype: String > + """ > + return self.__pathToTraceEvents > + > + def getTraceEventNames(self): > + """ > + Returns a list of all the trace event names found. > + > + @return: Returns a list of all the trace event names found. > + @rtype: Array > + """ > + return self.__traceEventsMap.keys() > + > + def getTraceEvent(self, traceEventName): > + """ > + Returns a TraceEvent that matches the traceEventName. If no match is > + found then None is returned. > + > + @return: Returns a TraceEvent that matches the traceEventName. If no > + match is found then None is returned. > + @rtype: TraceEvent > + """ > + if (self.__traceEventsMap.has_key(traceEventName)): > + return self.__traceEventsMap.get(traceEventName) > + return None > + > +# ##################################################################### > +# Helper functions. > +# ##################################################################### > +def runCommand(command, listOfCommandOptions, standardOut=subprocess.PIPE, standardError=subprocess.PIPE): > + """ > + This function will execute a command. It will return True if the return code > + was zero, otherwise False is returned. > + > + @return: Returns True if the return code was zero, otherwise False is > + returned. > + @rtype: Boolean > + > + @param command: The command that will be executed. > + @type command: String > + @param listOfCommandOptions: The list of options for the command that will > + be executed. > + @type listOfCommandOptions: Array > + @param standardOut: The pipe that will be used to write standard output. By > + default the pipe that is used is subprocess.PIPE. > + @type standardOut: Pipe > + @param standardError: The pipe that will be used to write standard error. By > + default the pipe that is used is subprocess.PIPE. > + @type standardError: Pipe > + """ > + stdout = "" > + stderr = "" > + try: > + commandList = [command] > + commandList += listOfCommandOptions > + task = subprocess.Popen(commandList, stdout=standardOut, stderr=standardError) > + task.wait() > + (stdout, stderr) = task.communicate() > + return (task.returncode == 0) > + except OSError: > + commandOptionString = "" > + for option in listOfCommandOptions: > + commandOptionString += "%s " %(option) > + message = "An error occurred running the command: $ %s %s\n" %(command, commandOptionString) > + if (len(stdout) > 0): > + message += stdout > + message += "\n" > + if (len(stderr) > 0): > + message += stderr > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + return False > + > +def mountFilesystem(filesystemType, pathToDevice, pathToMountPoint): > + """ > + This function will attempt to mount a filesystem. If the filesystem is > + already mounted or the filesystem was successfully mounted then True is > + returned, otherwise False is returned. > + > + @return: If the filesystem is already mounted or the filesystem was > + successfully mounted then True is returned, otherwise False is returned. > + @rtype: Boolean > + > + @param filesystemType: The type of filesystem that will be mounted. > + @type filesystemType: String > + @param pathToDevice: The path to the device that will be mounted. > + @type pathToDevice: String > + @param pathToMountPoint: The path to the directory that will be used as the > + mount point for the device. > + @type pathToMountPoint: String > + """ > + if (os.path.ismount(PATH_TO_DEBUG_DIR)): > + return True > + listOfCommandOptions = ["-t", filesystemType, pathToDevice, pathToMountPoint] > + if (not runCommand("mount", listOfCommandOptions)): > + message = "There was an error mounting the filesystem type %s for the device %s to the mount point %s." %(filesystemType, pathToDevice, pathToMountPoint) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + return os.path.ismount(PATH_TO_DEBUG_DIR) > + > +def exitScript(removePidFile=True, errorCode=0): > + """ > + This function will cause the script to exit or quit. It will return an error > + code and will remove the pid file that was created. > + > + @param removePidFile: If True(default) then the pid file will be remove > + before the script exits. > + @type removePidFile: Boolean > + @param errorCode: The exit code that will be returned. The default value is 0. > + @type errorCode: Int > + """ > + if (removePidFile): > + message = "Removing the pid file: %s" %(PATH_TO_PID_FILENAME) > + logging.getLogger(MAIN_LOGGER_NAME).debug(message) > + if (os.path.exists(PATH_TO_PID_FILENAME)): > + try: > + os.remove(PATH_TO_PID_FILENAME) > + except IOError: > + message = "There was an error removing the file: %s." %(PATH_TO_PID_FILENAME) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + message = "The script will exit." > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + sys.exit(errorCode) > + > +def getMountedGFS2Filesystems(): > + """ > + This function returns a list of all the mounted GFS2 filesystems. > + > + @return: Returns a list of all the mounted GFS2 filesystems. > + @rtype: Array > + """ > + fsType = "gfs2" > + listOfMountedFilesystems = [] > + dataOutput = FileUtils.getDataFromFile("/proc/mounts") > + if (not dataOutput == None): > + for line in dataOutput: > + splitLine = line.split() > + if (len(splitLine) > 0): > + if (splitLine[2] == fsType): > + listOfMountedFilesystems.append(line) > + return listOfMountedFilesystems > +# ############################################################################## > +# Get user selected options > +# ############################################################################## > +def __getOptions(version) : > + """ > + This function creates the OptionParser and returns commandline > + a tuple of the selected commandline options and commandline args. > + > + The cmdlineOpts which is the options user selected and cmdLineArgs > + is value passed and not associated with an option. > + > + @return: A tuple of the selected commandline options and commandline args. > + @rtype: Tuple > + > + @param version: The version of the this script. > + @type version: String > + """ > + cmdParser = OptionParserExtended(version) > + cmdParser.add_option("-d", "--debug", > + action="store_true", > + dest="enableDebugLogging", > + help="enables debug logging", > + default=False) > + cmdParser.add_option("-q", "--quiet", > + action="store_true", > + dest="disableLoggingToConsole", > + help="disables logging to console", > + default=False) > + cmdParser.add_option("-l", "--list", > + action="store_true", > + dest="listTraceEvents", > + help="lists the enabled state and filters for the GFS2 trace events", > + default=False) > + cmdParser.add_option("-E", "--enable_all_trace_events", > + action="store_true", > + dest="enableAllTraceEvents", > + help="enables all trace_events for GFS2", > + default=False) > + cmdParser.add_option("-e", "--enable_trace_event", > + action="extend", > + dest="enableTraceEventsList", > + help="selected trace_events that will be enabled for GFS2", > + type="string", > + metavar="", > + default=[]) > + cmdParser.add_option("-N", "--disable_all_trace_events", > + action="store_true", > + dest="disableAllTraceEvents", > + help="disables all trace_events for GFS2", > + default=False) > + cmdParser.add_option("-n", "--disable_trace_event", > + action="extend", > + dest="disableTraceEventsList", > + help="selected trace_events that will be disabled for GFS2", > + type="string", > + metavar="", > + default=[]) > + cmdParser.add_option("-c", "--capture", > + action="store", > + dest="pathToOutputFilename", > + help="enables capturing of trace events and will save the data to a file", > + type="string", > + metavar="", > + default="") > + > + (cmdLineOpts, cmdLineArgs) = cmdParser.parse_args() > + return (cmdLineOpts, cmdLineArgs) > + > +# ############################################################################## > +# OptParse classes for commandline options > +# ############################################################################## > +class OptionParserExtended(OptionParser): > + """ > + This is the class that gets the command line options the end user > + selects. > + """ > + def __init__(self, version) : > + """ > + @param version: The version of the this script. > + @type version: String > + """ > + self.__commandName = os.path.basename(sys.argv[0]) > + versionMessage = "%s %s\n" %(self.__commandName, version) > + > + commandDescription ="%s can enable trace events, disable trace events, and capture data from GFS2 trace events.\n"%(self.__commandName) > + OptionParser.__init__(self, option_class=ExtendOption, > + version=versionMessage, > + description=commandDescription) > + > + def print_help(self): > + """ > + Print examples at the bottom of the help message. > + """ > + exampleMessage = "\nExamples:\n" > + exampleMessage += "To list the enable status and filter for each trace event.\n" > + exampleMessage += "# %s -l\n\n" %(self.__commandName) > + exampleMessage += "To disable all trace events.\n" > + exampleMessage += "# %s -N\n\n" %(self.__commandName) > + exampleMessage += "To enable all trace events.\n" > + exampleMessage += "# %s -E\n\n" %(self.__commandName) > + exampleMessage += "To disable all trace events and then enable a couple trace events.\n" > + exampleMessage += "# %s -N -e gfs2_demote_rq,gfs2_glock_state_change,gfs2_promote\n\n" %(self.__commandName) > + exampleMessage += "To capture all the trace events and write to the file /tmp/gfs2_trace.log.\n" > + exampleMessage += "# %s -c /tmp/gfs2_trace.log\n\n" %(self.__commandName) > + exampleMessage += "To disable all trace events and then enable a couple trace events and capture the output to a file.\n" > + exampleMessage += "# %s -N -e gfs2_demote_rq,gfs2_glock_state_change,gfs2_promote -c /tmp/gfs2_trace.log\n" %(self.__commandName) > + self.print_version() > + OptionParser.print_help(self) > + print exampleMessage > + > +class ExtendOption (Option): > + """ > + Allow to specify comma delimited list of entries for arrays > + and dictionaries. > + """ > + ACTIONS = Option.ACTIONS + ("extend",) > + STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",) > + TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",) > + > + def take_action(self, action, dest, opt, value, values, parser): > + """ > + This function is a wrapper to take certain options passed on command > + prompt and wrap them into an Array. > + > + @param action: The type of action that will be taken. For example: > + "store_true", "store_false", "extend". > + @type action: String > + @param dest: The name of the variable that will be used to store the > + option. > + @type dest: String/Boolean/Array > + @param opt: The option string that triggered the action. > + @type opt: String > + @param value: The value of opt(option) if it takes a > + value, if not then None. > + @type value: > + @param values: All the opt(options) in a dictionary. > + @type values: Dictionary > + @param parser: The option parser that was orginally called. > + @type parser: OptionParser > + """ > + if (action == "extend") : > + valueList=[] > + try: > + for v in value.split(","): > + # Need to add code for dealing with paths if there is option for paths. > + valueList.append(v) > + except: > + pass > + else: > + values.ensure_value(dest, []).extend(valueList) > + else: > + Option.take_action(self, action, dest, opt, value, values, parser) > + > +# ############################################################################### > +# Main Function > +# ############################################################################### > +if __name__ == "__main__": > + try: > + # ####################################################################### > + # Get the options from the commandline. > + # ####################################################################### > + (cmdLineOpts, cmdLineArgs) = __getOptions(VERSION_NUMBER) > + > + # ####################################################################### > + # Setup the logger > + # ####################################################################### > + # Create the logger > + logLevel = logging.INFO > + logger = logging.getLogger(MAIN_LOGGER_NAME) > + logger.setLevel(logLevel) > + # Create a new status function and level. > + logging.STATUS = logging.INFO + 2 > + logging.addLevelName(logging.STATUS, "STATUS") > + # Create a function for the STATUS_LEVEL since not defined by python. This > + # means you can call it like the other predefined message > + # functions. Example: logging.getLogger("loggerName").status(message) > + setattr(logger, "status", lambda *args: logger.log(logging.STATUS, *args)) > + streamHandler = logging.StreamHandler() > + streamHandler.setFormatter(logging.Formatter("%(levelname)s %(message)s")) > + logger.addHandler(streamHandler) > + > + # Set options on logger for debugging or no logging. > + if (cmdLineOpts.disableLoggingToConsole): > + logging.disable(logging.CRITICAL) > + elif (cmdLineOpts.enableDebugLogging) : > + logging.getLogger(MAIN_LOGGER_NAME).setLevel(logging.DEBUG) > + message = "Debugging has been enabled." > + logging.getLogger(MAIN_LOGGER_NAME).debug(message) > + > + # ####################################################################### > + # Check to see if pid file exists and error if it does. > + # ####################################################################### > + if (os.path.exists(PATH_TO_PID_FILENAME)): > + message = "The PID file %s already exists and this script cannot run till it does not exist." %(PATH_TO_PID_FILENAME) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + message = "Verify that there are no other existing processes running. If there are running processes those need to be stopped first and the file removed." > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + exitScript(removePidFile=False, errorCode=1) > + else: > + message = "Creating the pid file: %s" %(PATH_TO_PID_FILENAME) > + logging.getLogger(MAIN_LOGGER_NAME).debug(message) > + # Creata the pid file so we dont have more than 1 process of this > + # script running. > + FileUtils.writeToFile(PATH_TO_PID_FILENAME, str(os.getpid()), createFile=True) > + > + # ####################################################################### > + # Check to see if there any GFS2 filesystems mounted, if not then exit. > + # ####################################################################### > + if (not len(getMountedGFS2Filesystems()) > 0): > + message = "There was no GFS2 file-systems mounted." > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + exitScript(errorCode=1) > + > + # ####################################################################### > + # Check to see if the debug directory is mounted. If not then > + # log an error. > + # ####################################################################### > + if(mountFilesystem("debugfs", "none", PATH_TO_DEBUG_DIR)): > + message = "The debug filesystem %s is mounted." %(PATH_TO_DEBUG_DIR) > + logging.getLogger(MAIN_LOGGER_NAME).debug(message) > + else: > + message = "There was a problem mounting the debug filesystem: %s" %(PATH_TO_DEBUG_DIR) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + message = "The debug filesystem is required to be mounted for this script to run." > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + exitScript(errorCode=1) > + > + # ####################################################################### > + # List of the enable state and filters for each trace event > + # ####################################################################### > + traceEvents = TraceEvents(PATH_TO_GFS2_TRACE_EVENTS_DIR) > + listOfTraceEventNames = traceEvents.getTraceEventNames() > + > + if (cmdLineOpts.listTraceEvents): > + listOfTraceEventNames.sort() > + maxTraceEventNameSize = len(max(listOfTraceEventNames, key=len)) > + traceEventsString = "" > + for traceEventName in listOfTraceEventNames: > + traceEvent = traceEvents.getTraceEvent(traceEventName) > + if (not traceEventName == None): > + traceEventEnableStatus = "UNKNOWN" > + if (traceEvent.getEnable() == "0"): > + traceEventEnableStatus = "DISABLED" > + elif (traceEvent.getEnable() == "1"): > + traceEventEnableStatus = "ENABLED" > + whitespaces = "" > + for i in range(0, (maxTraceEventNameSize - len(traceEventName))): > + whitespaces += " " > + traceEventsString += "%s %s%s\n" %(traceEventName, whitespaces, traceEventEnableStatus) > + # Disable logging to console except for debug when we print into information to console. > + logging.disable(logging.CRITICAL) > + if (len(traceEventsString) > 0): > + print "trace event name trace event status" > + print "---------------- ------------------" > + print traceEventsString.rstrip() > + exitScript() > + # ####################################################################### > + # Enable or Disable Trace Events > + # ####################################################################### > + if (cmdLineOpts.disableAllTraceEvents): > + message = "Disabling all trace events." > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + for traceEventName in listOfTraceEventNames: > + traceEvent = traceEvents.getTraceEvent(traceEventName) > + if (not traceEvent == None): > + traceEvent.setEventEnable("0") > + elif (cmdLineOpts.enableAllTraceEvents): > + message = "Enabling all trace events." > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + for traceEventName in listOfTraceEventNames: > + traceEvent = traceEvents.getTraceEvent(traceEventName) > + if (not traceEvent == None): > + traceEvent.setEventEnable("1") > + > + if (len(cmdLineOpts.disableTraceEventsList) > 0): > + for traceEventName in cmdLineOpts.disableTraceEventsList: > + traceEvent = traceEvents.getTraceEvent(traceEventName) > + if (not traceEvent == None): > + message = "Disabling the selected trace event: %s" %(traceEvent.getName()) > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + traceEvent.setEventEnable("0") > + if (len(cmdLineOpts.enableTraceEventsList) > 0): > + for traceEventName in cmdLineOpts.enableTraceEventsList: > + traceEvent = traceEvents.getTraceEvent(traceEventName) > + if (not traceEvent == None): > + message = "Enabling the selected trace event: %s" %(traceEvent.getName()) > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + traceEvent.setEventEnable("1") > + > + # ####################################################################### > + # Capture the data generate by the trace events. > + # ####################################################################### > + if (len(cmdLineOpts.pathToOutputFilename) > 0): > + # Read from tracing pipe and write the output to a file. > + message = "The capturing of the trace events that were enabled to a file will be started by reading the the trace pipe: %s." %(PATH_TO_TRACE_PIPE) > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + message = "Leave this script running until you have capture all the data, then hit control-c to exit." > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + try: > + fout = open(cmdLineOpts.pathToOutputFilename, "w") > + for line in fileinput.input(PATH_TO_TRACE_PIPE): > + fout.write(line) > + fout.close() > + message = "The data was written to this file: %s" %(cmdLineOpts.pathToOutputFilename) > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + except KeyboardInterrupt: > + message = "A control-c was detected and the capturing of trace events data will stop." > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + fout.close() > + message = "The data was written to this file: %s" %(cmdLineOpts.pathToOutputFilename) > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + except UnicodeEncodeError, e: > + message = "There was a unicode encode error writing to the file: %s." %(cmdLineOpts.pathToOutputFilename) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + except IOError: > + message = "There was an error writing to the file: %s." %(cmdLineOpts.pathToOutputFilename) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + message = "The capturing of the trace event data has completed." > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + # Compress the file so that it will have a smaller file size. > + pathToTarFilename = "%s.tar.bz2" %(os.path.splitext(cmdLineOpts.pathToOutputFilename)[0]) > + message = "Creating a compressed archvied file: %s" %(pathToTarFilename) > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + try: > + tar = tarfile.open(pathToTarFilename, "w:bz2") > + tar.add(cmdLineOpts.pathToOutputFilename, arcname=os.path.basename(cmdLineOpts.pathToOutputFilename)) > + tar.close() > + message = "The compressed archvied file was created: %s" %(pathToTarFilename) > + logging.getLogger(MAIN_LOGGER_NAME).info(message) > + except tarfile.TarError: > + message = "There was an error creating the tarfile: %s." %(pathToTarFilename) > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + except KeyboardInterrupt: > + print "" > + message = "This script will exit since control-c was executed by end user." > + logging.getLogger(MAIN_LOGGER_NAME).error(message) > + exitScript() > + # ####################################################################### > + # Exit the application with zero exit code since we cleanly exited. > + # ####################################################################### > + exitScript() >