121 lines
3.5 KiB
Python
121 lines
3.5 KiB
Python
import constants
|
|
|
|
import sys, time
|
|
import builtins, logging
|
|
import settings
|
|
|
|
# base logging format
|
|
log_format = "[%(asctime)s] [%(levelname)s] (%(name)s) %(message)s"
|
|
|
|
# date-time format
|
|
date_format = constants.DATE_FORMAT
|
|
|
|
# formatter for logger
|
|
formatter = logging.Formatter(log_format, date_format)
|
|
|
|
# class for redirect STD to Logging
|
|
class StdLogRedirect:
|
|
|
|
def __init__(self, stream, formatter, level=logging.ERROR, name="stderr"):
|
|
self.stream = stream
|
|
self.formatter = formatter
|
|
self.level = level
|
|
self.name = name
|
|
self._buf = ""
|
|
|
|
def _emit_line(self, line: str):
|
|
rec = logging.LogRecord(
|
|
name=self.name,
|
|
level=self.level,
|
|
pathname="<stderr>",
|
|
lineno=0,
|
|
msg=line,
|
|
args=(),
|
|
exc_info=None,
|
|
)
|
|
sys.stdout.write(self.formatter.format(rec) + "\n")
|
|
|
|
def write(self, s):
|
|
if isinstance(s, bytes):
|
|
s = s.decode(errors="replace")
|
|
self._buf += s
|
|
while True:
|
|
idx = self._buf.find("\n")
|
|
if idx == -1:
|
|
break
|
|
line = self._buf[:idx+1:]
|
|
self._buf = self._buf[idx+1:]
|
|
if line:
|
|
self._emit_line(line)
|
|
|
|
def flush(self):
|
|
if self._buf:
|
|
self._emit_line(self._buf.rstrip("\r"))
|
|
self._buf = ""
|
|
self.stream.flush()
|
|
|
|
def isatty(self):
|
|
return self.stream.isatty()
|
|
|
|
# redirect STDERR to STDOUT using usual Logging format
|
|
sys.stderr = StdLogRedirect(sys.stderr, formatter, level=logging.ERROR, name="external.stderr")
|
|
|
|
# redirect print to Logging
|
|
_builtin_print = print
|
|
def print_as_log(*args, level=logging.NOTSET, name="unknown.print", **kwargs):
|
|
record = logging.LogRecord(
|
|
name=name,
|
|
level=level,
|
|
pathname=__file__,
|
|
lineno=0,
|
|
msg=" ".join(str(a) for a in args),
|
|
args=(),
|
|
exc_info=None,
|
|
)
|
|
_builtin_print(formatter.format(record), **kwargs)
|
|
builtins.print = print_as_log
|
|
|
|
# logging basic config
|
|
logging.basicConfig(
|
|
level=settings.LOG_LEVEL_TEXT,
|
|
format=log_format,
|
|
datefmt=date_format,
|
|
stream=sys.stdout,
|
|
force=True
|
|
)
|
|
|
|
# create own logger class to prevent init custom loggers by other libs
|
|
class GatekeeperLogger(logging.Logger):
|
|
def addHandler(self, h):
|
|
# only "root", "__main__" and own loggers will be accepted
|
|
if self.name == "root" or self.name.startswith((settings.LOG_PREFIX, "__main__")):
|
|
return super().addHandler(h)
|
|
|
|
logging.setLoggerClass(GatekeeperLogger)
|
|
|
|
# Werkzeug 로거 설정 (Flask 개발 서버용)
|
|
# 기존 werkzeug 로거의 핸들러를 모두 제거하고 커스텀 포맷 적용
|
|
import logging as _logging
|
|
werkzeug_logger = _logging.getLogger("werkzeug")
|
|
werkzeug_logger.handlers = [] # 기존 핸들러 제거
|
|
werkzeug_logger.setLevel(settings.LOG_LEVEL_TEXT)
|
|
handler = _logging.StreamHandler(sys.stdout)
|
|
handler.setFormatter(formatter) # 통일된 포맷 사용
|
|
werkzeug_logger.addHandler(handler)
|
|
werkzeug_logger.propagate = False
|
|
|
|
# Flask의 기본 로거도 동일하게 설정
|
|
flask_logger = _logging.getLogger("flask.app")
|
|
flask_logger.handlers = []
|
|
flask_logger.setLevel(settings.LOG_LEVEL_TEXT)
|
|
flask_handler = _logging.StreamHandler(sys.stdout)
|
|
flask_handler.setFormatter(formatter)
|
|
flask_logger.addHandler(flask_handler)
|
|
flask_logger.propagate = False
|
|
|
|
def custom_logger(log_prefix: str):
|
|
import logging
|
|
|
|
logger = logging.getLogger(log_prefix)
|
|
logger.setLevel(settings.LOG_LEVEL_TEXT)
|
|
return logger |