feat : 新增日志查阅功能
This commit is contained in:
parent
a11865d6da
commit
8f0f80c644
@ -151,6 +151,53 @@ p, li { white-space: pre-wrap; }
|
|||||||
<string>事件时间线</string>
|
<string>事件时间线</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_readlog">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>日志查看</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBox_logSelect">
|
||||||
|
<property name="currentText">
|
||||||
|
<string>IDL日志</string>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>IDL日志</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>审计日志</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>维护日志</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>OS串口日志</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>运行状态</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>部件日志</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextBrowser" name="textBrowser_logView"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
@ -76,6 +76,23 @@ class Ui_MainWindow(object):
|
|||||||
self.tab_timeline_event = QtWidgets.QWidget()
|
self.tab_timeline_event = QtWidgets.QWidget()
|
||||||
self.tab_timeline_event.setObjectName("tab_timeline_event")
|
self.tab_timeline_event.setObjectName("tab_timeline_event")
|
||||||
self.tabWidget.addTab(self.tab_timeline_event, "")
|
self.tabWidget.addTab(self.tab_timeline_event, "")
|
||||||
|
self.tab_readlog = QtWidgets.QWidget()
|
||||||
|
self.tab_readlog.setObjectName("tab_readlog")
|
||||||
|
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab_readlog)
|
||||||
|
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||||
|
self.comboBox_logSelect = QtWidgets.QComboBox(self.tab_readlog)
|
||||||
|
self.comboBox_logSelect.setObjectName("comboBox_logSelect")
|
||||||
|
self.comboBox_logSelect.addItem("")
|
||||||
|
self.comboBox_logSelect.addItem("")
|
||||||
|
self.comboBox_logSelect.addItem("")
|
||||||
|
self.comboBox_logSelect.addItem("")
|
||||||
|
self.comboBox_logSelect.addItem("")
|
||||||
|
self.comboBox_logSelect.addItem("")
|
||||||
|
self.verticalLayout_2.addWidget(self.comboBox_logSelect)
|
||||||
|
self.textBrowser_logView = QtWidgets.QTextBrowser(self.tab_readlog)
|
||||||
|
self.textBrowser_logView.setObjectName("textBrowser_logView")
|
||||||
|
self.verticalLayout_2.addWidget(self.textBrowser_logView)
|
||||||
|
self.tabWidget.addTab(self.tab_readlog, "")
|
||||||
self.horizontalLayout_2.addWidget(self.tabWidget)
|
self.horizontalLayout_2.addWidget(self.tabWidget)
|
||||||
MainWindow.setCentralWidget(self.centralwidget)
|
MainWindow.setCentralWidget(self.centralwidget)
|
||||||
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
||||||
@ -120,6 +137,14 @@ class Ui_MainWindow(object):
|
|||||||
self.comboBox.setItemText(10, _translate("MainWindow", "VR_FPGA_Temp"))
|
self.comboBox.setItemText(10, _translate("MainWindow", "VR_FPGA_Temp"))
|
||||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_temp_all), _translate("MainWindow", "温度信息"))
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_temp_all), _translate("MainWindow", "温度信息"))
|
||||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_timeline_event), _translate("MainWindow", "事件时间线"))
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_timeline_event), _translate("MainWindow", "事件时间线"))
|
||||||
|
self.comboBox_logSelect.setCurrentText(_translate("MainWindow", "IDL日志"))
|
||||||
|
self.comboBox_logSelect.setItemText(0, _translate("MainWindow", "IDL日志"))
|
||||||
|
self.comboBox_logSelect.setItemText(1, _translate("MainWindow", "审计日志"))
|
||||||
|
self.comboBox_logSelect.setItemText(2, _translate("MainWindow", "维护日志"))
|
||||||
|
self.comboBox_logSelect.setItemText(3, _translate("MainWindow", "OS串口日志"))
|
||||||
|
self.comboBox_logSelect.setItemText(4, _translate("MainWindow", "运行状态"))
|
||||||
|
self.comboBox_logSelect.setItemText(5, _translate("MainWindow", "部件日志"))
|
||||||
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_readlog), _translate("MainWindow", "日志查看"))
|
||||||
self.menu.setTitle(_translate("MainWindow", "文件"))
|
self.menu.setTitle(_translate("MainWindow", "文件"))
|
||||||
self.actionUpload_log.setText(_translate("MainWindow", "打开"))
|
self.actionUpload_log.setText(_translate("MainWindow", "打开"))
|
||||||
self.actionUpload_log.setStatusTip(_translate("MainWindow", "上传日志文件到程序中"))
|
self.actionUpload_log.setStatusTip(_translate("MainWindow", "上传日志文件到程序中"))
|
||||||
|
|||||||
58
src/ZiJin_mergeLog.py
Normal file
58
src/ZiJin_mergeLog.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import os
|
||||||
|
import utils
|
||||||
|
|
||||||
|
project_root = utils.get_project_root()
|
||||||
|
cache_dir = os.path.join(project_root, "okd_tmp")
|
||||||
|
onekeylog_dir = os.path.join(cache_dir, "onekeylog")
|
||||||
|
extlog_dir = os.path.join(onekeylog_dir, "log")
|
||||||
|
sollog_dir = os.path.join(extlog_dir, "sollog")
|
||||||
|
running_dir = os.path.join(onekeylog_dir, "runningdata")
|
||||||
|
comp_dir = os.path.join(onekeylog_dir, "component")
|
||||||
|
|
||||||
|
# cache_{file}
|
||||||
|
cache_idl = os.path.join(cache_dir, "merge_idl.log")
|
||||||
|
cache_audit = os.path.join(cache_dir, "merge_audit.log")
|
||||||
|
cache_maintenace = os.path.join(cache_dir, "merge_maintenance.log")
|
||||||
|
cache_console = os.path.join(cache_dir, "os_sol.log")
|
||||||
|
running_file = os.path.join(running_dir, "rundatainfo.log")
|
||||||
|
compfile = os.path.join(comp_dir, "component.log")
|
||||||
|
|
||||||
|
def merge_all_log_to_root():
|
||||||
|
# 1.融合处理IDL日志, 已在parse_idl中整合, pass
|
||||||
|
|
||||||
|
# 2.融合审计日志
|
||||||
|
audit_log = os.path.join(extlog_dir, "audit.log")
|
||||||
|
utils.merge_logrotate_files(audit_log, 2, cache_audit)
|
||||||
|
|
||||||
|
# 3.融合维护日志
|
||||||
|
# 暂时设定为最多解压四份,共合并五份日志
|
||||||
|
maintenance_log = os.path.join(extlog_dir, "maintenance.log")
|
||||||
|
utils.extract_maintenancelog_gz_files(extlog_dir, extlog_dir, 4)
|
||||||
|
utils.merge_logrotate_files(maintenance_log, 5, cache_maintenace)
|
||||||
|
|
||||||
|
# 4.融合OS串口日志
|
||||||
|
sol_log = os.path.join(sollog_dir, "SOLHostCapture.log")
|
||||||
|
utils.merge_logrotate_files(sol_log, 2, cache_console)
|
||||||
|
|
||||||
|
def get_logfile_path_by_key(key):
|
||||||
|
match key:
|
||||||
|
case "log_idl":
|
||||||
|
logfile = cache_idl
|
||||||
|
case "log_audit":
|
||||||
|
logfile = cache_audit
|
||||||
|
case "log_maintenance":
|
||||||
|
logfile = cache_maintenace
|
||||||
|
case "log_osconsole":
|
||||||
|
logfile = cache_console
|
||||||
|
case "log_run":
|
||||||
|
logfile = running_file
|
||||||
|
case "log_comp":
|
||||||
|
logfile = compfile
|
||||||
|
case _ :
|
||||||
|
logfile = ""
|
||||||
|
|
||||||
|
return logfile
|
||||||
|
|
||||||
|
def program_main():
|
||||||
|
merge_all_log_to_root()
|
||||||
|
return True
|
||||||
@ -38,3 +38,26 @@ class DiagnoseThread(QThread):
|
|||||||
"""停止线程"""
|
"""停止线程"""
|
||||||
self.is_running = False
|
self.is_running = False
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
class FileReaderThread(QThread):
|
||||||
|
# 定义信号,用于传递读取到的文本块和完成状态
|
||||||
|
text_chunk_ready = pyqtSignal(str)
|
||||||
|
finished = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, file_path, chunk_size=4096):
|
||||||
|
super().__init__()
|
||||||
|
self.file_path = file_path
|
||||||
|
self.chunk_size = chunk_size # 每次读取的块大小
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try:
|
||||||
|
with open(self.file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
||||||
|
while True:
|
||||||
|
chunk = f.read(self.chunk_size) # 分块读取
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
self.text_chunk_ready.emit(chunk) # 发送文本块到主线程
|
||||||
|
self.finished.emit()
|
||||||
|
except Exception as e:
|
||||||
|
self.text_chunk_ready.emit(f"读取文件错误: {str(e)}")
|
||||||
|
self.finished.emit()
|
||||||
@ -1,7 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
|
import service
|
||||||
from PyQt5.QtWidgets import QFileDialog
|
from PyQt5.QtWidgets import QFileDialog
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from PyQt5.QtGui import QDragEnterEvent, QDropEvent
|
from PyQt5.QtGui import QDragEnterEvent, QDropEvent, QTextCharFormat
|
||||||
|
from background_task import FileReaderThread
|
||||||
|
|
||||||
class EventHandler:
|
class EventHandler:
|
||||||
def __init__(self, main_window):
|
def __init__(self, main_window):
|
||||||
@ -19,6 +21,8 @@ class EventHandler:
|
|||||||
self.main_window.graphicsView.wheelEvent = self.zoom_with_mouse_wheel
|
self.main_window.graphicsView.wheelEvent = self.zoom_with_mouse_wheel
|
||||||
# 窗口 resize 事件
|
# 窗口 resize 事件
|
||||||
self.main_window.resizeEvent = self.resize_event
|
self.main_window.resizeEvent = self.resize_event
|
||||||
|
# 日志下拉框变化事件
|
||||||
|
self.main_window.comboBox_logSelect.currentTextChanged.connect(self.logSelect_on_combo_changed)
|
||||||
|
|
||||||
def upload_file(self):
|
def upload_file(self):
|
||||||
"""打开文件选择对话框"""
|
"""打开文件选择对话框"""
|
||||||
@ -41,6 +45,27 @@ class EventHandler:
|
|||||||
self.main_window.parse_status.diag_complete_status
|
self.main_window.parse_status.diag_complete_status
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def logview_append_text(self, chunk):
|
||||||
|
# 在主线程中追加文本
|
||||||
|
self.main_window.textBrowser_logView.insertPlainText(chunk)
|
||||||
|
# 自动滚动到底部
|
||||||
|
self.main_window.textBrowser_logView.moveCursor(
|
||||||
|
self.main_window.textBrowser_logView.textCursor().End)
|
||||||
|
|
||||||
|
def logSelect_on_combo_changed(self, selected_text):
|
||||||
|
key = self.main_window.comboBox_logSelect_text_dict.get(selected_text)
|
||||||
|
if key:
|
||||||
|
filepath = service.get_logfile_path(key)
|
||||||
|
if not os.path.exists(filepath):
|
||||||
|
self.main_window.textBrowser_logView.setText("文件不存在/未上传日志")
|
||||||
|
return
|
||||||
|
self.main_window.textBrowser_logView.clear()
|
||||||
|
|
||||||
|
self.main_window.reader_thread = FileReaderThread(filepath)
|
||||||
|
self.main_window.reader_thread.text_chunk_ready.connect(self.logview_append_text)
|
||||||
|
# self.main_window.reader_thread.finished.connect(self.on_read_finished)
|
||||||
|
self.main_window.reader_thread.start()
|
||||||
|
|
||||||
def dragEnterEvent(self, event: QDragEnterEvent):
|
def dragEnterEvent(self, event: QDragEnterEvent):
|
||||||
"""拖入事件:判断是否为文件"""
|
"""拖入事件:判断是否为文件"""
|
||||||
if event.mimeData().hasUrls():
|
if event.mimeData().hasUrls():
|
||||||
|
|||||||
@ -30,10 +30,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.ui_init.init_textbrowser_style()
|
self.ui_init.init_textbrowser_style()
|
||||||
self.ui_init.init_tableView_alert_model()
|
self.ui_init.init_tableView_alert_model()
|
||||||
self.ui_init.re_init_time_line_tab()
|
self.ui_init.re_init_time_line_tab()
|
||||||
|
self.ui_init.init_textbrowser_logview_style()
|
||||||
# 事件绑定(按钮、拖放、下拉框)
|
# 事件绑定(按钮、拖放、下拉框)
|
||||||
self.event_handler.bind_events()
|
self.event_handler.bind_events()
|
||||||
self.event_handler.patch_drag_events() # 将拖放事件绑定到主窗口
|
self.event_handler.patch_drag_events() # 将拖放事件绑定到主窗口
|
||||||
# 初始化下拉框映射字典(跨模块使用,放在主窗口)
|
# 初始化温度图下拉框映射字典(跨模块使用,放在主窗口)
|
||||||
self.combo_box_text_dict = {
|
self.combo_box_text_dict = {
|
||||||
"ALL_Temp": "all",
|
"ALL_Temp": "all",
|
||||||
"CPU_Temp": "cpu",
|
"CPU_Temp": "cpu",
|
||||||
@ -51,3 +52,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
"OPT2_Temp": "opt2",
|
"OPT2_Temp": "opt2",
|
||||||
"OPT3_Temp": "opt3",
|
"OPT3_Temp": "opt3",
|
||||||
}
|
}
|
||||||
|
# 初始化日志窗格下拉框映射字典
|
||||||
|
self.reader_thread = None
|
||||||
|
self.comboBox_logSelect_text_dict = {
|
||||||
|
"IDL日志": "log_idl",
|
||||||
|
"审计日志": "log_audit",
|
||||||
|
"维护日志": "log_maintenance",
|
||||||
|
"OS串口日志": "log_osconsole",
|
||||||
|
"运行状态": "log_run",
|
||||||
|
"部件日志": "log_comp"
|
||||||
|
}
|
||||||
65
src/search_shortcut.py
Normal file
65
src/search_shortcut.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
from PyQt5.QtWidgets import QDialog, QHBoxLayout, QLineEdit, QLabel, QPushButton, QMessageBox
|
||||||
|
from PyQt5.QtGui import QTextCursor
|
||||||
|
|
||||||
|
class FindDialog(QDialog):
|
||||||
|
"""独立的查找对话框类,用于在文本中查找指定内容"""
|
||||||
|
def __init__(self, parent=None, text_browser=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.text_browser = text_browser
|
||||||
|
self.init_ui()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
self.setWindowTitle("查找")
|
||||||
|
self.setFixedSize(300, 80)
|
||||||
|
self.setModal(True) # 模态对话框,阻止对父窗口的操作
|
||||||
|
|
||||||
|
# 创建布局
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
|
||||||
|
# 查找输入框
|
||||||
|
self.find_input = QLineEdit()
|
||||||
|
self.find_input.setPlaceholderText("输入要查找的内容...")
|
||||||
|
self.find_input.returnPressed.connect(self.find_next) # 回车触发查找
|
||||||
|
|
||||||
|
# 查找按钮
|
||||||
|
self.find_btn = QPushButton("查找下一个")
|
||||||
|
self.find_btn.clicked.connect(self.find_next)
|
||||||
|
|
||||||
|
# 添加到布局
|
||||||
|
layout.addWidget(QLabel("查找:"))
|
||||||
|
layout.addWidget(self.find_input)
|
||||||
|
layout.addWidget(self.find_btn)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
# 让输入框获取焦点
|
||||||
|
self.find_input.setFocus()
|
||||||
|
|
||||||
|
def find_next(self):
|
||||||
|
"""查找下一个匹配项"""
|
||||||
|
if not self.text_browser:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 获取要查找的文本
|
||||||
|
find_text = self.find_input.text()
|
||||||
|
if not find_text:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 获取当前文本和光标
|
||||||
|
document = self.text_browser.document()
|
||||||
|
cursor = self.text_browser.textCursor()
|
||||||
|
|
||||||
|
# 从当前位置之后查找
|
||||||
|
cursor = document.find(find_text, cursor)
|
||||||
|
|
||||||
|
# 如果没找到,从头开始查找
|
||||||
|
if cursor.isNull():
|
||||||
|
cursor = QTextCursor(document)
|
||||||
|
cursor = document.find(find_text, cursor)
|
||||||
|
|
||||||
|
# 如果找到匹配项
|
||||||
|
if not cursor.isNull():
|
||||||
|
self.text_browser.setTextCursor(cursor)
|
||||||
|
self.text_browser.ensureCursorVisible() # 滚动到可见位置
|
||||||
|
else:
|
||||||
|
QMessageBox.information(self, "查找完成", f"找不到 '{find_text}'")
|
||||||
@ -5,6 +5,7 @@ import ZiJin_parse_sensorhistory as sensorparse
|
|||||||
import ZiJin_parse_baseinfo as baseinfo
|
import ZiJin_parse_baseinfo as baseinfo
|
||||||
import ZiJin_parse_idl as parseidl
|
import ZiJin_parse_idl as parseidl
|
||||||
import ZiJin_parse_event as zijin_event
|
import ZiJin_parse_event as zijin_event
|
||||||
|
import ZiJin_mergeLog as mergelog
|
||||||
|
|
||||||
class ServiceStatus():
|
class ServiceStatus():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -12,6 +13,7 @@ class ServiceStatus():
|
|||||||
self.sensorhistory_status = False
|
self.sensorhistory_status = False
|
||||||
self.baseinfo_status = False
|
self.baseinfo_status = False
|
||||||
self.parseidl_status = False
|
self.parseidl_status = False
|
||||||
|
self.mergelog_status = False
|
||||||
self.eventline_status = False
|
self.eventline_status = False
|
||||||
|
|
||||||
def set_sensorhistory_status(self, status):
|
def set_sensorhistory_status(self, status):
|
||||||
@ -38,6 +40,12 @@ class ServiceStatus():
|
|||||||
def get_eventline_status(self):
|
def get_eventline_status(self):
|
||||||
return self.eventline_status
|
return self.eventline_status
|
||||||
|
|
||||||
|
def set_mergelog_status(self, status):
|
||||||
|
self.mergelog_status = status
|
||||||
|
|
||||||
|
def get_mergelog_status(self):
|
||||||
|
return self.mergelog_status
|
||||||
|
|
||||||
def app_cache_init():
|
def app_cache_init():
|
||||||
project_root = utils.get_project_root()
|
project_root = utils.get_project_root()
|
||||||
cache_dir = os.path.join(project_root, "okd_tmp")
|
cache_dir = os.path.join(project_root, "okd_tmp")
|
||||||
@ -76,6 +84,9 @@ def is_idl_alert_empty():
|
|||||||
def get_timeline_event_json():
|
def get_timeline_event_json():
|
||||||
return zijin_event.get_event_json()
|
return zijin_event.get_event_json()
|
||||||
|
|
||||||
|
def get_logfile_path(key):
|
||||||
|
return mergelog.get_logfile_path_by_key(key)
|
||||||
|
|
||||||
def start_diagnose(parseStatus, filepath, progress_callback=None):
|
def start_diagnose(parseStatus, filepath, progress_callback=None):
|
||||||
"""
|
"""
|
||||||
执行诊断任务,添加进度回调
|
执行诊断任务,添加进度回调
|
||||||
@ -101,10 +112,15 @@ def start_diagnose(parseStatus, filepath, progress_callback=None):
|
|||||||
parseStatus.set_baseinfo_status(result_baseinfo)
|
parseStatus.set_baseinfo_status(result_baseinfo)
|
||||||
|
|
||||||
if progress_callback:
|
if progress_callback:
|
||||||
progress_callback(80, "正在解析告警信息...")
|
progress_callback(60, "正在解析告警信息...")
|
||||||
result_parseidl = parseidl.program_main()
|
result_parseidl = parseidl.program_main()
|
||||||
parseStatus.set_parseidl_status(result_parseidl)
|
parseStatus.set_parseidl_status(result_parseidl)
|
||||||
|
|
||||||
|
if progress_callback:
|
||||||
|
progress_callback(80, "正在整合日志文件...")
|
||||||
|
result_mergelog = mergelog.program_main()
|
||||||
|
parseStatus.set_mergelog_status(result_mergelog)
|
||||||
|
|
||||||
if progress_callback:
|
if progress_callback:
|
||||||
progress_callback(95, "正在生成时间线...")
|
progress_callback(95, "正在生成时间线...")
|
||||||
result_eventline = zijin_event.program_main()
|
result_eventline = zijin_event.program_main()
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
from PyQt5.QtWidgets import QVBoxLayout, QGraphicsScene
|
from PyQt5.QtWidgets import QVBoxLayout, QGraphicsScene, QShortcut
|
||||||
from PyQt5.QtGui import QPainter, QStandardItemModel
|
from PyQt5.QtGui import (QPainter, QStandardItemModel, QTextOption, QKeySequence,
|
||||||
|
QTextCharFormat, QBrush, QColor)
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
import timelineEvent
|
import timelineEvent
|
||||||
|
from search_shortcut import FindDialog
|
||||||
class UIInitializer:
|
class UIInitializer:
|
||||||
def __init__(self, main_window):
|
def __init__(self, main_window):
|
||||||
self.main_window = main_window # 持有主窗口引用
|
self.main_window = main_window # 持有主窗口引用
|
||||||
@ -80,3 +81,25 @@ class UIInitializer:
|
|||||||
self.main_window.tableView_alert.horizontalHeader().setSectionResizeMode(
|
self.main_window.tableView_alert.horizontalHeader().setSectionResizeMode(
|
||||||
self.main_window.tableView_alert.horizontalHeader().ResizeToContents
|
self.main_window.tableView_alert.horizontalHeader().ResizeToContents
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def show_find_dialog(self):
|
||||||
|
"""显示查找对话框"""
|
||||||
|
# 如果文本浏览器有内容才显示查找对话框
|
||||||
|
if self.main_window.textBrowser_logView.toPlainText():
|
||||||
|
dialog = FindDialog(self.main_window, self.main_window.textBrowser_logView)
|
||||||
|
dialog.exec_()
|
||||||
|
|
||||||
|
def init_textbrowser_logview_style(self):
|
||||||
|
# 关键设置:禁用自动换行,启用横向滚动条
|
||||||
|
self.main_window.textBrowser_logView.setWordWrapMode(QTextOption.NoWrap)
|
||||||
|
|
||||||
|
# 设置字体为等宽字体,更适合查看日志
|
||||||
|
font = self.main_window.textBrowser_logView.font()
|
||||||
|
font.setFamily("Consolas") # Windows系统
|
||||||
|
# font.setFamily("Monaco") # macOS系统
|
||||||
|
# font.setFamily("Monospace") # Linux系统
|
||||||
|
self.main_window.textBrowser_logView.setFont(font)
|
||||||
|
|
||||||
|
# 设置Ctrl+F快捷键
|
||||||
|
self.main_window.textBrowser_logView.find_shortcut = QShortcut(QKeySequence("Ctrl+F"), self.main_window)
|
||||||
|
self.main_window.textBrowser_logView.find_shortcut.activated.connect(self.show_find_dialog)
|
||||||
51
src/utils.py
51
src/utils.py
@ -3,7 +3,9 @@ import tarfile
|
|||||||
import shutil
|
import shutil
|
||||||
import stat
|
import stat
|
||||||
import re
|
import re
|
||||||
|
import gzip
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
from PyQt5.QtWidgets import QMessageBox
|
||||||
|
|
||||||
def show_error_message(parent, file_path):
|
def show_error_message(parent, file_path):
|
||||||
@ -398,3 +400,52 @@ def parse_idllog_line(log_line):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"解析日志行时出错: {str(e)}")
|
print(f"解析日志行时出错: {str(e)}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def extract_maintenancelog_gz_files(input_dir, output_dir, max_files=10):
|
||||||
|
"""
|
||||||
|
解压指定目录下的maintenancelog.1.gz到log.max_files.gz文件到目标目录
|
||||||
|
|
||||||
|
参数:
|
||||||
|
input_dir: 压缩文件所在的目录路径
|
||||||
|
output_dir: 解压后文件的保存目录路径
|
||||||
|
max_files: 最大文件编号,默认为10
|
||||||
|
"""
|
||||||
|
# 确保输入输出目录存在
|
||||||
|
input_path = Path(input_dir)
|
||||||
|
output_path = Path(output_dir)
|
||||||
|
|
||||||
|
# 创建输出目录(如果不存在)
|
||||||
|
output_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# 检查输入目录是否存在
|
||||||
|
if not input_path.exists() or not input_path.is_dir():
|
||||||
|
print(f"错误:输入目录 '{input_path}' 不存在或不是一个目录")
|
||||||
|
return
|
||||||
|
|
||||||
|
for i in range(1, max_files + 1):
|
||||||
|
# 压缩文件路径
|
||||||
|
gz_filename = input_path / f"maintenance.log.{i}.gz"
|
||||||
|
|
||||||
|
# 检查文件是否存在
|
||||||
|
if not gz_filename.exists() or not gz_filename.is_file():
|
||||||
|
print(f"文件 {gz_filename} 不存在,跳过")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 解压后的文件路径
|
||||||
|
output_filename = output_path / f"maintenance.log.{i}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 打开压缩文件并解压
|
||||||
|
with gzip.open(gz_filename, 'rb') as f_in:
|
||||||
|
with open(output_filename, 'wb') as f_out:
|
||||||
|
# 分块读取写入,处理大文件更高效
|
||||||
|
while True:
|
||||||
|
chunk = f_in.read(1024 * 1024) # 1MB块
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
f_out.write(chunk)
|
||||||
|
|
||||||
|
print(f"成功解压: {gz_filename} -> {output_filename}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"解压 {gz_filename} 时出错: {str(e)}")
|
||||||
Loading…
Reference in New Issue
Block a user