Compare commits

...

3 Commits

Author SHA1 Message Date
c27e250fad update log config 2026-06-13 19:47:27 +08:00
66c0b71b89 update ip 2026-06-13 17:35:46 +08:00
5c7b73b7a4 add log 2026-06-13 16:49:29 +08:00
5 changed files with 130 additions and 68 deletions

View File

@@ -157,8 +157,8 @@ class Decoder_main(threading.Thread):
# self.blink_b, self.blink_a = signal.butter(4, [self.l_freq / (self.device_info['sample_rate'] / 2), self.h_freq / (self.device_info['sample_rate'] / 2)], btype='band')
def parameter_init(self,bandPass_low,bandPass_high):
self.interval_epoch = [int(i * self.device_info['sample_rate']) for i in self.interval_epoch] # epoch截取信息
self.train_epoch = [int(self.interval_epoch[0]), int(self.interval_epoch[1] + 0.1 * self.device_info['sample_rate'])] # 训练样本epoch
self.interval_epoch = [int(i * self.device_info['sample_rate']) for i in self.interval_epoch] # epoch截取信息 ssmvep [50, 550]
self.train_epoch = [int(self.interval_epoch[0]), int(self.interval_epoch[1] + 0.1 * self.device_info['sample_rate'])] # 训练样本epoch ssmevep [50, 575]
self.trainData = [] #训练数据
self.trainLabel = [] #训练标签
self.plotData = [] #报告分析数据
@@ -287,9 +287,9 @@ class Decoder_main(threading.Thread):
if trainTrial.shape[1] == (self.train_epoch[1] - self.train_epoch[0]) and isinstance(
self.trainLabel, list) \
and self.trainLabel.count(self.currentLabel) < self.single_train:
algo_log(f"SSMVEP训练集{np.shape(self.trainData)}", level="DEBUG")
self.trainData.append(trainTrial)
self.trainLabel.append(self.currentLabel)
algo_log(f"SSMVEP训练集{np.shape(self.trainData)}", level="DEBUG")
else:
time.sleep(0.0001)
return

View File

