cdxcore 0.1.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cdxcore might be problematic. Click here for more details.

cdxcore/logger.py ADDED
@@ -0,0 +1,319 @@
1
+ """
2
+ Basic log file logic
3
+ """
4
+
5
+ from .util import _fmt, prnt, write
6
+ import sys as sys
7
+ import logging as logging
8
+ import traceback as traceback
9
+ import datetime as datetime
10
+
11
+ _prnt = prnt
12
+ _write = write
13
+
14
+ class Logger(object):
15
+ """
16
+ Simple utility object to decorate loggers, plus:
17
+ - infor, warning, () also accept named argument formatting ie "The error is %(message)self" instead of positional %
18
+ - added Exceptn function which logs an error before returning an exception.
19
+ It also make sure an exception is only tracked once.
20
+ The point of this class is to be able to write
21
+ import base.logger as logger
22
+ _log = logger.getLogger(__file__)
23
+ ...
24
+ _log.verify( some_condition_we_want_met, "Error: cannot find %s", message)
25
+ and it will keep a log of that exception.
26
+
27
+ Exceptions independent of logging level
28
+
29
+ verify( cond, text, *args, **kwargs )
30
+ If cond is not met, raise an exception with util.fmt( text, *args, **kwargs )
31
+
32
+ throw_if(cond, text, *args, **kwargs )
33
+ If cond is met, raise an exception with util.fmt( text, *args, **kwargs )
34
+
35
+ throw( text, *args, **kwargs )
36
+ Raise an exception with fmt( text, *args, **kwargs )
37
+
38
+ Unconditional logging
39
+
40
+ debug( text, *args, **kwargs )
41
+ info( text, *args, **kwargs )
42
+ warning( text, *args, **kwargs )
43
+ error( text, *args, **kwargs )
44
+ debug( text, *args, **kwargs )
45
+
46
+ Conditional logging functions, verify version
47
+
48
+ verify_debug( cond, text, *args, **kwargs )
49
+ verify_info( cond, text, *args, **kwargs )
50
+ verify_warning( cond, text, *args, **kwargs )
51
+
52
+ verify( cond, text, *args, **kwargs )
53
+
54
+ Conditional logging functions, if version
55
+
56
+ debug_if( text, *args, **kwargs )
57
+ info_if( text, *args, **kwargs )
58
+ warning_if( text, *args, **kwargs )
59
+
60
+ throw_if( text, *args, **kwargs )
61
+
62
+ prnt_if( text, *args, **kwargs ) # with EOL
63
+ write_if( text, *args, **kwargs ) # without EOL
64
+ """
65
+
66
+ CRITICAL = logging.CRITICAL
67
+ ERROR = logging.ERROR
68
+ WARNING = logging.WARNING
69
+ INFO = logging.INFO
70
+ DEBUG = logging.DEBUG
71
+ NOTSET = logging.NOTSET
72
+
73
+ def __init__(self,topic : str):
74
+ assert topic !="", "Logger cannot be empty"
75
+ setupAppLogging() # ensure system is ready
76
+ i = topic.rfind('/')
77
+ if i == -1:
78
+ i = topic.rfind('\\')
79
+ if i != -1 and i<len(topic)-1:
80
+ topic = topic[i+1:]
81
+ self.logger = logging.getLogger(topic)
82
+
83
+ # Exception support
84
+ # -----------------
85
+
86
+ class LogException(Exception):
87
+ """ Placeholder exception class we use to identify our own exceptions """
88
+
89
+ def __init__(self,text : str):
90
+ Exception.__init__(self,text)
91
+
92
+ def Exceptn(self, text : str, *args, **kwargs ):
93
+ """
94
+ Returns an exception object with 'text' % kwargs and stores an 'error' message
95
+ If an exception is present, it will be printed, too.
96
+ If the base logger logs 'debug' information, the call stack will be printed as well
97
+
98
+ Usage:
99
+ raise _log.Exceptn("Something happened")
100
+ """
101
+ text = _fmt(text,args,kwargs)
102
+ (typ, val, trc) = sys.exc_info()
103
+
104
+ # are we already throwing our own exception?
105
+ if typ is Logger.LogException:
106
+ return val # --> already logged --> keep raising the exception but don't do anything
107
+
108
+ # new exception?
109
+ if typ is None:
110
+ assert val is None and trc is None, "*** Internal error"
111
+ self.error( text )
112
+ return Logger.LogException("*** LogException: " + text)
113
+
114
+ # another exception is being thrown.
115
+ # we re-cast this as one of our own.
116
+ if text[-1] == ".":
117
+ text = text + " " + str(val)
118
+ else:
119
+ text = text + ". " + str(val)
120
+
121
+ # in debug, add trace information
122
+ if self.logger.getEffectiveLevel() <= logging.WARNING:
123
+ text = text.rstrip()
124
+ txt = traceback.format_exception(typ,val,trc,limit = 100)
125
+ for t in txt:
126
+ text += "\n " + t[:-1]
127
+ self.error( text )
128
+
129
+ # return an exception with the corresponding text
130
+ return Logger.LogException("*** LogException: " + text)
131
+
132
+ # logging() replacemets
133
+ # ---------------------
134
+
135
+ def debug(self, text, *args, **kwargs ):
136
+ """ Reports debug information with new style formatting """
137
+ if self.logger.getEffectiveLevel() <= logging.DEBUG and len(text) > 0:
138
+ self.logger.debug(_fmt(text,args,kwargs))
139
+
140
+ def info(self, text, *args, **kwargs ):
141
+ """ Reports information with new style formatting """
142
+ if self.logger.getEffectiveLevel() <= logging.INFO and len(text) > 0:
143
+ self.logger.info(_fmt(text,args,kwargs))
144
+
145
+ def warning(self, text, *args, **kwargs ):
146
+ """ Reports a warning with new style formatting """
147
+ if self.logger.getEffectiveLevel() <= logging.WARNING and len(text) > 0:
148
+ self.logger.warning(_fmt(text,args,kwargs))
149
+ warn = warning
150
+
151
+ def error(self, text, *args, **kwargs ):
152
+ """ Reports an error with new style formatting """
153
+ if self.logger.getEffectiveLevel() <= logging.ERROR and len(text) > 0:
154
+ self.logger.error(_fmt(text,args,kwargs))
155
+
156
+ def critical(self, text, *args, **kwargs ):
157
+ """ Reports a critial occcurance with new style formatting """
158
+ if self.logger.getEffectiveLevel() <= logging.CRITICAL and len(text) > 0:
159
+ self.logger.critical(_fmt(text,args,kwargs))
160
+
161
+ def throw( self, text, *args, **kwargs ):
162
+ """ Raise an exception """
163
+ raise self.Exceptn(text,*args,**kwargs)
164
+
165
+ @staticmethod
166
+ def prnt( text, *args, **kwargs ):
167
+ """ Simple print, with EOL """
168
+ _prnt(_fmt(text,args,kwargs))
169
+
170
+ @staticmethod
171
+ def write(text, *args, **kwargs ):
172
+ """ Simple print, without EOL """
173
+ _write(_fmt(text,args,kwargs))
174
+
175
+ # run time utilities with validity check
176
+ # --------------------------------------
177
+
178
+ def verify(self, cond, text, *args, **kwargs ):
179
+ """
180
+ Verifies 'cond'. Raises an exception if 'cond' is not met with the specified text.
181
+ Usage:
182
+ _log.verify( i>0, "i must be positive, found %d", i)
183
+ """
184
+ if not cond:
185
+ self.throw(text,*args,**kwargs)
186
+
187
+ def verify_warning(self, cond, text, *args, **kwargs ):
188
+ """
189
+ Verifies 'cond'. If true, writes a warning and then continues
190
+ Usage
191
+ _log.verify_warning( i>0, "i must be positive, found %d", i)
192
+ """
193
+ if not cond:
194
+ self.warning(text, *args, **kwargs )
195
+
196
+ verify_warn = verify_warning
197
+
198
+ def verify_info(self, cond, text, *args, **kwargs ):
199
+ """ Verifies 'cond'. If true, writes log information and then continues """
200
+ if not cond:
201
+ self.info(text, *args, **kwargs )
202
+
203
+ def verify_debug(self, cond, text, *args, **kwargs ):
204
+ """ Verifies 'cond'. If true, writes log debug and then continues """
205
+ if not cond:
206
+ self.debug(text, *args, **kwargs )
207
+
208
+ # if-action
209
+ # ---------
210
+
211
+ def throw_if(self, cond, text, *args, **kwargs ):
212
+ """ Raises an exception if 'cond' is true. This is the reverse of verify() """
213
+ if cond:
214
+ raise self.Exceptn(text,*args,**kwargs)
215
+ raise_if = throw_if
216
+
217
+ def warning_if(self, cond, text, *args, **kwargs ):
218
+ """ If 'cond' is true, writes a warning. Opposite condition than verify_warning """
219
+ if cond:
220
+ self.warning(text,*args,**kwargs)
221
+ warn_if = warning_if
222
+
223
+ def info_if(self, cond, text, *args, **kwargs ):
224
+ """ If 'cond' is true, writes information 'info'. Opposite condition than verify_info """
225
+ if cond:
226
+ self.info(text,*args,**kwargs)
227
+
228
+ def debug_if(self, cond, text, *args, **kwargs ):
229
+ """ If 'cond' is true, writes debug 'info'. Opposite condition than verify_debug """
230
+ if cond:
231
+ self.debug(text,*args,**kwargs)
232
+
233
+ @staticmethod
234
+ def prnt_if(cond, text, *args, **kwargs ):
235
+ """ If 'cond' is True, prnt() text. Python 2.7 """
236
+ if cond:
237
+ Logger.prnt(text,*args,**kwargs)
238
+
239
+ @staticmethod
240
+ def write_if(cond, text, *args, **kwargs ):
241
+ """ If 'cond' is True, prnt() text """
242
+ if cond:
243
+ Logger.write(text,*args,**kwargs)
244
+
245
+ # interface into logging
246
+ # ----------------------
247
+
248
+ def setLevel(self, level):
249
+ """ logging.setLevel """
250
+ self.logger.setLevel(level)
251
+
252
+ def getEffectiveLevel(self):
253
+ """ logging.getEffectiveLevel """
254
+ return self.logger.getEffectiveLevel()
255
+
256
+ # ====================================================================================================
257
+ # setupAppLogging
258
+ # ---------------
259
+ # Defines logging at stderr and file level.
260
+ # ====================================================================================================
261
+
262
+ GLOBAL_LOG_DATA = "cdxbasics.logger"
263
+
264
+ class RootLog(object):
265
+ def __init__(self, root):
266
+ self.handler = root
267
+ self.fileName = None
268
+
269
+ rootLog = RootLog( logging.getLogger() ) # root level logger
270
+
271
+ def setupAppLogging( levelPrint : int = logging.ERROR,
272
+ levelFile : int = None
273
+ ):
274
+ """
275
+ Application wide logging control - basically sets a log file path
276
+ This function will only called once.
277
+ Put this function into your root import
278
+
279
+ Parameters
280
+ ----------
281
+ levelPrint : printing level https://docs.python.org/3/library/logging.html
282
+ levelFile : file level. Set to None to not write to file.
283
+ """
284
+
285
+ data = globals().get(GLOBAL_LOG_DATA,None)
286
+ if data is None:
287
+ # logging for std derror
288
+ logging.basicConfig(level=min(levelPrint,levelFile) if not levelFile is None else levelPrint)
289
+ fmtt = logging.Formatter(fmt="%(asctime)self %(levelname)-10s: %(message)self" )
290
+ stdErr = logging.StreamHandler(sys.stdout)
291
+ stdErr.setLevel(levelPrint )
292
+ rootLog.handler.addHandler( stdErr )
293
+ data = {'strm':stdErr }
294
+
295
+ if not levelFile is None:
296
+ # file system
297
+ import os
298
+ import os.path
299
+ import tempfile
300
+ stamp = datetime.datetime.now().strftime("%Y-%m-%d_%S%M%H")
301
+ pid = os.getpid() # note: process name is 'python.exe'
302
+ tmpDir = tempfile.gettempdir()
303
+ logFile = os.path.join(tmpDir,"py_logger_" + stamp + "_" + str(pid) + ".log")
304
+
305
+ fileE = None
306
+ try:
307
+ fileE = logging.FileHandler(logFile)
308
+ fileE.setFormatter(fmtt)
309
+ fileE.setLevel( levelFile )
310
+ rootLog.handler.addHandler( fileE )
311
+ data = {'strm':stdErr, 'file':fileE, 'logFileName':logFile }
312
+ except:
313
+ pass
314
+
315
+ globals()[GLOBAL_LOG_DATA] = data
316
+
317
+ rootLog.fileName = data.get('logFileName', None)
318
+ return data
319
+