Salome HOME
Revert "Synchronize adm files"
[modules/kernel.git] / src / KERNEL_PY / kernel / logger.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
4 #
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, or (at your option) any later version.
9 #
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.
14 #
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
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21
22 #=============================================================================
23 #  Author    : Guillaume Boulant (CSSI)
24 #  Rewritten by Renaud Barate (EDF R&D)
25 #  Project   : SALOME
26 #  Copyright : EDF 2001-2009
27 #  $Header$
28 #=============================================================================
29
30 ## \defgroup logger logger
31 #  \{ 
32 #  \details
33 #  This module defines a class which provides logging facility in Salome.
34 #  \}
35
36 """
37 This module defines a class which provides logging facility in Salome:
38 """
39
40 import sys, os
41 import logging
42
43 from salome.kernel.deprecation import deprecated
44 from salome.kernel import termcolor
45 import salome.kernel.logconfig
46
47 ## This class formats and displays log messages in Salome environment. It
48 #  inherits \b logging.Logger class defined in \b logging module from Python 
49 #  library, so all methods from \b logging.Logger can be used here. 
50 #  The format of the traces is:
51 #  LEVEL[keyword] : Message  
52 #  
53 #  ,where \em LEVEL is the level of the message (\em DEBUG, \em INFO, etc.),
54 #  \em keyword is the name of the logger, and \em Message is the message to log.
55 #    
56 #  When creating a new Logger object, the parameter \em keyword defines the
57 #  name of the logger, \em level defines the logging level (default is
58 #  \b logging.DEBUG if KERNEL module is configured with --enable-debug option 
59 #  or \b logging.WARNING otherwise), and \em color defines the color
60 #  of the log messages for this logger (log messages will appear in color
61 #  only when displayed on color - capable ASCII terminals). See module
62 #  \ref termcolor "salome.kernel.termcolor" for the color constants.
63 #    
64 #  By default, log messages will be displayed only on standard output. They
65 #  can also be recorded in a file (see method setLogFile()). For now,
66 #  the CORBA-based logging facility can not be used through this class.
67 #
68 #  A source filename \em sourceFileName can be defined. If this argument is
69 #  specified, then the \em keyword is modified to the basename of the 
70 #  \em sourceFileName
71 #    
72 #  Basic usage::
73 #  \code    
74 #  from salome.kernel.logger import Logger
75 #  log = Logger("Test")
76 #  log.debug("Debug message")
77 #  log.info("Information message")
78 #  log.warning("Warning message")
79 #  log.error("Error message")
80 #  log.critical("Fatal error message")
81 #  \endcode
82 #  \ingroup logger
83 class Logger(logging.Logger):
84     """
85     This class formats and displays log messages in Salome environment. It
86     inherits :class:`Logger<logging.Logger>` class defined in :mod:`logging`
87     module from Python library, so all methods from :class:`logging.Logger`
88     can be used here. The format of the traces is:
89     
90     LEVEL    [keyword] : Message
91     
92     where `LEVEL` is the level of the message (`DEBUG`, `INFO`, etc.),
93     `keyword` is the name of the logger, and `Message` is the message to log.
94     
95     When creating a new Logger object, the parameter `keyword` defines the
96     name of the logger, `level` defines the logging level (default is
97     :const:`logging.DEBUG` if KERNEL module is configured with --enable-debug
98     option or :const:`logging.WARNING` otherwise), and `color` defines the color
99     of the log messages for this logger (log messages will appear in color
100     only when displayed on color-capable ASCII terminals). See module
101     :mod:`salome.kernel.termcolor` for the color constants.
102     
103     By default, log messages will be displayed only on standard output. They
104     can also be recorded in a file (see method :meth:`setLogFile`). For now,
105     the CORBA-based logging facility can not be used through this class.
106
107     A source filename `sourceFileName` can be defined. If this argument is
108     specified, then the `keyword` is modified to the basename of the `sourceFileName`
109     
110     Basic usage::
111     
112         from salome.kernel.logger import Logger
113         log = Logger("Test")
114         log.debug("Debug message")
115         log.info("Information message")
116         log.warning("Warning message")
117         log.error("Error message")
118         log.critical("Fatal error message")
119
120     """
121
122     def __init__(self, keyword = "KEY", level = salome.kernel.logconfig.loggingLevel,
123                  color = None, sourceFileName=None):
124
125         if sourceFileName is not None:
126             keyword = os.path.basename(sourceFileName).split('.')[0]
127         logging.Logger.__init__(self, keyword, level)
128         self._baseFormatString = "%(levelname)-8s [%(name)s] : %(message)s"
129         self._baseFormatter = logging.Formatter(self._baseFormatString)
130         if hasattr(sys.stdout, "flush"):
131             self._stdoutStream = sys.stdout
132         else:
133             self._stdoutStream = _UnFlushableLogStream(sys.stdout)
134         self._stdoutHandler = logging.StreamHandler(self._stdoutStream)
135         self._stdoutHandler.setLevel(logging.DEBUG)
136         self.setColor(color)
137         self.addHandler(self._stdoutHandler)
138         self._fileHandler = None
139
140     ## Log all messages, including DEBUG level messages (equivalent to
141     #  setLevel(logging.DEBUG)).
142     def showDebug(self):
143         """
144         Log all messages, including DEBUG level messages (equivalent to
145         ``setLevel(logging.DEBUG)``).
146         """
147         self.setLevel(logging.DEBUG)
148
149     ## Define a log file to record the log messages (in addition to the
150     #  standard output).
151     def setLogFile(self, logFilename):
152         """
153         Define a log file to record the log messages (in addition to the
154         standard output).
155         """
156         self.closeLogFile()
157         self._fileHandler = logging.FileHandler(logFilename, 'w')
158         self._fileHandler.setLevel(logging.DEBUG)
159         self._fileHandler.setFormatter(self._baseFormatter)
160         self.addHandler(self._fileHandler)
161
162     ## Set the color of log messages on color-capable terminals. If \em color
163     #  is \b None, the default color will be used.
164     def setColor(self, color):
165         """
166         Set the color of log messages on color-capable terminals. If `color`
167         is :const:`None`, the default color will be used.
168         """
169         if color is None or not termcolor.canDisplayColor(self._stdoutStream):
170             stdoutFormatter = self._baseFormatter
171         else:
172             format = ("%s%s%s" %
173                       (termcolor.getControlSequence(color),
174                        self._baseFormatString,
175                        termcolor.getControlSequence(termcolor.DEFAULT)))
176             stdoutFormatter = logging.Formatter(format)
177         self._stdoutHandler.setFormatter(stdoutFormatter)
178
179     ## Close the log file.
180     def closeLogFile(self):
181         """Close the log file."""
182         if self._fileHandler is not None:
183             self.removeHandler(self._fileHandler)
184             self._fileHandler.close()
185             self._fileHandler = None
186
187     ## Hide DEBUG level messages (equivalent to setLevel(logging.INFO)).
188     def hideDebug(self):
189         """
190         Hide DEBUG level messages (equivalent to ``setLevel(logging.INFO)``).
191         """
192         self.setLevel(logging.INFO)
193
194     @deprecated("Deprecated since version 5.1.5. Please replace with "
195                 "Logger.critical(message)")
196     
197     ## Log a message with CRITICAL level. This method only exists for
198     #  backward compatibility and is equivalent to \b critical(message).
199     def fatal(self, message):
200         """
201         Log a message with CRITICAL level. This method only exists for
202         backward compatibility and is equivalent to ``critical(message)``.
203         """
204         self.critical(message)
205
206 ## This utility class allows to log messages to a stream with no \b flush
207 #  method. This is useful to send log messages to \b PyOut objects.
208 #  \ingroup logger
209 class _UnFlushableLogStream:
210     """
211     This utility class allows to log messages to a stream with no `flush`
212     method. This is useful to send log messages to `PyOut` objects.
213     """
214
215     def __init__(self, stream):
216         self._stream = stream
217
218     def write(self, msg):
219         self._stream.write(msg)
220
221     def flush(self):
222         pass
223
224 ## This class extends Logger class and adds exception information
225 #  when DEBUG messages are recorded. It exists mainly for backward
226 #  compatibility, as the same thing can be done by calling
227 #  <em> Logger.debug(message, exc_info = True) </em>.
228 #  \ingroup logger
229 class ExtLogger(Logger):
230     """
231     This class extends :class:`Logger` class and adds exception information
232     when DEBUG messages are recorded. It exists mainly for backward
233     compatibility, as the same thing can be done by calling
234     ``Logger.debug(message, exc_info = True)``.
235     """
236     
237     @deprecated("Class ExtLogger is deprecated since version 5.1.5. See "
238                 "documentation for replacement.")
239     def __init__(self, keyword = "KEY",
240                  level = salome.kernel.logconfig.loggingLevel,
241                  color = None, sourceFileName=None):
242         Logger.__init__(self, keyword, level, color, sourceFileName)
243
244     ## Log a DEBUG message with exception information (equivalent to
245     #  <em> Logger.debug(message, exc_info = True) </em>).
246     def debug( self, message ):
247         """
248         Log a DEBUG message with exception information (equivalent to
249         ``Logger.debug(message, exc_info = True)``).
250         """
251         Logger.debug(self, message, exc_info = True)
252
253 ## Test function for logger module
254 #  \ingroup logger
255 def TEST_Logger():
256     """Test function for logger module"""
257     log = Logger("TST")
258
259     # Base methods
260     log.info("Information message")
261     log.debug("Debug message")
262     log.fatal("Fatal error message")
263
264     # Message building
265     data = 12
266     log.info("This message displays data = " + str(data))
267
268     data = {}
269     data["KERNEL"] = "V1"
270     data["GEOM"] = "V2"
271     log.info("This message displays data = " + str(data))
272
273     # Test with a non-string parameter
274     log.info(data)
275
276     # Test with a default instance
277     log = Logger()
278     log.info("Default logger")
279
280     # Test showDebug method
281     log.setLogFile("test.log")
282     log.debug("Debug trace")
283     log.hideDebug()
284     log.debug("This trace should NOT be displayed")
285     log.showDebug()
286     log.debug("This trace should be displayed")
287     log.closeLogFile()
288     log.info("After closing the log file")
289
290
291 # Main function only used to test the module
292 if __name__ == "__main__":
293     TEST_Logger()