@@ -39,3 +39,5 @@ python upperHost_stimmock/MI_headless.py
# debug log
## MI
Epoch采集完成|收到命令: {'method': 'train'|取出的
收到命令: {'method': 'train'|收到命令: {'method': 'train'|收到命令: {'method': 'predict'|事件检测到

View File

@@ -18,11 +18,22 @@ Upper_Port = 8088
Decoder_Host = 127.0.0.1
Decoder_Port = 8099
Serial_port = COM44
algo_log_path = d:/Program Files/64chn_Decoder/logs
algo_log_level = DEBUG
console_output = 1
save_train_data = 0
zmqServer_host = 10.200.27.140
zmqServer_host = 127.0.0.1
[algo_log]
# ========== 文件日志配置 ==========
file_log_enable = true
file_log_level = DEBUG
log_path = exe
retention_days = 3
# ========== 控制台/黑框配置 ==========
console_enable = true
console_show_window = true
console_log_level = DEBUG
; 64 导设备配置
[device_type_1]

View File

@@ -1,122 +1,172 @@
import os
import sys
from pathlib import Path
from datetime import datetime, timedelta
import logging
from logging.handlers import RotatingFileHandler
import inspect
try:
import win32gui
import win32con
WIN32_AVAILABLE = True
except ImportError:
WIN32_AVAILABLE = False
from PubLibrary.InifileHelper import IniRead
# ===================== 新增:获取 EXE 同级目录 =====================
def get_app_root():
"""获取 runDecoder.exe 所在的真实根目录(兼容 onefile / standalone"""
if getattr(sys, 'frozen', False):
# Nuitka / PyInstaller 打包后走这里
app_path = sys.executable
else:
# 本地源码运行时,取当前脚本目录
app_path = os.path.abspath(__file__)
return os.path.dirname(app_path)
# 全局配置
console_output = IniRead('system', 'console_output', '1')
log_level = IniRead('system', 'algo_log_level', 'INFO')
# 程序根目录exe 同级)
APP_ROOT = Path(get_app_root())
# 日志文件夹名exe 同级下 logs 目录
DEFAULT_LOG_DIR = APP_ROOT / "logs"
# ===================== 读取 [algo_log] 配置 =====================
# 文件日志
FILE_LOG_ENABLE = IniRead("algo_log", "file_log_enable", "true").lower() == "true"
FILE_LOG_LEVEL = IniRead("algo_log", "file_log_level", "DEBUG").upper()
# 优先级:配置文件 > 默认exe同级logs
CFG_LOG_PATH = IniRead("algo_log", "log_path", "").strip()
if CFG_LOG_PATH == "exe":
LOG_DIR = DEFAULT_LOG_DIR
else:
LOG_DIR = Path(CFG_LOG_PATH)
LOG_RETENTION_DAYS = int(IniRead("algo_log", "retention_days", 3))
# 控制台日志 + 黑框控制
CONSOLE_ENABLE = IniRead("algo_log", "console_enable", "true").lower() == "true"
CONSOLE_SHOW_WINDOW = IniRead("algo_log", "console_show_window", "true").lower() == "true"
CONSOLE_LOG_LEVEL = IniRead("algo_log", "console_log_level", "INFO").upper()
# ===================== 全局常量与缓存 =====================
log_once_cache = set()
logger_cache = {}
LOG_RETENTION_DAYS = 3
LOG_PATH_STR = IniRead('system', 'algo_log_path', "d:/Program Files/64chn_Decoder/logs")
LOG_DIR = Path(LOG_PATH_STR)
# 自动补全路径分隔符,创建目录(不存在则新建,避免写日志报错)
LOG_DIR.mkdir(parents=True, exist_ok=True)
# 如需字符串格式路径
LOG_DIR_STR = str(LOG_DIR) + "\\"
LOG_FILE_PREFIX = 'algo_log_'
# 确保日志目录存在
LOG_DIR.mkdir(parents=True, exist_ok=True)
LOG_DIR_STR = str(LOG_DIR) + "\\"
# 日志格式:时间 - 日志器名 - 级别 - 文件名:行号 - 函数名 - 日志内容
# 日志格式
LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
# 日志级别映射
LEVEL_MAP = {
"DEBUG": logging.DEBUG,
"INFO": logging.INFO,
"WARNING": logging.WARNING,
"ERROR": logging.ERROR,
"FATAL": logging.FATAL
}
FILE_LOG_LEVEL_INT = LEVEL_MAP.get(FILE_LOG_LEVEL, logging.INFO)
CONSOLE_LOG_LEVEL_INT = LEVEL_MAP.get(CONSOLE_LOG_LEVEL, logging.INFO)
def clean_old_logs():
"""清理超过指定天数的旧日志文件"""
# ===================== Windows 控制台黑框显示/隐藏 =====================
def control_console_window():
if not sys.platform.startswith("win") or not WIN32_AVAILABLE:
return
try:
if not os.path.exists(LOG_DIR):
hwnd = win32gui.GetForegroundWindow()
if CONSOLE_SHOW_WINDOW:
win32gui.ShowWindow(hwnd, win32con.SW_SHOW)
else:
win32gui.ShowWindow(hwnd, win32con.SW_HIDE)
except Exception:
pass
control_console_window()
# ===================== 清理过期日志 =====================
def clean_old_logs():
try:
if not LOG_DIR.exists():
return
expire_date = datetime.now() - timedelta(days=LOG_RETENTION_DAYS)
for filename in os.listdir(LOG_DIR):
if not filename.startswith(LOG_FILE_PREFIX) or not filename.endswith('.log'):
if not (filename.startswith(LOG_FILE_PREFIX) and filename.endswith('.log')):
continue
date_str = filename[len(LOG_FILE_PREFIX):-4]
try:
file_date = datetime.strptime(date_str, '%Y-%m-%d')
if file_date < expire_date:
file_path = os.path.join(LOG_DIR, filename)
file_path = LOG_DIR / filename
os.remove(file_path)
print(f"清理过期日志: {file_path}")
except ValueError:
continue
except Exception as e:
print(f"清理旧日志异常: {str(e)}")
except Exception:
pass
# ===================== 初始化日志器 =====================
def init_module_logger(logger_name):
"""初始化日志器 + 清理旧日志"""
os.makedirs(LOG_DIR, exist_ok=True)
clean_old_logs()
current_date = datetime.now().strftime("%Y-%m-%d")
log_file = os.path.join(LOG_DIR, f"{LOG_FILE_PREFIX}{current_date}.log")
if logger_name in logger_cache:
return logger_cache[logger_name]
clean_old_logs()
logger = logging.getLogger(logger_name)
logger.setLevel(log_level)
logger.setLevel(logging.DEBUG)
if logger.handlers:
logger_cache[logger_name] = logger
return logger
# 文件输出处理器
formatter = logging.Formatter(LOG_FORMAT, datefmt=DATE_FORMAT)
# 文件日志
if FILE_LOG_ENABLE:
current_date = datetime.now().strftime("%Y-%m-%d")
log_file = LOG_DIR / f"{LOG_FILE_PREFIX}{current_date}.log"
file_handler = RotatingFileHandler(
log_file,
maxBytes=10 * 1024 * 1024,
backupCount=10,
encoding='utf-8'
)
formatter = logging.Formatter(LOG_FORMAT, datefmt=DATE_FORMAT)
file_handler.setFormatter(formatter)
file_handler.setLevel(FILE_LOG_LEVEL_INT)
logger.addHandler(file_handler)
# 控制台输出
if console_output:
console_handler = logging.StreamHandler()
# 控制台日志
if CONSOLE_ENABLE:
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(formatter)
console_handler.setLevel(CONSOLE_LOG_LEVEL_INT)
logger.addHandler(console_handler)
logger_cache[logger_name] = logger
return logger
# ===================== 对外日志入口函数 =====================
def algo_log(content, level="INFO", record_once=False):
"""
日志入口函数
自动记录:调用文件名、代码行号、所在函数
"""
# 回溯栈帧,获取真正调用 algo_log 的代码位置
# f_back(1) -> algo_log 自身f_back(2) -> 业务调用处
frame = inspect.currentframe().f_back.f_back
if not frame:
file_name = "unknown"
else:
file_name = os.path.basename(frame.f_code.co_filename)
frame = inspect.currentframe()
if frame:
frame = frame.f_back.f_back
file_name = os.path.basename(frame.f_code.co_filename) if frame else "unknown"
logger = init_module_logger(file_name)
# 单次日志去重
if record_once:
log_key = f"{level.upper()}_{content}"
if log_key in log_once_cache:
return
log_once_cache.add(log_key)
# 日志级别分发
level_upper = level.upper()
log_map = {
log_func_map = {
"DEBUG": logger.debug,
"INFO": logger.info,
"WARNING": logger.warning,
"ERROR": logger.error,
"FATAL": logger.fatal,
"INFO": logger.info
"FATAL": logger.fatal
}
log_func = log_map.get(level_upper, logger.info)
log_func = log_func_map.get(level_upper, logger.info)
log_func(content)

View File

@@ -28,7 +28,6 @@ echo "输出目录:${OUT_DIR}"
python -m nuitka \
--standalone \
--msvc=latest \
--windows-console-mode=force \
--module-parameter=torch-disable-jit=yes \
--enable-plugin=no-qt \
--include-package=numpy \