loggi.logger
1import logging 2 3from pathier import Pathier, Pathish 4 5from loggi import models 6 7root = Pathier(__file__).parent 8 9 10class Logger(logging.Logger): 11 @property 12 def logpath(self) -> Pathier | None: 13 """Return a file handler path whose stem matches `self.name`, if there is one.""" 14 for path in self.logpaths: 15 if path.stem == self.name: 16 return path 17 18 @property 19 def logpaths(self) -> list[Pathier]: 20 """A list of `Pathier` objects for any file handlers attached to this `Logger`.""" 21 return [ 22 Pathier(handler.baseFilename) 23 for handler in self.handlers 24 if isinstance(handler, logging.FileHandler) 25 ] 26 27 def close(self): 28 for handler in self.handlers: 29 self.removeHandler(handler) 30 handler.close() 31 32 def get_log(self) -> models.Log | None: 33 """Returns a `models.Log` object populated from this logger's `logpath`.""" 34 if path := self.logpath: 35 return models.Log.load_log(path) 36 37 def logprint(self, message: str, level: str | int = "INFO"): 38 getattr( 39 self, 40 (level if isinstance(level, str) else logging.getLevelName(level)).lower(), 41 )(message) 42 if self.isEnabledFor( 43 level if isinstance(level, int) else logging.getLevelName(level) 44 ): 45 print(message) 46 47 48def getLogger(name: str, path: Pathish = Pathier.cwd()) -> Logger: 49 """Get a configured `loggi.Logger` instance for `name` with a file handler. 50 51 The log file will be located in `path` at `path/{name}.log`. 52 53 Default level is `INFO`. 54 55 Logs are in the format: `{levelname}|-|{asctime}|-|{message} 56 57 asctime is formatted as `%x %X`""" 58 path = Pathier(path) 59 path.mkdir() 60 # make sure loggi.Logger is the current logger class 61 logging.setLoggerClass(Logger) 62 logger = logging.Logger.manager.getLogger(name) 63 # TODO: Add option for a stream handler 64 # Add file handler using `logger.name` 65 logpath = path / f"{logger.name}.log" 66 handler = logging.FileHandler(logpath, encoding="utf-8") 67 if handler.baseFilename not in [ 68 existing_handler.baseFilename 69 for existing_handler in logger.handlers 70 if isinstance(existing_handler, logging.FileHandler) 71 ]: 72 handler.setFormatter( 73 logging.Formatter( 74 "{levelname}|-|{asctime}|-|{message}", style="{", datefmt="%x %X" 75 ) 76 ) 77 logger.addHandler(handler) 78 logger.setLevel(logging.INFO) 79 return logger # type: ignore 80 81 82def load_log(logpath: Pathish) -> models.Log: 83 """Return a `loggi.models.Log` object for the log file at `logpath`.""" 84 return models.Log.load_log(Pathier(logpath)) 85 86 87# |===================================================| 88# Backwards compatibility with previous loggi versions 89# |===================================================| 90 91 92def get_logpaths(logger: Logger | logging.Logger) -> list[Pathier]: 93 """Loop through the handlers for `logger` and return a list of paths for any handler of type `FileHandler`.""" 94 return [ 95 Pathier(handler.baseFilename) 96 for handler in logger.handlers 97 if isinstance(handler, logging.FileHandler) 98 ] 99 100 101def get_logpath(logger: Logger | logging.Logger) -> Pathier | None: 102 """Search `logger.handlers` for a `FileHandler` that has a file stem matching `logger.name`. 103 104 Returns `None` if not found.""" 105 for path in get_logpaths(logger): 106 if path.stem == logger.name: 107 return path 108 109 110def get_log(logger: Logger | logging.Logger) -> models.Log | None: 111 """Find the corresponding log file for `logger`, load it into a `models.Log` instance, and then return it. 112 113 Returns `None` if a log file can't be found.""" 114 path = get_logpath(logger) 115 if path: 116 return load_log(path) 117 118 119def close(logger: Logger | logging.Logger): 120 """Removes and closes handlers for `logger`.""" 121 for handler in logger.handlers: 122 logger.removeHandler(handler) 123 handler.close()
11class Logger(logging.Logger): 12 @property 13 def logpath(self) -> Pathier | None: 14 """Return a file handler path whose stem matches `self.name`, if there is one.""" 15 for path in self.logpaths: 16 if path.stem == self.name: 17 return path 18 19 @property 20 def logpaths(self) -> list[Pathier]: 21 """A list of `Pathier` objects for any file handlers attached to this `Logger`.""" 22 return [ 23 Pathier(handler.baseFilename) 24 for handler in self.handlers 25 if isinstance(handler, logging.FileHandler) 26 ] 27 28 def close(self): 29 for handler in self.handlers: 30 self.removeHandler(handler) 31 handler.close() 32 33 def get_log(self) -> models.Log | None: 34 """Returns a `models.Log` object populated from this logger's `logpath`.""" 35 if path := self.logpath: 36 return models.Log.load_log(path) 37 38 def logprint(self, message: str, level: str | int = "INFO"): 39 getattr( 40 self, 41 (level if isinstance(level, str) else logging.getLevelName(level)).lower(), 42 )(message) 43 if self.isEnabledFor( 44 level if isinstance(level, int) else logging.getLevelName(level) 45 ): 46 print(message)
Instances of the Logger class represent a single logging channel. A "logging channel" indicates an area of an application. Exactly how an "area" is defined is up to the application developer. Since an application can have any number of areas, logging channels are identified by a unique string. Application areas can be nested (e.g. an area of "input processing" might include sub-areas "read CSV files", "read XLS files" and "read Gnumeric files"). To cater for this natural nesting, channel names are organized into a namespace hierarchy where levels are separated by periods, much like the Java or Python package namespace. So in the instance given above, channel names might be "input" for the upper level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels. There is no arbitrary limit to the depth of nesting.
Return a file handler path whose stem matches self.name
, if there is one.
A list of Pathier
objects for any file handlers attached to this Logger
.
33 def get_log(self) -> models.Log | None: 34 """Returns a `models.Log` object populated from this logger's `logpath`.""" 35 if path := self.logpath: 36 return models.Log.load_log(path)
Returns a models.Log
object populated from this logger's logpath
.
Inherited Members
- logging.Logger
- Logger
- setLevel
- debug
- info
- warning
- warn
- error
- exception
- critical
- fatal
- log
- findCaller
- makeRecord
- handle
- addHandler
- removeHandler
- hasHandlers
- callHandlers
- getEffectiveLevel
- isEnabledFor
- getChild
- logging.Filterer
- addFilter
- removeFilter
- filter
49def getLogger(name: str, path: Pathish = Pathier.cwd()) -> Logger: 50 """Get a configured `loggi.Logger` instance for `name` with a file handler. 51 52 The log file will be located in `path` at `path/{name}.log`. 53 54 Default level is `INFO`. 55 56 Logs are in the format: `{levelname}|-|{asctime}|-|{message} 57 58 asctime is formatted as `%x %X`""" 59 path = Pathier(path) 60 path.mkdir() 61 # make sure loggi.Logger is the current logger class 62 logging.setLoggerClass(Logger) 63 logger = logging.Logger.manager.getLogger(name) 64 # TODO: Add option for a stream handler 65 # Add file handler using `logger.name` 66 logpath = path / f"{logger.name}.log" 67 handler = logging.FileHandler(logpath, encoding="utf-8") 68 if handler.baseFilename not in [ 69 existing_handler.baseFilename 70 for existing_handler in logger.handlers 71 if isinstance(existing_handler, logging.FileHandler) 72 ]: 73 handler.setFormatter( 74 logging.Formatter( 75 "{levelname}|-|{asctime}|-|{message}", style="{", datefmt="%x %X" 76 ) 77 ) 78 logger.addHandler(handler) 79 logger.setLevel(logging.INFO) 80 return logger # type: ignore
Get a configured loggi.Logger
instance for name
with a file handler.
The log file will be located in path
at path/{name}.log
.
Default level is INFO
.
Logs are in the format: `{levelname}|-|{asctime}|-|{message}
asctime is formatted as %x %X
83def load_log(logpath: Pathish) -> models.Log: 84 """Return a `loggi.models.Log` object for the log file at `logpath`.""" 85 return models.Log.load_log(Pathier(logpath))
Return a loggi.models.Log
object for the log file at logpath
.
93def get_logpaths(logger: Logger | logging.Logger) -> list[Pathier]: 94 """Loop through the handlers for `logger` and return a list of paths for any handler of type `FileHandler`.""" 95 return [ 96 Pathier(handler.baseFilename) 97 for handler in logger.handlers 98 if isinstance(handler, logging.FileHandler) 99 ]
Loop through the handlers for logger
and return a list of paths for any handler of type FileHandler
.
102def get_logpath(logger: Logger | logging.Logger) -> Pathier | None: 103 """Search `logger.handlers` for a `FileHandler` that has a file stem matching `logger.name`. 104 105 Returns `None` if not found.""" 106 for path in get_logpaths(logger): 107 if path.stem == logger.name: 108 return path
Search logger.handlers
for a FileHandler
that has a file stem matching logger.name
.
Returns None
if not found.
111def get_log(logger: Logger | logging.Logger) -> models.Log | None: 112 """Find the corresponding log file for `logger`, load it into a `models.Log` instance, and then return it. 113 114 Returns `None` if a log file can't be found.""" 115 path = get_logpath(logger) 116 if path: 117 return load_log(path)
Find the corresponding log file for logger
, load it into a models.Log
instance, and then return it.
Returns None
if a log file can't be found.
120def close(logger: Logger | logging.Logger): 121 """Removes and closes handlers for `logger`.""" 122 for handler in logger.handlers: 123 logger.removeHandler(handler) 124 handler.close()
Removes and closes handlers for logger
.