Salome HOME
spns #26801 : bug sat package, le lanceur ne faisait pas le réinit
[tools/sat.git] / src / logger.py
old mode 100644 (file)
new mode 100755 (executable)
index d1aa350..545ac0b
@@ -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