X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2Flogger.py;h=545ac0b8dfbe368f7d2333b23129455ed653dffa;hb=b9e6051c562d5a43354f33fab32109d45cbc9d5a;hp=d1aa350360e6728f55d432c28cf3035d7f2d71dc;hpb=4fcd76ce82f9aefff693f177e6d84e8ea15f450a;p=tools%2Fsat.git diff --git a/src/logger.py b/src/logger.py old mode 100644 new mode 100755 index d1aa350..545ac0b --- a/src/logger.py +++ b/src/logger.py @@ -22,23 +22,29 @@ Implements the classes and method relative to the logging import sys import os +import stat import datetime import re import tempfile +import shutil import src -from . import printcolors -from . import xmlManager +import printcolors +import xmlManager + +import src.debug as DBG log_macro_command_file_expression = "^[0-9]{8}_+[0-9]{6}_+.*\.xml$" log_all_command_file_expression = "^.*[0-9]{8}_+[0-9]{6}_+.*\.xml$" +verbose = True # cvw TODO + class Logger(object): """\ Class to handle log mechanism. """ def __init__(self, - config, + config= None, silent_sysstd=False, all_in_terminal=False, micro_command = False): @@ -48,6 +54,7 @@ class Logger(object): :param silent_sysstd boolean: if True, do not write anything in terminal. """ + DBG.write("src.logger.Logger", id(self)) self.config = config self.default_level = 3 self.silentSysStd = silent_sysstd @@ -66,8 +73,22 @@ class Logger(object): # the external commands calls (cmake, make, git clone, etc...) txtFileName = prefix + hour_command_host + ".txt" txtFilePath = os.path.join(log_dir, "OUT", txtFileName) - - src.ensure_path_exists(os.path.dirname(logFilePath)) + + aDirLog = os.path.dirname(logFilePath) + if not os.path.exists(aDirLog): + print("create log dir %s" % aDirLog) + src.ensure_path_exists(aDirLog) + # sometimes other users make 'sat log' and create hat.xml file... + os.chmod(aDirLog, + stat.S_IRUSR | + stat.S_IRGRP | + stat.S_IROTH | + stat.S_IWUSR | + stat.S_IWGRP | + stat.S_IWOTH | + stat.S_IXUSR | + stat.S_IXGRP | + stat.S_IXOTH) src.ensure_path_exists(os.path.dirname(txtFilePath)) # The path of the log files (one for sat traces, and the other for @@ -113,7 +134,7 @@ class Logger(object): self.config.VARS.command}) # version of salomeTools self.xmlFile.append_node_attrib("Site", attrib={"satversion" : - self.config.INTERNAL.sat_version}) + src.get_salometool_version(self.config)}) # machine name on which the command has been launched self.xmlFile.append_node_attrib("Site", attrib={"hostname" : self.config.VARS.hostname}) @@ -125,7 +146,7 @@ class Logger(object): self.config.VARS.user}) # The time when command was launched Y, m, dd, H, M, S = date_to_datetime(self.config.VARS.datehour) - date_hour = "%2s/%2s/%4s %2sh%2sm%2ss" % (dd, m, Y, H, M, S) + date_hour = "%4s/%2s/%2s %2sh%2sm%2ss" % (Y, m, dd, H, M, S) self.xmlFile.append_node_attrib("Site", attrib={"beginTime" : date_hour}) # The application if any @@ -156,12 +177,9 @@ class Logger(object): ("sat command ...") """ xmlLinks = self.xmlFile.xmlroot.find("Links") - src.xmlManager.add_simple_node(xmlLinks, - "link", - text = log_file_name, - attrib = {"command" : command_name, - "passed" : command_res, - "launchedCommand" : full_launched_command}) + flc = src.xmlManager.escapeSequence(full_launched_command) + att = {"command" : command_name, "passed" : str(command_res), "launchedCommand" : flc} + src.xmlManager.add_simple_node(xmlLinks, "link", text = log_file_name, attrib = att) def write(self, message, level=None, screenOnly=False): """\ @@ -173,6 +191,12 @@ class Logger(object): to the message 0 < level < 6. :param screenOnly boolean: if True, do not write in log file. """ + # avoid traces if unittest + if isCurrentLoggerUnittest(): + # print("doing unittest") + sendMessageToCurrentLogger(message, level) + return + # do not write message starting with \r to log file if not message.startswith("\r") and not screenOnly: self.xmlFile.append_node_text("Log", @@ -194,20 +218,57 @@ class Logger(object): sys.stdout.write(message) self.flush() - def error(self, message): - """Print an error. - - :param message str: The message to print. - """ - # Print in the log file - self.xmlFile.append_node_text("traces", _('ERROR:') + message) + def error(self, message, prefix="ERROR: "): + """Print an error. + + :param message str: The message to print. + """ + # Print in the log file + self.xmlFile.append_node_text("traces", prefix + message) + + # Print in the terminal and clean colors if the terminal + # is redirected by user + if not ('isatty' in dir(sys.stderr) and sys.stderr.isatty()): + sys.stderr.write(printcolors.printcError(prefix + message + "\n")) + else: + sys.stderr.write(prefix + message + "\n") + + def step(self, message): + """Print an step message. + + :param message str: The message to print. + """ + self.write('STEP: ' + message, level=4) + + def trace(self, message): + """Print an trace message. + + :param message str: The message to print. + """ + self.write('TRACE: ' + message, level=5) + + def debug(self, message): + """Print an debug message. + + :param message str: The message to print. + """ + self.write('DEBUG: ' + message, level=6) + + def warning(self, message): + """Print an warning message. + + :param message str: The message to print. + """ + self.error(message, prefix="WARNING: ") + + def critical(self, message): + """Print an critical message. + + :param message str: The message to print. + """ + self.error(message, prefix="CRITICAL: ") + - # Print in the terminal and clean colors if the terminal - # is redirected by user - if not ('isatty' in dir(sys.stderr) and sys.stderr.isatty()): - sys.stderr.write(printcolors.printcError(_('ERROR:') + message)) - else: - sys.stderr.write(_('ERROR:') + message) def flush(self): """Flush terminal""" @@ -245,10 +306,28 @@ class Logger(object): # Call the method to write the xml file on the hard drive self.xmlFile.write_tree(stylesheet = "command.xsl") + + # so unconditionnaly copy stylesheet file(s) + xslDir = os.path.join(self.config.VARS.srcDir, 'xsl') + xslCommand = "command.xsl" + # xslHat = "hat.xsl" # have to be completed (one time at end) + xsltest = "test.xsl" + imgLogo = "LOGO-SAT.png" + files_to_copy = [xslCommand, xsltest, imgLogo] + + logDir = src.get_log_path(self.config) + # copy the stylesheets in the log directory as soon as possible here + # because referenced in self.xmlFile.write_tree above + # OP We use copy instead of copy2 to update the creation date + # So we can clean the LOGS directories easily + for f in files_to_copy: + f_init = os.path.join(xslDir, f) + f_target = os.path.join(logDir, f) + if not os.path.isfile(f_target): # do not overrride + shutil.copy(f_init, logDir) # Dump the config in a pyconf file in the log directory - logDir = src.get_log_path(self.config) - dumpedPyconfFileName = (self.config.VARS.datehour + dumpedPyconfFileName = (self.config.VARS.datehour + "_" + self.config.VARS.command + ".pyconf") @@ -320,17 +399,22 @@ def show_command_log(logFilePath, cmd, application, notShownCommands): sys.stdout.write(printcolors.printcWarning("%s\n%s\n" % (msg, e))) return False, None, None - if 'application' in logFileXml.xmlroot.keys(): - appliLog = logFileXml.xmlroot.get('application') - launched_cmd = logFileXml.xmlroot.find('Site').attrib['launchedCommand'] - # if it corresponds, then the log has to be shown - if appliLog == application: - return True, appliLog, launched_cmd - elif application != 'None': - return False, appliLog, launched_cmd - - return True, appliLog, launched_cmd - + try: + if 'application' in logFileXml.xmlroot.keys(): + appliLog = logFileXml.xmlroot.get('application') + launched_cmd = logFileXml.xmlroot.find('Site').attrib['launchedCommand'] + # if it corresponds, then the log has to be shown + if appliLog == application: + return True, appliLog, launched_cmd + elif application != 'None': + return False, appliLog, launched_cmd + + return True, appliLog, launched_cmd + except Exception as e: + msg = _("WARNING: the log file %s cannot be parsed:" % logFilePath) + sys.stdout.write(printcolors.printcWarning("%s\n%s\n" % (msg, e))) + return False, None, None + if application == 'None': return True, None, None @@ -388,8 +472,7 @@ def update_hat_xml(logDir, application=None, notShownCommands = []): """ # Create an instance of XmlLogFile class to create hat.xml file xmlHatFilePath = os.path.join(logDir, 'hat.xml') - xmlHat = src.xmlManager.XmlLogFile(xmlHatFilePath, - "LOGlist", {"application" : application}) + xmlHat = src.xmlManager.XmlLogFile(xmlHatFilePath, "LOGlist", {"application" : application}) # parse the log directory to find all the command logs, # then add it to the xml file lLogFile = list_log_file(logDir, log_macro_command_file_expression) @@ -409,3 +492,95 @@ def update_hat_xml(logDir, application=None, notShownCommands = []): # Write the file on the hard drive xmlHat.write_tree('hat.xsl') + # Sometimes other users will make 'sat log' and update this file + os.chmod(xmlHatFilePath, + stat.S_IRUSR | + stat.S_IRGRP | + stat.S_IROTH | + stat.S_IWUSR | + stat.S_IWGRP | + stat.S_IWOTH ) + + + +# TODO for future +# prepare skip to logging logger sat5.1 +# suppose only one logger in sat5.1 +_currentLogger = [] + +def getCurrentLogger(): + """get current logging logger, set as DefaultLogger if not set yet""" + if len(_currentLogger) == 0: + import src.loggingSimple as LOGSI + logger = LOGSI.getDefaultLogger() + _currentLogger.append(logger) + logger.warning("set by default current logger as %s" % logger.name) + return _currentLogger[0] + +def getDefaultLogger(): + """get simple logging logger DefaultLogger, set it as current""" + import src.loggingSimple as LOGSI + logger = LOGSI.getDefaultLogger() + setCurrentLogger(logger) # set it as current + return logger + +def getUnittestLogger(): + """get simple logging logger UnittestLogger, set it as current""" + import src.loggingSimple as LOGSI + logger = LOGSI.getUnittestLogger() + setCurrentLogger(logger) # set it as current + return logger + +def setCurrentLogger(logger): + """temporary send all in stdout as simple logging logger""" + if len(_currentLogger) == 0: + _currentLogger.append(logger) + logger.debug("set current logger as %s" % logger.name) + else: + if _currentLogger[0].name != logger.name: + # logger.debug("quit current logger as default %s" % _currentLogger[0].name) + _currentLogger[0] = logger + logger.warning("change current logger as %s" % logger.name) + return _currentLogger[0] + +def isCurrentLoggerUnittest(): + logger = getCurrentLogger() + if "Unittest" in logger.name: + res = True + else: + res = False + #DBG.write("isCurrentLoggerUnittest %s" % logger.name, res) + return res + +def sendMessageToCurrentLogger(message, level): + """ + assume relay from obsolescent + logger.write(msg, 1/2/3...) to future + logging.critical/warning/info...(msg) (as logging package tips) + """ + logger = getCurrentLogger() + if level is None: + lev = 2 + else: + lev = level + if lev <= 1: + logger.critical(message) + return + if lev == 2: + logger.warning(message) + return + if lev == 3: + logger.info(message) + return + if lev == 4: + logger.step(message) + return + if lev == 5: + logger.trace(message) + return + if lev >= 6: + logger.debug(message) + return + msg = "What is this level: '%s' for message:\n%s" % (level, message) + logger.warning(msg) + return