1、logger名字为日期
一个彩色的日志,用于在输出框里输出彩色字体,并在文件保持处生成正常的字体
1.1、日志样式
----your_file.py
----log
-------2023_2_10.log
1.2、实现方法
我这里的命名方式为:colors_logger.py
# -*- coding: utf-8 -*
# @Time : 2024/8/14 15:08
# @Author : huakuohao
# @File : colors_logger.py
# @Project : B_daily_Project
# @Software: PyCharm
# love
# If I can't be a god, I'll be a beast
import logging
import sys
import os
import time
# 公众号:右恩
class TerminalColor:
RED = '\033[91m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RESET = '\033[0m'
BLUE = '\033[94m'
MAGENTA = '\033[95m'
CYAN = '\033[96m'
WHITE = '\033[97m'
'''
30:黑色
31:红色
32:绿色
33:黄色(或称为棕色或橄榄色)
34:蓝色
35:品红(或称为紫色)
36:青色(或称为蓝绿色)
37:白色
90-97:亮色版本(亮黑、亮红、亮绿、亮黄、亮蓝、亮品红、亮青、亮白)
'''
class ColorFormatter(logging.Formatter):
COLORS = {
logging.DEBUG: TerminalColor.CYAN,
logging.INFO: TerminalColor.BLUE,
logging.WARNING: TerminalColor.MAGENTA,
logging.ERROR: TerminalColor.RED,
logging.CRITICAL: TerminalColor.GREEN
}
def format(self, record):
level_color = self.COLORS.get(record.levelno, TerminalColor.RESET)
reset_color = TerminalColor.RESET
message = super().format(record)
return f"{level_color}{message}{reset_color}"
def _reset_logger(log):
for handler in log.handlers:
handler.close()
log.removeHandler(handler)
del handler
log.handlers.clear()
log.propagate = False
console_handle = logging.StreamHandler(sys.stdout)
console_handle.setFormatter(
ColorFormatter(
"%(asctime)s- %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s",
datefmt="%H:%M:%S",
)
)
log_name = os.path.join(_ensure_log_path(), f"{time.strftime('%Y_%m_%d')}.log")
file_handle = logging.FileHandler(log_name, encoding="utf-8")
file_handle.setFormatter(
logging.Formatter(
"[%(asctime)s][%(levelname)s][%(filename)s:%(lineno)d] - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
)
log.addHandler(file_handle)
log.addHandler(console_handle)
# 公众号:右恩
def _ensure_log_path():
log_path = os.path.join(os.getcwd(), 'logs')
os.makedirs(log_path, exist_ok=True)
return log_path
def _get_logger():
log = logging.getLogger("log")
_reset_logger(log)
log.setLevel(logging.DEBUG)
return log
# 日志句柄
logger = _get_logger()
if __name__ == '__main__':
logger.info('This is an info message')
logger.debug('This is a debug message')
logger.warning('This is a warning message')
logger.error('This is an error message')
logger.critical('This is a critical message')
后续调用
from colors_logger import logger
logger.info("这是一个日志")
# 公众号:右恩
调用后的文件位置
----your_file.py
----log
-------2023_2_10.log
2、当前文件名的日志
2.1日志样式
----your_file.py
----log
-------your_file_log.log
2.2实现方法
# -*-coding:utf-8 -*-
import logging
import sys
import os
import time
import inspect
import re
class TerminalColor:
RED = '\033[91m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RESET = '\033[0m'
BLUE = '\033[94m'
MAGENTA = '\033[95m'
CYAN = '\033[96m'
WHITE = '\033[97m'
# 公众号:右恩
class ColorFormatter(logging.Formatter):
COLORS = {
logging.DEBUG: TerminalColor.CYAN,
logging.INFO: TerminalColor.BLUE,
logging.WARNING: TerminalColor.MAGENTA,
logging.ERROR: TerminalColor.RED,
logging.CRITICAL: TerminalColor.GREEN
}
def format(self, record):
level_color = self.COLORS.get(record.levelno, TerminalColor.RESET)
reset_color = TerminalColor.RESET
message = super().format(record)
return f"{level_color}{message}{reset_color}"
def _sanitize_filename(name):
"""清理非法文件名字符"""
# Windows非法字符:<>:"/\|?* 以及ASCII控制字符(0-31)
return re.sub(r'[<>:"/\\|?*\x00-\x1f]', '', name).strip()
# 公众号:右恩
def _get_valid_caller():
"""获取有效的调用者信息"""
stack = inspect.stack()
for frame_info in stack:
filename = frame_info.filename
# 跳过当前文件和非文件路径
if filename == __file__:
continue
if not os.path.exists(filename):
continue
if '<' in filename or '>' in filename:
continue
return filename
return None
def _get_caller_filename():
"""安全获取调用者文件名"""
valid_path = _get_valid_caller()
if valid_path:
base_name = os.path.splitext(os.path.basename(valid_path))[0]
return _sanitize_filename(base_name) or "default_log"
return "default_log"
def _ensure_log_path():
log_path = os.path.join(os.getcwd(), 'logs')
os.makedirs(log_path, exist_ok=True)
return log_path
# 公众号:右恩
def _reset_logger(log):
# 清除现有handler
for handler in log.handlers[:]:
handler.close()
log.removeHandler(handler)
# 控制台handler
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(
ColorFormatter(
"%(asctime)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s",
datefmt="%H:%M:%S"
)
)
# 文件handler
caller_name = _get_caller_filename()
safe_name = f"{caller_name}_log.log"
log_name = os.path.join(_ensure_log_path(), safe_name)
try:
file_handler = logging.FileHandler(log_name, encoding="utf-8")
except Exception as e:
sys.stderr.write(f"无法创建日志文件 {log_name}: {str(e)}\n")
file_handler = logging.FileHandler("fallback.log", encoding="utf-8")
file_handler.setFormatter(
logging.Formatter(
"[%(asctime)s][%(levelname)s][%(filename)s:%(lineno)d] - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
)
# 添加handler# 公众号:右恩
log.addHandler(console_handler)
log.addHandler(file_handler)
log.propagate = False
def _get_logger():
log = logging.getLogger("safe_dynamic_logger")
if not log.handlers:
_reset_logger(log)
log.setLevel(logging.DEBUG)
return log
# 全局日志对象
logger = _get_logger()
if __name__ == '__main__':
logger.debug("Debug测试信息")
logger.info("当前日志文件:", extra={"skip_special_check": True})
3、当前文件名加时间的日志
3.1日志样式
----your_file.py
----log
-------your_file_log_2025_03_03_12_20_30.log
3.2实现方法
# -*-coding:utf-8 -*-
import logging
import sys
import os
import time
import inspect
import re
class TerminalColor:
RED = '\033[91m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RESET = '\033[0m'
BLUE = '\033[94m'
MAGENTA = '\033[95m'
CYAN = '\033[96m'
WHITE = '\033[97m'
class ColorFormatter(logging.Formatter):
COLORS = {
logging.DEBUG: TerminalColor.CYAN,
logging.INFO: TerminalColor.BLUE,
logging.WARNING: TerminalColor.MAGENTA,
logging.ERROR: TerminalColor.RED,
logging.CRITICAL: TerminalColor.GREEN
}
def format(self, record):
level_color = self.COLORS.get(record.levelno, TerminalColor.RESET)
reset_color = TerminalColor.RESET
message = super().format(record)
return f"{level_color}{message}{reset_color}"
def _sanitize_filename(name):
"""清理非法文件名字符"""
return re.sub(r'[<>:"/\\|?*\x00-\x1f]', '', name).strip()
def _get_valid_caller():
stack = inspect.stack()
for frame_info in stack:
filename = frame_info.filename
if filename == __file__: continue
if not os.path.exists(filename): continue
if '<' in filename or '>' in filename: continue
return filename
return None
def _get_caller_filename():
valid_path = _get_valid_caller()
if valid_path:
base_name = os.path.splitext(os.path.basename(valid_path))[0]
return _sanitize_filename(base_name) or "default_log"
return "default_log"
def _ensure_log_path():
log_path = os.path.join(os.getcwd(), 'logs')
os.makedirs(log_path, exist_ok=True)
return log_path
def _generate_timestamp():
"""生成标准时间戳字符串"""
return time.strftime("%Y_%m_%d_%H_%M_%S")
def _reset_logger(log):
# 清除现有handler
for handler in log.handlers[:]:
handler.close()
log.removeHandler(handler)
# 控制台输出配置
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(
ColorFormatter(
"%(asctime)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s",
datefmt="%H:%M:%S"
)
)
# 文件输出配置(新增时间戳)
caller_name = _get_caller_filename()
timestamp = _generate_timestamp()
safe_name = f"{caller_name}_log_{timestamp}.log" # 格式:test1_log_2025_03_03_12_20_30.log
log_name = os.path.join(_ensure_log_path(), safe_name)
try:
file_handler = logging.FileHandler(log_name, encoding="utf-8")
except Exception as e:
sys.stderr.write(f"创建日志文件失败: {str(e)}\n")
file_handler = logging.FileHandler("fallback.log", encoding="utf-8")
file_handler.setFormatter(
logging.Formatter(
"[%(asctime)s][%(levelname)s][%(filename)s:%(lineno)d] - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
)
log.addHandler(console_handler)
log.addHandler(file_handler)
log.propagate = False
def _get_logger():
log = logging.getLogger("timestamp_logger")
if not log.handlers:
_reset_logger(log)
log.setLevel(logging.DEBUG)
return log
# 全局日志对象
logger = _get_logger()
if __name__ == '__main__':
# 验证日志文件名生成
logger.info("测试时间戳日志文件名")
print("生成的日志文件:", [f for f in os.listdir('logs') if f.endswith('.log')])