]> SALOME platform Git repositories - tools/eficas.git/blob - Noyau/N_info.py
Salome HOME
Modif V6_4_°
[tools/eficas.git] / Noyau / N_info.py
1 #@ MODIF N_info Noyau  DATE 17/08/2011   AUTEUR COURTOIS M.COURTOIS 
2 # -*- coding: iso-8859-1 -*-
3 #            CONFIGURATION MANAGEMENT OF EDF VERSION
4 # ======================================================================
5 # COPYRIGHT (C) 1991 - 2011  EDF R&D                  WWW.CODE-ASTER.ORG
6 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
7 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
8 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
9 # (AT YOUR OPTION) ANY LATER VERSION.
10 #
11 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
12 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
13 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
14 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
15 #
16 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
17 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
18 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
19 # ======================================================================
20 # RESPONSABLE COURTOIS M.COURTOIS
21
22 """Module to manage information printing : debug, info, error.
23 Should replace 'print' and 'UTMESS' calls at least in the supervisor
24 modules.
25 Only used for debug right now.
26 """
27
28 import os
29 import os.path as osp
30 import re
31 import traceback
32 from functools import partial
33 from subprocess import Popen, PIPE
34
35 from N_utils import Enum
36
37 def default_print(text):
38     """Basic print function."""
39     print text
40
41 LEVEL = Enum(
42     'DEBUG',
43     'INFO',
44     'WARN',
45     'ERROR'
46 )
47
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."""
51     def __init__(self):
52         self._level = LEVEL.INFO
53         self._fmt = "%-8s"
54         self._header = {
55             LEVEL.DEBUG : "DEBUG",
56             LEVEL.INFO : None,
57             LEVEL.WARN : "WARNING",
58             LEVEL.ERROR : "ERROR",
59         }
60
61     def set_level(self, level):
62         """Set the current level."""
63         self._level = level
64
65     def get_level(self):
66         """Return the current level."""
67         return self._level
68
69     def set_header(self, level, header):
70         """Set the header of ``level`` messages."""
71         self._header[level] = header
72
73     def get_header(self, level):
74         """Return the header at this ``level``."""
75         header = self._header.get(level, "")
76         if header:
77             header = self._fmt % header
78         return header
79
80     def active(self, level):
81         """Tell if a message should be print at this ``level``."""
82         return self._level <= level
83
84
85 ALL = Category()
86 SUPERV = Category()
87 SUPERV.set_header(LEVEL.ERROR, None)
88 MISS = Category()
89
90 REGEXP_ORIG = re.compile('File [\'\"]*(.*?)[\'\"]*, *line ([0-9]+), *in (.*)')
91
92 # slighty different and very simplier than logger objects
93 # from the logging module.
94 class InfoLevel(object):
95     """Store informations level."""
96     def __init__(self, level):
97         """Initialization"""
98         self._parts = []
99         for part in self._parts:
100             part.level = level
101         self.reset_print_function()
102         self._msg_callback = []
103         #self.extend_message(ALL, stack_header_callback)
104         self.extend_message(ALL, insert_header)
105
106     def add(self, category):
107         """Add a category of message."""
108         self._parts.append(category)
109
110     def set_level(self, category, level):
111         """Set the current level for ``category``."""
112         assert category in self._parts, "unknown category : %s" % category
113         assert LEVEL.exists(level), "unknown level : %s" % level
114         category.set_level(level)
115         if category == ALL:
116             for part in self._parts:
117                 part.set_level(level)
118
119     def set_debug(self):
120         """Set debug level for all categories."""
121         self.set_level(ALL, LEVEL.DEBUG)
122
123     def set_header(self, category, level, header):
124         """Set the header of ``level`` messages."""
125         category.set_header(level, header)
126
127     def register_print_function(self, print_function):
128         """Define the `print_function` to use."""
129         self._print = print_function
130
131     def reset_print_function(self):
132         """Register the default 'print function'."""
133         self._print = default_print
134
135     def extend_message(self, category, callback):
136         """Allow to extend the message calling an external function."""
137         self._msg_callback.append((category, callback))
138
139     def _message(self, category, level, msg, args, kwargs):
140         """Print the message if the level is reached."""
141         if category.active(level):
142             if kwargs.get('utmess'):
143                 func = self._message_utmess
144             else:
145                 func = self._message_print
146             func = self._message_print
147             apply(func, (category, level, msg, args, kwargs))
148
149     def _message_print(self, category, level, msg, args, kwargs):
150         """Print the message if the level is reached."""
151         for cat, cbk in self._msg_callback:
152             if cat in (ALL, category):
153                 msg, args = cbk(category, level, msg, args, kwargs)
154         if len(args) > 0:
155             try:
156                 msg = msg % args
157             except Exception, err:
158                 msg = repr((msg, args, err))
159         self._print(msg)
160
161     def _message_utmess(self, category, level, msg, args, kwargs):
162         """Print the message if the level is reached."""
163         # how to use callbacks ? valk ?
164         from Utilitai.Utmess import MessageLog
165         code = {
166             LEVEL.DEBUG : 'I',
167             LEVEL.INFO : 'I',
168             LEVEL.WARN : 'A',
169             LEVEL.ERROR : 'F',
170         }
171         valk = kwargs.get('valk', ())
172         vali = kwargs.get('vali', ())
173         valr = kwargs.get('valr', ())
174         msg = MessageLog.GetText(code[level], msg, valk, vali, valr)
175         for cat, cbk in self._msg_callback:
176             if cat in (ALL, category):
177                 msg, args = cbk(category, level, msg, args, kwargs)
178         self._print(msg)
179
180     def debug(self, category, msg, *args, **kwargs):
181         """Print a debug message."""
182         self._message(category or ALL, LEVEL.DEBUG, msg, args, kwargs)
183
184     def info(self, category, msg, *args, **kwargs):
185         """Print an information message."""
186         self._message(category or ALL, LEVEL.INFO, msg, args, kwargs)
187
188     def warn(self, category, msg, *args, **kwargs):
189         """Print a warning message."""
190         self._message(category or ALL, LEVEL.WARN, msg, args, kwargs)
191
192     def error(self, category, msg, *args, **kwargs):
193         """Print an error message."""
194         self._message(category or ALL, LEVEL.ERROR, msg, args, kwargs)
195
196     critical = error
197
198     def add_memory_info(self, category):
199         """Shortcut to add memory informations."""
200         self.extend_message(category, mem_msg_callback)
201
202     def use_aster_print(self):
203         """Shortcut to use aster.affiche function to print the messages."""
204         import aster
205         self.register_print_function(partial(aster.affiche, 'MESSAGE'))
206
207
208 # defined extensions
209 def insert_header(category, level, msg, args, kwargs):
210     """Insert the header."""
211     header = category.get_header(level)
212     if header:
213         msg = header + msg
214     return msg, args
215
216 def stack_header_callback(category, level, msg, args, kwargs):
217     """To insert the origin."""
218     if level <= LEVEL.DEBUG:
219         stack_id = -5 + kwargs.get('stack_id', 0)
220         stack = traceback.format_stack(limit=10)[stack_id]
221         mat = REGEXP_ORIG.search(stack)
222         origin = '[%s:%s in %s] ' % (osp.basename(mat.group(1)), mat.group(2), mat.group(3))
223         msg = origin + msg
224     return msg, args
225
226
227 # objet singleton
228 message = InfoLevel(LEVEL.INFO)
229 message.add(ALL)
230 message.add(SUPERV)
231 message.add(MISS)
232
233 # callback to add memory information
234 _pid = os.getpid()
235
236 RE_VMPEAK = re.compile('VmPeak:\s*([0-9]+)\s*([kMGBo]+)', re.M | re.I)
237
238 def memory_used(pid):
239     """Return the current VmPeak value."""
240     p = Popen(['cat', '/proc/%s/status' % pid], stdout=PIPE)
241     output = p.communicate()[0]
242     mat = RE_VMPEAK.search(output)
243     return int(mat.group(1)) / 1024.
244
245 current_memory_used = partial(memory_used, _pid)
246
247 def mem_msg_callback(category, level, msg, args, kwargs):
248     """Callback to add memory infos to message."""
249     if level <= LEVEL.DEBUG:
250         msg = msg + " - VmPeak : %.2f Mo"
251         args = tuple(list(args) + [current_memory_used(), ])
252     return msg, args
253
254
255 if __name__ == "__main__":
256     message.set_level(SUPERV, LEVEL.WARN)
257     message.set_level(MISS, LEVEL.DEBUG)
258     message.debug(None, "debug message")
259     message.info(ALL, "information message")
260     message.warn(None, "warning message")
261     message.error(ALL, "error message")
262     message.add_memory_info()
263     message.debug(MISS, "debug supervisor message")
264     message.info(SUPERV, "information supervisor message")
265     message.warn(SUPERV, "warning supervisor message")
266     message.error(SUPERV, "error supervisor message")
267     message.critical(MISS, "test the critical alias")
268
269