1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2007-2013 EDF R&D
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 """Module to manage information printing : debug, info, error.
22 Should replace 'print' and 'UTMESS' calls at least in the supervisor
24 Only used for debug right now.
31 from functools import partial
32 from subprocess import Popen, PIPE
34 from N_utils import Enum, Singleton
35 from strfunc import convert
37 def default_print(text):
38 """Basic print function."""
48 class Category(object):
49 """Define a category of message for different parts of the code.
50 This allows to store different parameters for each category of message."""
52 self._level = LEVEL.INFO
55 LEVEL.DEBUG : "DEBUG",
57 LEVEL.WARN : "WARNING",
58 LEVEL.ERROR : "ERROR",
61 def set_level(self, level):
62 """Set the current level."""
66 """Return the current level."""
69 def set_header(self, level, header):
70 """Set the header of ``level`` messages."""
71 self._header[level] = header
73 def get_header(self, level):
74 """Return the header at this ``level``."""
75 header = self._header.get(level, "")
77 header = self._fmt % header
80 def active(self, level):
81 """Tell if a message should be print at this ``level``."""
82 return self._level <= level
87 SUPERV.set_header(LEVEL.ERROR, None)
90 REGEXP_ORIG = re.compile('File [\'\"]*(.*?)[\'\"]*, *line ([0-9]+), *in (.*)')
92 # slighty different and very simplier than logger objects
93 # from the logging module.
94 class InfoLevel(Singleton):
95 """Store informations level."""
96 _singleton_id = 'N_info.InfoLevel'
98 def __init__(self, level):
101 for part in self._parts:
103 self.reset_print_function()
104 self._msg_callback = []
105 #self.extend_message(ALL, stack_header_callback)
106 self.extend_message(ALL, insert_header)
108 def add(self, category):
109 """Add a category of message."""
110 self._parts.append(category)
112 def set_level(self, category, level):
113 """Set the current level for ``category``."""
114 assert category in self._parts, "unknown category : %s" % category
115 assert LEVEL.exists(level), "unknown level : %s" % level
116 category.set_level(level)
118 for part in self._parts:
119 part.set_level(level)
122 """Set debug level for all categories."""
123 self.set_level(ALL, LEVEL.DEBUG)
125 def set_header(self, category, level, header):
126 """Set the header of ``level`` messages."""
127 category.set_header(level, header)
129 def register_print_function(self, print_function):
130 """Define the `print_function` to use."""
131 self._print = print_function
133 def reset_print_function(self):
134 """Register the default 'print function'."""
135 self._print = default_print
137 def extend_message(self, category, callback):
138 """Allow to extend the message calling an external function."""
139 self._msg_callback.append((category, callback))
141 def _message(self, category, level, msg, args, kwargs):
142 """Print the message if the level is reached."""
143 if category.active(level):
144 if kwargs.get('utmess'):
145 func = self._message_utmess
147 func = self._message_print
148 func = self._message_print
149 apply(func, (category, level, msg, args, kwargs))
151 def _message_print(self, category, level, msg, args, kwargs):
152 """Print the message if the level is reached."""
153 for cat, cbk in self._msg_callback:
154 if cat in (ALL, category):
155 msg, args = cbk(category, level, msg, args, kwargs)
159 except Exception, err:
160 msg = repr((msg, args, err))
163 def _message_utmess(self, category, level, msg, args, kwargs):
164 """Print the message if the level is reached."""
165 # how to use callbacks ? valk ?
166 from Utilitai.Utmess import MessageLog
173 valk = kwargs.get('valk', ())
174 vali = kwargs.get('vali', ())
175 valr = kwargs.get('valr', ())
176 msg = MessageLog.GetText(code[level], msg, valk, vali, valr)
177 for cat, cbk in self._msg_callback:
178 if cat in (ALL, category):
179 msg, args = cbk(category, level, msg, args, kwargs)
182 def debug(self, category, msg, *args, **kwargs):
183 """Print a debug message."""
184 self._message(category or ALL, LEVEL.DEBUG, msg, args, kwargs)
186 def info(self, category, msg, *args, **kwargs):
187 """Print an information message."""
188 self._message(category or ALL, LEVEL.INFO, msg, args, kwargs)
190 def warn(self, category, msg, *args, **kwargs):
191 """Print a warning message."""
192 self._message(category or ALL, LEVEL.WARN, msg, args, kwargs)
194 def error(self, category, msg, *args, **kwargs):
195 """Print an error message."""
196 self._message(category or ALL, LEVEL.ERROR, msg, args, kwargs)
200 def add_memory_info(self, category):
201 """Shortcut to add memory informations."""
202 self.extend_message(category, mem_msg_callback)
204 def use_aster_print(self):
205 """Shortcut to use aster.affiche function to print the messages."""
207 self.register_print_function(partial(aster.affiche, 'MESSAGE'))
211 def insert_header(category, level, msg, args, kwargs):
212 """Insert the header."""
213 header = category.get_header(level)
218 def stack_header_callback(category, level, msg, args, kwargs):
219 """To insert the origin."""
220 if level <= LEVEL.DEBUG:
221 stack_id = -5 + kwargs.get('stack_id', 0)
222 stack = traceback.format_stack(limit=10)[stack_id]
223 mat = REGEXP_ORIG.search(stack)
224 origin = '[%s:%s in %s] ' % (osp.basename(mat.group(1)), mat.group(2), mat.group(3))
230 message = InfoLevel(LEVEL.INFO)
235 # callback to add memory information
238 RE_VMPEAK = re.compile('VmPeak:\s*([0-9]+)\s*([kMGBo]+)', re.M | re.I)
240 def memory_used(pid):
241 """Return the current VmPeak value."""
242 p = Popen(['cat', '/proc/%s/status' % pid], stdout=PIPE)
243 output = p.communicate()[0]
244 mat = RE_VMPEAK.search(output)
245 mem = mat and int(mat.group(1)) or 0.
248 current_memory_used = partial(memory_used, _pid)
250 def mem_msg_callback(category, level, msg, args, kwargs):
251 """Callback to add memory infos to message."""
252 if level <= LEVEL.DEBUG:
253 msg = msg + " - VmPeak : %.2f Mo"
254 args = tuple(list(args) + [current_memory_used(), ])
258 if __name__ == "__main__":
259 message.set_level(SUPERV, LEVEL.WARN)
260 message.set_level(MISS, LEVEL.DEBUG)
261 #message.debug(None, "debug message")
262 message.info(ALL, "information message")
263 message.warn(None, "warning message")
264 message.error(ALL, "error message")
265 message.add_memory_info()
266 #message.debug(MISS, "debug supervisor message")
267 message.info(SUPERV, "information supervisor message")
268 message.warn(SUPERV, "warning supervisor message")
269 message.error(SUPERV, "error supervisor message")
270 message.critical(MISS, "test the critical alias")