From aef92bca114f012e02a5dc4331a06a4f76121ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BC=BA?= <1206709430@qq.com> Date: Sat, 8 Apr 2023 21:27:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9A=E5=8F=96=E6=B6=88lo?= =?UTF-8?q?guru=E6=97=A5=E5=BF=97=EF=BC=8C=E4=BD=BF=E7=94=A8=E7=AE=80?= =?UTF-8?q?=E5=8D=95Django=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/application/settings.py | 92 +++++++++++++--------- backend/dvadmin/utils/log.py | 131 -------------------------------- backend/requirements.txt | 1 - 3 files changed, 57 insertions(+), 167 deletions(-) delete mode 100644 backend/dvadmin/utils/log.py diff --git a/backend/application/settings.py b/backend/application/settings.py index c916894..6946d38 100644 --- a/backend/application/settings.py +++ b/backend/application/settings.py @@ -187,78 +187,100 @@ else: }, } - -# ================================================= # -# ********************* 日志配置 ******************* # -# ================================================= # - -# log 配置部分BEGIN # +# # ================================================= # +# # ********************* 日志配置 ******************* # +# # ================================================= # +# # log 配置部分BEGIN # +SERVER_LOGS_FILE = os.path.join(BASE_DIR, "logs", "server.log") +ERROR_LOGS_FILE = os.path.join(BASE_DIR, "logs", "error.log") LOGS_FILE = os.path.join(BASE_DIR, "logs") if not os.path.exists(os.path.join(BASE_DIR, "logs")): os.makedirs(os.path.join(BASE_DIR, "logs")) +# 格式:[2020-04-22 23:33:01][micoservice.apps.ready():16] [INFO] 这是一条日志: +# 格式:[日期][模块.函数名称():行号] [级别] 信息 +STANDARD_LOG_FORMAT = ( + "[%(asctime)s][%(name)s.%(funcName)s():%(lineno)d] [%(levelname)s] %(message)s" +) +CONSOLE_LOG_FORMAT = ( + "[%(asctime)s][%(name)s.%(funcName)s():%(lineno)d] [%(levelname)s] %(message)s" +) LOGGING = { "version": 1, "disable_existing_loggers": False, "formatters": { - "servers": { - "format": "%(message)s", + "standard": {"format": STANDARD_LOG_FORMAT}, + "console": { + "format": CONSOLE_LOG_FORMAT, "datefmt": "%Y-%m-%d %H:%M:%S", - } + }, + "file": { + "format": CONSOLE_LOG_FORMAT, + "datefmt": "%Y-%m-%d %H:%M:%S", + }, }, "handlers": { - "servers": { - "logging_levels": ["info", "error", "warning"], - "class": "dvadmin.utils.log.InterceptTimedRotatingFileHandler", # 这个路径看你本地放在哪里(下面的log文件) - "filename": os.path.join(LOGS_FILE, "server.log"), - "when": "D", - "interval": 1, + "file": { + "level": "INFO", + "class": "logging.handlers.RotatingFileHandler", + "filename": SERVER_LOGS_FILE, "maxBytes": 1024 * 1024 * 100, # 100 MB - "backupCount": 1, - "formatter": "servers", + "backupCount": 5, # 最多备份5个 + "formatter": "standard", "encoding": "utf-8", - } + }, + "error": { + "level": "ERROR", + "class": "logging.handlers.RotatingFileHandler", + "filename": ERROR_LOGS_FILE, + "maxBytes": 1024 * 1024 * 100, # 100 MB + "backupCount": 3, # 最多备份3个 + "formatter": "standard", + "encoding": "utf-8", + }, + "console": { + "level": "INFO", + "class": "logging.StreamHandler", + "formatter": "console", + }, + }, "loggers": { - # default日志 - 'django': { - 'handlers': ['servers'], - 'propagate': False, - 'level': "INFO" + "": { + "handlers": ["console", "error", "file"], + "level": "INFO", }, - '': { - 'handlers': ['servers'], - 'propagate': False, - 'level': "ERROR" + "django": { + "handlers": ["console", "error", "file"], + "level": "INFO", + "propagate": False, }, 'celery': { - 'handlers': ['servers'], + 'handlers': ["console", "error", "file"], 'propagate': False, 'level': "INFO" }, 'django.db.backends': { - 'handlers': ['servers'], + 'handlers': ["console", "error", "file"], 'propagate': False, 'level': "INFO" }, 'django.request': { - 'handlers': ['servers'], + 'handlers': ["console", "error", "file"], 'propagate': False, 'level': "DEBUG" }, "uvicorn.error": { "level": "INFO", - "handlers": ["servers"], + "handlers": ["console", "error", "file"], }, "uvicorn.access": { - "handlers": ["servers"], - "level": "INFO", - "propagate": False + "handlers": ["console", "error", "file"], + "level": "INFO" }, }, } - # ================================================= # # *************** REST_FRAMEWORK配置 *************** # # ================================================= # diff --git a/backend/dvadmin/utils/log.py b/backend/dvadmin/utils/log.py deleted file mode 100644 index 73618c2..0000000 --- a/backend/dvadmin/utils/log.py +++ /dev/null @@ -1,131 +0,0 @@ -import logging -import os.path -import sys - -from django.db import connection -from loguru import logger - -from logging.handlers import RotatingFileHandler - -# 1.🎖️先声明一个类继承logging.Handler(制作一件品如的衣服) - -from application.dispatch import is_tenants_mode - - -class InterceptTimedRotatingFileHandler(RotatingFileHandler): - """ - 自定义反射时间回滚日志记录器 - 缺少命名空间 - """ - - def __init__(self, filename, when='d', interval=1, backupCount=5, encoding="utf-8", delay=False, utc=False, - maxBytes=1024 * 1024 * 100, atTime=None, logging_levels="all", format=None): - super(InterceptTimedRotatingFileHandler, self).__init__(filename) - filename = os.path.abspath(filename) - # 定义默认格式 - if not format: - format = "{time:YYYY-MM-DD HH:mm:ss.SSS} | {extra[client_addr]:^18} | {level: <8}| {message}" - when = when.lower() - # 2.🎖️需要本地用不同的文件名做为不同日志的筛选器 - logger.configure( - handlers=[ - dict(sink=sys.stderr, format=format), - ], - ) - self.logger_ = logger.bind(sime=filename, client_addr="-") - self.filename = filename - key_map = { - 'h': 'hour', - 'w': 'week', - 's': 'second', - 'm': 'minute', - 'd': 'day', - } - # 根据输入文件格式及时间回滚设立文件名称 - rotation = f"{maxBytes / 1024 / 1024}MB" - retention = "%d %ss" % (backupCount, key_map[when]) - time_format = "{time:%Y-%m-%d_%H-%M-%S}" - if when == "s": - time_format = "{time:%Y-%m-%d_%H-%M-%S}" - elif when == "m": - time_format = "{time:%Y-%m-%d_%H-%M}" - elif when == "h": - time_format = "{time:%Y-%m-%d_%H}" - elif when == "d": - time_format = "{time:%Y-%m-%d}" - elif when == "w": - time_format = "{time:%Y-%m-%d}" - level_keys = ["info"] - # 3.🎖️构建一个筛选器 - levels = { - "debug": lambda x: "DEBUG" == x['level'].name.upper() and x['extra'].get('sime') == filename, - "error": lambda x: "ERROR" == x['level'].name.upper() and x['extra'].get('sime') == filename, - "info": lambda x: "INFO" == x['level'].name.upper() and x['extra'].get('sime') == filename, - "warning": lambda x: "WARNING" == x['level'].name.upper() and x['extra'].get('sime') == filename - } - # 4. 🎖️根据输出构建筛选器 - if isinstance(logging_levels, str): - if logging_levels.lower() == "all": - level_keys = levels.keys() - elif logging_levels.lower() in levels: - level_keys = [logging_levels] - elif isinstance(logging_levels, (list, tuple)): - level_keys = logging_levels - for k, f in {_: levels[_] for _ in level_keys}.items(): - - # 5.🎖️为防止重复添加sink,而重复写入日志,需要判断是否已经装载了对应sink,防止其使用秘技:反复横跳。 - filename_fmt = filename.replace(".log", "_%s_%s.log" % (time_format, k)) - # noinspection PyUnresolvedReferences,PyProtectedMember - file_key = {_._name: han_id for han_id, _ in self.logger_._core.handlers.items()} - filename_fmt_key = "'{}'".format(filename_fmt) - if filename_fmt_key in file_key: - continue - # self.logger_.remove(file_key[filename_fmt_key]) - self.logger_.add( - filename_fmt, - format=format, - retention=retention, - encoding=encoding, - level=self.level, - rotation=rotation, - compression="zip", # 日志归档自行压缩文件 - delay=delay, - enqueue=True, - backtrace=True, - filter=f - ) - - def emit(self, record): - try: - level = self.logger_.level(record.levelname).name - except ValueError: - level = record.levelno - - frame, depth = logging.currentframe(), 2 - # 6.🎖️把当前帧的栈深度回到发生异常的堆栈深度,不然就是当前帧发生异常而无法回溯 - while frame.f_code.co_filename == logging.__file__: - frame = frame.f_back - depth += 1 - # 设置自定义属性 - details = frame.f_locals.get('details', None) - msg = self.format(record) - bind = {} - record_client = None - if isinstance(record.args, dict): - record_client = record.args.get('client_addr') or record.args.get('client') - elif isinstance(record.args, tuple) and len(record.args) > 0: - if ":" in str(record.args[0]): - record_client = record.args[0] - if msg.split("-") and len(msg.split("-")) == 2: - msg = f"{msg.split('-')[1].strip(' ')}" - elif isinstance(record.args[0], tuple) and len(record.args[0]) == 2: - record_client = f"{record.args[0][0]}:{record.args[0][1]}" - if msg.split("-") and len(msg.split("-")) == 2: - msg = f"{msg.split('-')[1].strip(' ')}" - client = record_client or (details and details.get('client')) - if client: - bind["client_addr"] = client - if is_tenants_mode(): - bind["schema_name"] = connection.tenant.schema_name - bind["domain_url"] = getattr(connection.tenant, 'domain_url', None) - self.logger_.opt(depth=depth, exception=record.exc_info, colors=True, lazy=True).bind(**bind).log(level, f"{msg}") diff --git a/backend/requirements.txt b/backend/requirements.txt index c8660ac..17727f8 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -47,4 +47,3 @@ uvicorn==0.21.1 gunicorn==20.1.0 gevent==22.10.2 websockets==10.4 -loguru==0.6.0