201 lines
7.8 KiB
Python
201 lines
7.8 KiB
Python
import sys
|
||
import logging
|
||
import os
|
||
import tempfile
|
||
import traceback
|
||
from logging.handlers import TimedRotatingFileHandler
|
||
from datetime import datetime
|
||
from PySide6.QtWidgets import QApplication, QMessageBox
|
||
from PySide6.QtCore import QTranslator, QLocale, QLibraryInfo
|
||
from widgets.login_widget import LoginWidget
|
||
from utils.menu_translator import MenuTranslator
|
||
from utils.config_loader import ConfigLoader
|
||
|
||
# 自定义异常处理器
|
||
def global_exception_handler(exctype, value, tb):
|
||
"""全局异常处理器,捕获未处理的异常并记录日志"""
|
||
error_msg = ''.join(traceback.format_exception(exctype, value, tb))
|
||
logging.critical(f"未捕获的异常: {error_msg}")
|
||
|
||
# 如果已经有QApplication实例,显示错误对话框
|
||
if QApplication.instance():
|
||
QMessageBox.critical(None, "系统错误",
|
||
f"发生了未处理的错误:\n{value}\n\n请联系管理员并提供日志文件。")
|
||
|
||
# 调用原始的异常处理器
|
||
sys.__excepthook__(exctype, value, tb)
|
||
|
||
# 安装全局异常处理器
|
||
sys.excepthook = global_exception_handler
|
||
|
||
# 设置日志目录
|
||
log_dir = 'logs'
|
||
temp_log_dir = None
|
||
|
||
# 尝试使用应用程序目录
|
||
try:
|
||
if not os.path.exists(log_dir):
|
||
os.makedirs(log_dir, exist_ok=True)
|
||
|
||
# 测试目录是否可写
|
||
test_file = os.path.join(log_dir, 'test_write.tmp')
|
||
with open(test_file, 'w') as f:
|
||
f.write('test')
|
||
os.remove(test_file)
|
||
|
||
logging.basicConfig(level=logging.INFO, format='%(message)s')
|
||
logging.info(f"使用应用程序日志目录: {os.path.abspath(log_dir)}")
|
||
|
||
except (OSError, PermissionError) as e:
|
||
# 如果应用程序目录不可用或不可写,使用临时目录
|
||
temp_log_dir = os.path.join(tempfile.gettempdir(), 'app_logs')
|
||
log_dir = temp_log_dir
|
||
|
||
try:
|
||
if not os.path.exists(log_dir):
|
||
os.makedirs(log_dir, exist_ok=True)
|
||
|
||
logging.basicConfig(level=logging.INFO, format='%(message)s')
|
||
logging.info(f"无法使用应用程序日志目录,原因: {e}")
|
||
logging.info(f"使用临时日志目录: {log_dir}")
|
||
except Exception as e2:
|
||
# 如果临时目录也失败,只使用控制台输出
|
||
print(f"无法创建日志目录,将只使用控制台输出: {e2}")
|
||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||
|
||
# 配置全局日志
|
||
# 使用日期命名日志文件
|
||
today = datetime.now().strftime('%Y-%m-%d')
|
||
log_file_path = os.path.join(log_dir, f'app_{today}.log')
|
||
|
||
try:
|
||
# 创建一个TimedRotatingFileHandler,每天轮换一次日志文件
|
||
file_handler = TimedRotatingFileHandler(
|
||
log_file_path,
|
||
when='midnight', # 每天午夜轮换
|
||
interval=1, # 轮换间隔为1天
|
||
backupCount=30, # 保留30天的日志
|
||
encoding='utf-8' # 使用UTF-8编码
|
||
)
|
||
|
||
# 配置日志格式
|
||
log_format = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - [%(funcName)s:%(lineno)d] - %(message)s')
|
||
file_handler.setFormatter(log_format)
|
||
|
||
# 控制台输出处理器
|
||
console_handler = logging.StreamHandler(sys.stdout)
|
||
console_handler.setFormatter(log_format)
|
||
|
||
# 配置根日志记录器
|
||
root_logger = logging.getLogger()
|
||
root_logger.setLevel(logging.INFO) # 将默认级别设为INFO,减少DEBUG级别的输出
|
||
# 清除已有的handlers
|
||
for handler in root_logger.handlers[:]:
|
||
root_logger.removeHandler(handler)
|
||
root_logger.addHandler(file_handler)
|
||
root_logger.addHandler(console_handler)
|
||
|
||
logging.info("=================================================================")
|
||
logging.info("应用程序启动")
|
||
logging.info(f"Python version: {sys.version}")
|
||
logging.info(f"Working directory: {os.getcwd()}")
|
||
logging.info(f"日志文件: {log_file_path}")
|
||
|
||
except Exception as e:
|
||
# 如果文件处理器创建失败,仅使用控制台输出
|
||
logging.error(f"无法设置日志文件,将只使用控制台输出: {e}")
|
||
|
||
# 确保根logger至少有一个控制台处理器
|
||
root_logger = logging.getLogger()
|
||
if not root_logger.handlers:
|
||
console_handler = logging.StreamHandler(sys.stdout)
|
||
console_format = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - [%(funcName)s:%(lineno)d] - %(message)s')
|
||
console_handler.setFormatter(console_format)
|
||
root_logger.addHandler(console_handler)
|
||
|
||
logging.info("=================================================================")
|
||
logging.info("应用程序启动 (仅控制台日志)")
|
||
logging.info(f"Python version: {sys.version}")
|
||
logging.info(f"Working directory: {os.getcwd()}")
|
||
|
||
def main():
|
||
"""主程序入口"""
|
||
|
||
app = QApplication(sys.argv)
|
||
logging.info("=====================================================")
|
||
logging.info(" 应用程序启动 ")
|
||
logging.info("=====================================================")
|
||
|
||
try:
|
||
# 读取配置
|
||
config = ConfigLoader.get_instance()
|
||
# 打印关键配置信息
|
||
enable_serial_ports = config.get_value('serial.printer.enabled', False)
|
||
# 键盘监听器配置信息
|
||
enable_keyboard_listener = config.get_value('serial.keyboard.enabled', False)
|
||
logging.info(f"配置信息 - 启用串口: {enable_serial_ports}, 启用键盘监听: {enable_keyboard_listener}")
|
||
|
||
# 设置中文翻译器
|
||
translator = QTranslator(app)
|
||
# 使用兼容新旧版本的方式获取翻译路径
|
||
try:
|
||
# 新版本API
|
||
translations_path = QLibraryInfo.path(QLibraryInfo.LibraryPath.TranslationsPath)
|
||
except AttributeError:
|
||
# 旧版本API
|
||
translations_path = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
|
||
|
||
# 尝试加载翻译文件
|
||
translation_loaded = translator.load("qt_zh_CN", translations_path)
|
||
|
||
# 如果加载失败,尝试在可执行文件目录下查找翻译文件
|
||
if not translation_loaded and getattr(sys, 'frozen', False):
|
||
# 打包后的应用
|
||
app_dir = os.path.dirname(sys.executable)
|
||
possible_paths = [
|
||
os.path.join(app_dir, "translations"),
|
||
os.path.join(app_dir, "PySide6", "translations"),
|
||
os.path.join(app_dir, "Qt", "translations"),
|
||
]
|
||
|
||
for path in possible_paths:
|
||
if os.path.exists(path):
|
||
if translator.load("qt_zh_CN", path):
|
||
translation_loaded = True
|
||
translations_path = path
|
||
break
|
||
|
||
app.installTranslator(translator)
|
||
|
||
# 设置应用程序的本地化
|
||
locale = QLocale(QLocale.Chinese, QLocale.China)
|
||
QLocale.setDefault(locale)
|
||
|
||
# 安装菜单翻译器
|
||
MenuTranslator.install_menu_translator(app)
|
||
|
||
logging.info(f"已设置中文翻译器,翻译路径: {translations_path},加载状态: {translation_loaded}")
|
||
|
||
# 创建db目录(如果不存在)
|
||
os.makedirs('db', exist_ok=True)
|
||
|
||
# 检查数据库是否存在,如果不存在则初始化
|
||
if not os.path.exists('db/jtDB.db'):
|
||
from utils.init_db import init_database
|
||
init_database()
|
||
logging.info("初始化数据库完成")
|
||
|
||
login_widget = LoginWidget()
|
||
login_widget.show()
|
||
|
||
exit_code = app.exec()
|
||
logging.info(f"应用程序退出,退出码: {exit_code}")
|
||
sys.exit(exit_code)
|
||
|
||
except Exception as e:
|
||
logging.critical(f"严重错误: {e}", exc_info=True)
|
||
print(f"严重错误: {e}") # 确保即使日志系统故障也能看到错误
|
||
sys.exit(1)
|
||
|
||
if __name__ == "__main__":
|
||
main() |