Salome HOME
Minor source update for OM compatibility
[modules/adao.git] / src / daComposant / daCore / ExtendedLogging.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2008-2024 EDF R&D
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.
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 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
22
23 """
24     Ce module permet de mettre en place un logging utilisable partout dans
25     l'application, par défaut à la console, et si nécessaire dans un fichier.
26
27     Il doit être appelé en premier dans Aidsm (mais pas directement dans les
28     applications utilisateurs), en l'important et en instanciant un objet :
29         import ExtendedLogging ; ExtendedLogging.ExtendedLogging()
30
31     Par défaut, seuls les messages du niveau WARNING ou au-delà sont disponibles
32     (donc les simples messages d'info ne sont pas disponibles), ce que l'on peut
33     changer à l'instanciation avec le mot-clé "level" :
34         import ExtendedLogging ; ExtendedLogging.ExtendedLogging(level=20)
35
36     On peut éventuellement demander à l'objet de sortir aussi les messages dans
37     un fichier (noms par défaut : AdaoOutputLogfile.log, niveau NOTSET) :
38         import ExtendedLogging ; ExtendedLogging.ExtendedLogging().setLogfile()
39
40     Si on veut changer le nom du fichier ou le niveau global de message, il faut
41     récupérer l'instance et appliquer les méthodes :
42         import ExtendedLogging
43         log = ExtendedLogging.ExtendedLogging()
44         import logging
45         log.setLevel(logging.DEBUG)
46         log.setLogfile(filename="toto.log", filemode="a", level=logging.WARNING)
47     et on change éventuellement le niveau avec :
48         log.setLogfileLevel(logging.INFO)
49
50     Ensuite, n'importe où dans les applications, il suffit d'utiliser le module
51     "logging" (avec un petit "l") :
52         import logging
53         log = logging.getLogger(NAME) # Avec rien (recommandé) ou un nom NAME
54         log.critical("...")
55         log.error("...")
56         log.warning("...")
57         log.info("...")
58         log.debug("...")
59     ou encore plus simplement :
60         import logging
61         logging.info("...")
62
63     Dans une application, à n'importe quel endroit et autant de fois qu'on veut,
64     on peut changer le niveau global de message en utilisant par exemple :
65         import logging
66         log = logging.getLogger(NAME) # Avec rien (recommandé) ou un nom NAME
67         log.setLevel(logging.DEBUG)
68
69     On rappelle les niveaux (attributs de "logging") et leur ordre :
70         NOTSET=0 < DEBUG=10 < INFO=20 < WARNING=30 < ERROR=40 < CRITICAL=50
71 """
72 __author__ = "Jean-Philippe ARGAUD"
73 __all__ = []
74
75 import os
76 import sys
77 import logging
78 import functools
79 import time
80 from daCore import PlatformInfo
81
82 LOGFILE = os.path.join(os.path.abspath(os.curdir), "AdaoOutputLogfile.log")
83
84 # ==============================================================================
85 class ExtendedLogging(object):
86     """
87     Logger général pour disposer conjointement de la sortie standard et de la
88     sortie sur fichier
89     """
90     __slots__ = ("__logfile")
91
92     def __init__(self, level=logging.WARNING):
93         """
94         Initialise un logging à la console pour TOUS les niveaux de messages.
95         """
96         if sys.version_info.major <= 3 and sys.version_info.minor < 8:
97             if logging.getLogger().hasHandlers():
98                 while logging.getLogger().hasHandlers():
99                     logging.getLogger().removeHandler( logging.getLogger().handlers[-1] )
100                 __sys_stdout = logging.StreamHandler(sys.stdout)
101                 __sys_stdout.setFormatter(logging.Formatter('%(levelname)-8s %(message)s'))
102                 logging.getLogger().addHandler(__sys_stdout)
103             else:
104                 logging.basicConfig(
105                     format = '%(levelname)-8s %(message)s',
106                     level  = level,
107                     stream = sys.stdout,
108                 )
109         else:  # Actif lorsque Python > 3.7
110             logging.basicConfig(
111                 format = '%(levelname)-8s %(message)s',
112                 level  = level,
113                 stream = sys.stdout,
114                 force  = True,
115             )
116         self.__logfile = None
117         #
118         # Initialise l'affichage de logging
119         # ---------------------------------
120         lpi = PlatformInfo.PlatformInfo()
121         #
122         logging.info( "--------------------------------------------------" )
123         logging.info( lpi.getName() + " version " + lpi.getVersion() )
124         logging.info( "--------------------------------------------------" )
125         logging.info( "Library availability:" )
126         logging.info( "- Python.......: True" )
127         logging.info( "- Numpy........: " + str(lpi.has_numpy) )
128         logging.info( "- Scipy........: " + str(lpi.has_scipy) )
129         logging.info( "- Matplotlib...: " + str(lpi.has_matplotlib) )
130         logging.info( "- Gnuplot......: " + str(lpi.has_gnuplot) )
131         logging.info( "- Sphinx.......: " + str(lpi.has_sphinx) )
132         logging.info( "- Nlopt........: " + str(lpi.has_nlopt) )
133         logging.info( "Library versions:" )
134         logging.info( "- Python.......: " + lpi.getPythonVersion() )
135         logging.info( "- Numpy........: " + lpi.getNumpyVersion() )
136         logging.info( "- Scipy........: " + lpi.getScipyVersion() )
137         logging.info( "- Matplotlib...: " + lpi.getMatplotlibVersion() )
138         logging.info( "- Gnuplot......: " + lpi.getGnuplotVersion() )
139         logging.info( "- Sphinx.......: " + lpi.getSphinxVersion() )
140         logging.info( "- Nlopt........: " + lpi.getNloptVersion() )
141         logging.info( "" )
142
143     def setLogfile(self, filename=LOGFILE, filemode="w", level=logging.NOTSET):
144         """
145         Permet de disposer des messages dans un fichier EN PLUS de la console.
146         """
147         if self.__logfile is not None:
148             # Supprime le précédent mode de stockage fichier s'il existait
149             logging.getLogger().removeHandler(self.__logfile)
150         self.__logfile = logging.FileHandler(filename, filemode)
151         self.__logfile.setLevel(level)
152         self.__logfile.setFormatter(
153             logging.Formatter('%(asctime)s %(levelname)-8s %(message)s',
154                               '%d %b %Y %H:%M:%S'))
155         logging.getLogger().addHandler(self.__logfile)
156
157     def setLogfileLevel(self, level=logging.NOTSET ):
158         """
159         Permet de changer le niveau des messages stockés en fichier. Il ne sera
160         pris en compte que s'il est supérieur au niveau global.
161         """
162         self.__logfile.setLevel(level)
163
164     def getLevel(self):
165         """
166         Renvoie le niveau de logging sous forme texte
167         """
168         return logging.getLevelName( logging.getLogger().getEffectiveLevel() )
169
170 # ==============================================================================
171 def logtimer(f):
172     @functools.wraps(f)
173     def wrapper(*args, **kwargs):
174         start  = time.clock()  # time.time()
175         result = f(*args, **kwargs)
176         end    = time.clock()  # time.time()
177         msg    = 'TIMER Durée elapsed de la fonction utilisateur "{}": {:.3f}s'
178         logging.debug(msg.format(f.__name__, end - start))
179         return result
180     return wrapper
181
182 # ==============================================================================
183 if __name__ == "__main__":
184     print("\n AUTODIAGNOSTIC\n")