3 # Copyright (C) 2010-2012 CEA/DEN
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 from . import printcolors
25 from . import xmlManager
28 '''Class to handle log mechanism
30 def __init__(self, config, silent_sysstd=False):
33 :param config pyconf.Config: The global configuration.
34 :param silent_sysstd boolean: if True, do not write anything in terminal.
37 self.default_level = 3
38 self.silentSysStd = silent_sysstd
40 # Construct log file location. There are two cases. With an application an without any application.
41 logFileName = config.VARS.datehour + "_" + config.VARS.command + ".xml"
42 if 'APPLICATION' in config:
43 logFilePath = os.path.join(config.APPLICATION.out_dir, 'LOGS', logFileName)
45 logFilePath = os.path.join(config.VARS.personalDir, 'LOGS', logFileName)
46 src.ensure_path_exists(os.path.dirname(logFilePath))
48 self.logFileName = logFileName
49 self.logFilePath = logFilePath
50 self.xmlFile = xmlManager.xmlLogFile(logFilePath, "SATcommand", attrib = {"command" : config.VARS.command})
51 self.putInitialXMLFields()
53 def putInitialXMLFields(self):
54 '''Method called at class initialization : Put all fields corresponding to the command context (user, time, ...)
57 self.xmlFile.add_simple_node("Site", attrib={"command" : self.config.VARS.command})
58 # version of salomeTools
59 self.xmlFile.append_node_attrib("Site", attrib={"satversion" : self.config.INTERNAL.sat_version})
60 # machine name on which the command has been launched
61 self.xmlFile.append_node_attrib("Site", attrib={"hostname" : self.config.VARS.hostname})
62 # Distribution of the machine
63 self.xmlFile.append_node_attrib("Site", attrib={"OS" : self.config.VARS.dist})
64 # The user that have launched the command
65 self.xmlFile.append_node_attrib("Site", attrib={"user" : self.config.VARS.user})
66 # The time when command was launched
67 Y, m, dd, H, M, S = date_to_datetime(self.config.VARS.datehour)
68 date_hour = "%2s/%2s/%4s %2sh%2sm%2ss" % (dd, m, Y, H, M, S)
69 self.xmlFile.append_node_attrib("Site", attrib={"beginTime" : date_hour})
70 # The initialization of the trace node
71 self.xmlFile.add_simple_node("Log",text="")
73 def write(self, message, level=None, screenOnly=False):
74 '''the function used in the commands that will print in the terminal and the log file.
76 :param message str: The message to print.
77 :param level int: The output level corresponding to the message 0 < level < 6.
78 :param screenOnly boolean: if True, do not write in log file.
80 # do not write message starting with \r to log file
81 if not message.startswith("\r") and not screenOnly:
82 self.xmlFile.append_node_text("Log", printcolors.cleancolor(message))
84 # get user or option output level
85 current_output_level = self.config.USER.output_level
86 if not ('isatty' in dir(sys.stdout) and sys.stdout.isatty()):
87 # clean the message color if the terminal is redirected by user
88 # ex: sat compile appli > log.txt
89 message = printcolors.cleancolor(message)
91 # Print message regarding the output level value
93 if level <= current_output_level and not self.silentSysStd:
94 sys.stdout.write(message)
96 if self.default_level <= current_output_level and not self.silentSysStd:
97 sys.stdout.write(message)
99 def error(self, message):
102 :param message str: The message to print.
104 # Print in the log file
105 self.xmlFile.append_node_text("traces", _('ERROR:') + message)
107 # Print in the terminal and clean colors if the terminal is redirected by user
108 if not ('isatty' in dir(sys.stderr) and sys.stderr.isatty()):
109 sys.stderr.write(printcolors.printcError(_('ERROR:') + message))
111 sys.stderr.write(_('ERROR:') + message)
119 '''Method called just after command end : Put all fields corresponding to the command end context (time).
120 Write the log xml file on the hard drive.
121 And display the command to launch to get the log
123 # Print the command to launch to get the log, regarding the fact that there an application or not
124 self.write(_('\nTap the following command to get the log :\n'), screenOnly=True)
125 if 'APPLICATION' in self.config:
126 self.write('%s/sat log %s\n' % (self.config.VARS.salometoolsway, self.config.VARS.application), screenOnly=True)
128 self.write('%s/sat log\n' % self.config.VARS.salometoolsway, screenOnly=True)
130 # Get current time (end of command) and format it
131 dt = datetime.datetime.now()
132 Y, m, dd, H, M, S = date_to_datetime(self.config.VARS.datehour)
133 t0 = datetime.datetime(int(Y), int(m), int(dd), int(H), int(M), int(S))
136 total_time = timedelta_total_seconds(delta)
137 hours = int(total_time / 3600)
138 minutes = int((total_time - hours*3600) / 60)
139 seconds = total_time - hours*3600 - minutes*60
140 # Add the fields corresponding to the end time and the total time of command
141 endtime = dt.strftime('%d/%Y/%m %Hh%Mm%Ss')
142 self.xmlFile.append_node_attrib("Site", attrib={"endTime" : endtime})
143 self.xmlFile.append_node_attrib("Site", attrib={"TotalTime" : "%ih%im%is" % (hours, minutes, seconds)})
145 # Call the method to write the xml file on the hard drive
146 self.xmlFile.write_tree(stylesheet = "command.xsl")
148 # Update the hat xml (that shows all logs) in order to make the new log visible on the main log page)
149 if 'APPLICATION' in self.config:
150 src.xmlManager.update_hat_xml(self.config.VARS.logDir, self.config.VARS.application)
152 src.xmlManager.update_hat_xml(self.config.VARS.logDir)
154 def date_to_datetime(date):
155 '''Little method that gets year, mon, day, hour , minutes and seconds from a str in format YYYYMMDD_HHMMSS
157 :param date str: The date in format YYYYMMDD_HHMMSS
158 :return: the same date and time in separate variables.
159 :rtype: (str,str,str,str,str,str)
167 return Y, m, dd, H, M, S
169 def timedelta_total_seconds(timedelta):
170 '''Little method to replace total_seconds from datetime module in order to be compatible with old python versions
172 :param timedelta datetime.timedelta: The delta between two dates
173 :return: The number of seconds corresponding to timedelta.
177 timedelta.microseconds + 0.0 +
178 (timedelta.seconds + timedelta.days * 24 * 3600) * 10 ** 6) / 10 ** 6