Custom logger based on content from
Logging Cookbook.
Configuration file for the logging module can be provided in the following locations:
- A place named by the environment variable
LOGGA_CONF
- Current directory:
./log.conf
- User's home directory:
~$USER/log.conf
If not found, fallback is Logga's own configuration.
This arrangement is analogous to "rc" files. for example, "bashrc", "vimrc", etc.
autolog(message)
Automatically log the current function details.
Used interchangeably with the log
handler object. Handy for
for verbose messaging during development by adding more verbose detail
to the logging message, such as the calling function/method name
and line number that raised the log call. Will only work at the DEBUG
level:
>>> from logga import autolog, log, set_log_level
>>> set_log_level("DEBUG")
>>> autolog("Verbose")
2023-01-09 10:46:12 logga [DEBUG]: Verbose: autolog in <$HOME>/src/logga/__init__.py
>>> log.debug("DEBUG message")
2023-01-09 10:47:11 logga [DEBUG]: DEBUG message
>>> autolog("DEBUG message")
>>> 2023-01-09 10:47:34 logga [DEBUG]: DEBUG message: autolog in <$HOME>/src/logga/__init__.py
Parameters:
Name |
Type |
Description |
Default |
message |
Text
|
the log message to display |
required
|
Source code in logga/__init__.py
| def autolog(message: Text):
"""Automatically log the current function details.
Used interchangeably with the `log` handler object. Handy for
for verbose messaging during development by adding more verbose detail
to the logging message, such as the calling function/method name
and line number that raised the log call. Will only work at the `DEBUG` level:
```
>>> from logga import autolog, log, set_log_level
>>> set_log_level("DEBUG")
>>> autolog("Verbose")
2023-01-09 10:46:12 logga [DEBUG]: Verbose: autolog in <$HOME>/src/logga/__init__.py
>>> log.debug("DEBUG message")
2023-01-09 10:47:11 logga [DEBUG]: DEBUG message
>>> autolog("DEBUG message")
>>> 2023-01-09 10:47:34 logga [DEBUG]: DEBUG message: autolog in <$HOME>/src/logga/__init__.py
```
Parameters:
message: the log message to display
"""
if log.isEnabledFor(logging.DEBUG):
# Get the previous frame in the stack.
# Otherwise it would be this function!!!
frame: CodeType = cast(FrameType, inspect.currentframe()).f_code
lineno: Union[int, Any] = cast(FrameType, inspect.currentframe()).f_lineno
# Dump the message function details to the log.
log.debug("%s: %s in %s:%i", message, frame.co_name, frame.co_filename, lineno)
|
get_logger_name()
Identify logger name to target handlers.
The calling script will be the outermost call in the stack. Parse the
resulting frame to get the name of the script.
<stdin>
is a special case that will explicitly return None
Returns:
Type |
Description |
Optional[Text]
|
The logger name as a string, or None . |
Source code in logga/__init__.py
| def get_logger_name() -> Optional[Text]:
"""Identify logger name to target handlers.
The calling script will be the outermost call in the stack. Parse the
resulting frame to get the name of the script.
`<stdin>` is a special case that will explicitly return `None`
Returns:
The logger name as a string, or `None`.
"""
_name: Optional[Text] = os.path.basename(inspect.stack()[-1][1])
if _name == "<stdin>":
_name = None
return _name
|
locations()
Provide logging configuration directory locations in order of precedence.
Returns:
Type |
Description |
List[Text]
|
A list of locations as a set of strings that represent the directory location
of the log.conf file. |
Source code in logga/__init__.py
| def locations() -> List[Text]:
"""Provide logging configuration directory locations in order of precedence.
Returns:
A list of locations as a set of strings that represent the directory location
of the `log.conf` file.
"""
def items():
return (os.environ.get("LOGGA_CONF"), os.getcwd(), pathlib.Path.home())
return items()
|
set_console()
Drop back to the root logger handler. This is typically the console.
This can be used to override the logging file output stream and send
log messages to the console. For example, consider the following
code that has a log.conf
that writes to the log file my.log
:
from logga import log, set_console
set_console()
log.debug("Log from inside my Python module")
The set_console()
call will force the log message to write
Log from inside my Python module
to the console.
Source code in logga/__init__.py
| def set_console():
"""Drop back to the root logger handler. This is typically the console.
This can be used to override the logging file output stream and send
log messages to the console. For example, consider the following
code that has a `log.conf` that writes to the log file `my.log`:
```
from logga import log, set_console
set_console()
log.debug("Log from inside my Python module")
```
The `set_console()` call will force the log message to write
`Log from inside my Python module` to the console.
"""
def default_console_config() -> logging.StreamHandler:
"""Default console config that can be used as a fallback.
Returns a logging.StreamHandler configured with a simple format.
"""
console_handler = logging.StreamHandler()
console_formatter = logging.Formatter(
"%(asctime)s [%(levelname)s]:: %(message)s"
)
console_handler.setFormatter(console_formatter)
return console_handler
for hdlr in log.handlers:
log.removeHandler(hdlr)
log.propagate = False
log.addHandler(default_console_config())
log.level = logging.NOTSET
|
set_log_level(level='INFO')
Set the lower threshold of logged message level. Level defaults to `INFO``.
All default log levels are supported (in order of severity):
CRITICAL
ERROR
WARNING
INFO
DEBUG
NOTSET
Example:
>>> from logga import log, set_log_level
>>> log.info("This INFO message should display")
2023-01-09 10:29:04 logga [INFO]: This INFO message should display
>>> log.debug("Not this DEBUG")
>>> set_log_level(level="DEBUG")
>>> log.debug("DEBUG is now good to go")
2023-01-09 10:30:15 logga [DEBUG]: DEBUG is now good to go
Parameters:
Name |
Type |
Description |
Default |
level |
Text
|
the lower log level threshold. All log levels, including and above this level in
serverity, will be logged |
'INFO'
|
Source code in logga/__init__.py
| def set_log_level(level: Text = "INFO"):
"""Set the lower threshold of logged message level. Level defaults to `INFO``.
All default log levels are supported (in order of severity):
- `CRITICAL`
- `ERROR`
- `WARNING`
- `INFO`
- `DEBUG`
- `NOTSET`
Example:
```
>>> from logga import log, set_log_level
>>> log.info("This INFO message should display")
2023-01-09 10:29:04 logga [INFO]: This INFO message should display
>>> log.debug("Not this DEBUG")
>>> set_log_level(level="DEBUG")
>>> log.debug("DEBUG is now good to go")
2023-01-09 10:30:15 logga [DEBUG]: DEBUG is now good to go
```
Parameters:
level: the lower log level threshold. All log levels, including and above this level in
serverity, will be logged
"""
level_map = {
"CRITICAL": logging.INFO,
"ERROR": logging.INFO,
"WARNING": logging.INFO,
"INFO": logging.INFO,
"DEBUG": logging.DEBUG,
"NOTSET": logging.DEBUG,
}
log.setLevel(level_map[level])
|
source_logger_config()
Source logger config.
Will attempt to parse a log.conf
file to feed into logging.config.fileConfig
. Will also
determine the name of the calling script/module and associate that logger name with the
log.conf
.
Returns:
Type |
Description |
Optional[Text]
|
The name of the logger. Fallback, if no log.conf files are found is the logga logger. |
Source code in logga/__init__.py
| def source_logger_config() -> Optional[Text]:
"""Source logger config.
Will attempt to parse a `log.conf` file to feed into `logging.config.fileConfig`. Will also
determine the name of the calling script/module and associate that logger name with the
`log.conf`.
Returns:
The name of the logger. Fallback, if no `log.conf` files are found is the `logga` logger.
"""
config_found = False
for loc in locations():
if loc is None:
continue
try:
with open(os.path.join(loc, "log.conf"), encoding="utf-8") as _fh:
logging.config.fileConfig(_fh)
config_found = True
break
except IOError:
# Not a bad thing if the open failed. Just means that the log
# source does not exist.
continue
logger_name: Optional[Text] = get_logger_name()
if not config_found:
logger_name = "logga"
# If we've fallen through to here, then use Logga's own config.
config_path = os.path.join(
pathlib.Path(__file__).resolve().parents[0], "config", "log.conf"
)
with open(config_path, encoding="utf-8") as _fh:
logging.config.fileConfig(_fh)
return logger_name
|
suppress_logging()
Provides an overriding (to level CRITICAL
) suppression mechanism
for all loggers which takes precedence over the logger`s own level.
This function can be useful when the need arises to temporarily throttle logging output down
across the whole application.
Technically, this function will disable all logging calls below severity level
CRITICAL
. For example:
>>> from logga import log, suppress_logging
>>> log.info("This INFO message should display")
2023-01-09 10:33:43 logga [INFO]: This INFO message should display
>>> suppress_logging()
>>> log.info("This INFO message should NOT display")
>>> log.critical("But CRITICAL messages will get through")
2023-01-09 10:36:17 logga [CRITICAL]: But CRITICAL messages will get through
Source code in logga/__init__.py
| def suppress_logging():
"""Provides an overriding (to level `CRITICAL`) suppression mechanism
for all loggers which takes precedence over the logger`s own level.
This function can be useful when the need arises to temporarily throttle logging output down
across the whole application.
Technically, this function will disable all logging calls below severity level
`CRITICAL`. For example:
```
>>> from logga import log, suppress_logging
>>> log.info("This INFO message should display")
2023-01-09 10:33:43 logga [INFO]: This INFO message should display
>>> suppress_logging()
>>> log.info("This INFO message should NOT display")
>>> log.critical("But CRITICAL messages will get through")
2023-01-09 10:36:17 logga [CRITICAL]: But CRITICAL messages will get through
```
"""
logging.disable(logging.ERROR)
|