generated from jCloud/repository-template
Create logging target option and fallbacks
This commit is contained in:
@@ -17,17 +17,50 @@ import jcloud_config_parser
|
|||||||
import logging
|
import logging
|
||||||
import pathlib
|
import pathlib
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from .exceptions import Fail
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
'LoggingInfo',
|
||||||
'setup_logging'
|
'setup_logging'
|
||||||
]
|
]
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class LoggingInfo:
|
class LoggingInfo:
|
||||||
logger: logging.Logger
|
logger: logging.Logger
|
||||||
logfile: pathlib.Path
|
uvicorn_config: dict
|
||||||
format: str
|
|
||||||
level: int
|
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:
|
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
|
:rtype: LoggingInfo
|
||||||
'''
|
'''
|
||||||
|
|
||||||
logfile = configuration.logging.logfile
|
fail_strict = configuration.logging.fail_strict.lower() in ('true', 'yes', 't', 'y')
|
||||||
if os.path.isdir(logfile) or not logfile:
|
|
||||||
|
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
|
logfile = None
|
||||||
|
|
||||||
loglevel = logging._nameToLevel.get(
|
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)
|
logging.basicConfig(level=loglevel, format=logging_format)
|
||||||
logger = logging.getLogger('api')
|
logger = logging.getLogger('api')
|
||||||
logger.propagate = False
|
logger.propagate = False
|
||||||
logger.handlers = list()
|
|
||||||
|
|
||||||
formatter = logging.Formatter(logging_format)
|
formatter = logging.Formatter(logging_format)
|
||||||
if logfile is not None:
|
|
||||||
logger_file_handler = logging.FileHandler(logfile)
|
if logtarget == 'file':
|
||||||
logger_file_handler.setFormatter(formatter)
|
logger.handlers = list()
|
||||||
logger.addHandler(logger_file_handler)
|
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(
|
return LoggingInfo(
|
||||||
logger,
|
logger,
|
||||||
logfile,
|
uvicorn_config
|
||||||
logging_format,
|
|
||||||
loglevel
|
|
||||||
)
|
)
|
||||||
@@ -50,27 +50,5 @@ def main():
|
|||||||
host = host,
|
host = host,
|
||||||
port = port,
|
port = port,
|
||||||
server_header = False,
|
server_header = False,
|
||||||
log_config = {
|
log_config = logger_info.uvicorn_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
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
Reference in New Issue
Block a user