Create logging target option and fallbacks

This commit is contained in:
2026-05-06 00:38:56 +02:00
parent b295738c0e
commit 4cdd52059d
2 changed files with 92 additions and 37 deletions
+90 -13
View File
@@ -17,17 +17,50 @@ import jcloud_config_parser
import logging
import pathlib
from dataclasses import dataclass
from .exceptions import Fail
__all__ = [
'LoggingInfo',
'setup_logging'
]
@dataclass
class LoggingInfo:
logger: logging.Logger
logfile: pathlib.Path
format: str
level: int
uvicorn_config: dict
def _logfile_fallback_used(path: pathlib.Path) -> bool:
'''
Returns whether the fallback value for the logfile should be used.
:param path: The path to the logfile.
:type path: pathlib.Path
:return: Whether the fallback value should be used.
:rtype: bool
'''
# Path exists and is a directory -> invalid
if path.exists() and path.is_dir():
return True
parent = path.parent or pathlib.Path('.')
# Parent directory missing -> try to create it
if not parent.exists():
try:
parent.mkdir(parents = True, exist_ok = True)
except OSError:
return True
# Check whether the path is writable.
try:
with open(path, 'a'):
pass
except (OSError, PermissionError):
return True
return False
def setup_logging(configuration: jcloud_config_parser.ini.INIConfiguration) -> LoggingInfo:
'''
@@ -40,8 +73,22 @@ def setup_logging(configuration: jcloud_config_parser.ini.INIConfiguration) -> L
:rtype: LoggingInfo
'''
logfile = configuration.logging.logfile
if os.path.isdir(logfile) or not logfile:
fail_strict = configuration.logging.fail_strict.lower() in ('true', 'yes', 't', 'y')
logtarget = configuration.logging.logtarget
if logtarget not in ('file', 'stdout'):
if fail_strict:
raise Fail(f'\'{logtarget}\': invalid value for [logging].logtarget. Expected either \'file\' or \'stdout\'.')
logtarget = 'stdout'
if logtarget == 'file':
logfile = pathlib.Path(configuration.logging.logfile)
if _logfile_fallback_used(logfile):
if fail_strict:
raise Fail(f'\'{logfile}\': Cannot use as a log file.')
logtarget = 'stdout' # fallback to stdout
else:
logfile = None
loglevel = logging._nameToLevel.get(
@@ -54,17 +101,47 @@ def setup_logging(configuration: jcloud_config_parser.ini.INIConfiguration) -> L
logging.basicConfig(level=loglevel, format=logging_format)
logger = logging.getLogger('api')
logger.propagate = False
logger.handlers = list()
formatter = logging.Formatter(logging_format)
if logfile is not None:
logger_file_handler = logging.FileHandler(logfile)
logger_file_handler.setFormatter(formatter)
logger.addHandler(logger_file_handler)
if logtarget == 'file':
logger.handlers = list()
handler = logging.FileHandler(logfile)
handler.setFormatter(formatter)
else:
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
uvicorn_config = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'uvicorn_formatter': {
'format': logging_format
}
},
'loggers': {
'uvicorn': {
'handlers': ['uvicorn_handler'],
'level': loglevel,
'propagate': False
},
},
'handlers': {
'uvicorn_handler': {
'class': 'logging.FileHandler',
'filename': logfile,
'formatter': 'uvicorn_formatter'
} if logtarget == 'file'
else {
'class': 'logging.StreamHandler',
'formatter': 'uvicorn_formatter'
}
}
}
return LoggingInfo(
logger,
logfile,
logging_format,
loglevel
uvicorn_config
)
+1 -23
View File
@@ -50,27 +50,5 @@ def main():
host = host,
port = port,
server_header = False,
log_config = {
'version': 1,
'disable_existing_loggers': True,
'handlers': {
'uvicorn_handler': {
'class': 'logging.FileHandler',
'filename': str(logger_info.logfile),
'formatter': 'uvicorn_formatter',
},
},
'formatters': {
'uvicorn_formatter': {
'format': logger_info.format
},
},
'loggers': {
'uvicorn': {
'handlers': ['uvicorn_handler'],
'level': logger_info.level,
'propagate': False
},
},
}
log_config = logger_info.uvicorn_config
)