fix:修复日志tab栏以及日志读取

This commit is contained in:
spiritlhl
2025-11-02 11:31:37 +08:00
parent a7db4aca24
commit c7f2c2864e
8 changed files with 147 additions and 195 deletions

Binary file not shown.

View File

@@ -69,70 +69,3 @@ cp ../ecs/goecs-linux-amd64 jniLibs/x86_64/libgoecs.so && \
chmod 755 jniLibs/*/libgoecs.so && \
ls -lh jniLibs/*/libgoecs.so
```
## 测试验证
### 1. 验证 APK 包含 .so 文件
```bash
unzip -l your-app.apk | grep "lib/"
# 应该看到:
# lib/arm64-v8a/libgoecs.so
# lib/x86_64/libgoecs.so
```
### 2. 在设备上验证安装位置
```bash
# 安装 APK
adb install your-app.apk
# 查看安装位置
adb shell pm path com.oneclickvirt.goecs
# 查看 native library 目录
adb shell ls -l /data/app/com.oneclickvirt.goecs-*/lib/arm64/
# 测试执行
adb shell
run-as com.oneclickvirt.goecs
cd /data/app/com.oneclickvirt.goecs-*/lib/arm64/
./libgoecs.so --help
```
### 3. 查看应用日志
```bash
# 实时查看日志
adb logcat | grep -E "(goecs|oneclickvirt)"
# 只看错误
adb logcat *:E | grep goecs
```
## 故障排除
如果看到 "fork/exec" 错误:
1. **检查文件是否存在**
```bash
adb shell run-as com.oneclickvirt.goecs find /data/app -name "libgoecs.so"
```
2. **检查编译架构是否匹配设备**
```bash
adb shell getprop ro.product.cpu.abi
# arm64-v8a -> 需要 jniLibs/arm64-v8a/libgoecs.so
# x86_64 -> 需要 jniLibs/x86_64/libgoecs.so
```
3. **验证文件不是空的**
```bash
ls -lh jniLibs/*/libgoecs.so
# 文件应该有合理的大小几MB到几十MB
```
4. **检查应用日志中的详细错误信息**
- embedding 代码会输出所有检查过的路径
- 查看 logcat 获取详细信息

View File

@@ -42,6 +42,9 @@ func runGUIMode() {
myApp := app.NewWithID("com.oneclickvirt.goecs")
myApp.Settings().SetTheme(&ui.CustomTheme{})
// 设置为浅色主题
myApp.Settings().SetTheme(&ui.CustomTheme{})
testUI := ui.NewTestUI(myApp)
testUI.Window.ShowAndRun()
}

View File

@@ -12,7 +12,8 @@ type CustomTheme struct{}
var _ fyne.Theme = (*CustomTheme)(nil)
func (m *CustomTheme) Color(name fyne.ThemeColorName, variant fyne.ThemeVariant) color.Color {
return theme.DefaultTheme().Color(name, variant)
// 强制使用浅色主题
return theme.DefaultTheme().Color(name, theme.VariantLight)
}
func (m *CustomTheme) Icon(name fyne.ThemeIconName) fyne.Resource {

View File

@@ -2,10 +2,8 @@ package ui
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
@@ -136,13 +134,6 @@ func (ui *TestUI) startTests() {
ui.ProgressBar.Show()
ui.StatusLabel.SetText("测试运行中...")
// 如果启用了日志,显示日志标签页
if ui.LogCheck != nil && ui.LogCheck.Checked {
ui.showLogTab()
} else {
ui.hideLogTab()
}
// 清空终端输出
if ui.Terminal != nil {
ui.Terminal.Clear()
@@ -204,119 +195,162 @@ func (ui *TestUI) exportResults() {
}, ui.Window)
}
// showLogTab 显示日志标签页
func (ui *TestUI) showLogTab() {
// 如果日志标签页还不存在,创建它
if ui.LogTab == nil {
ui.LogTab = ui.createLogTab()
logTabItem := container.NewTabItem("日志查看", ui.LogTab)
ui.MainTabs.Append(logTabItem)
}
// 切换到日志标签页
ui.MainTabs.SelectIndex(2) // 0=配置, 1=结果, 2=日志
}
// hideLogTab 隐藏日志标签页
func (ui *TestUI) hideLogTab() {
// 如果有日志标签页,移除它
if ui.LogTab != nil && len(ui.MainTabs.Items) > 2 {
ui.MainTabs.Remove(ui.MainTabs.Items[2])
ui.LogTab = nil
ui.LogViewer = nil
// onLogCheckChanged 当日志复选框状态改变时调用
func (ui *TestUI) onLogCheckChanged(checked bool) {
if checked {
// 勾选时添加日志标签页
ui.addLogTab()
} else {
// 取消勾选时移除日志标签页
ui.removeLogTab()
}
}
// createLogTab 创建日志查看标签页
func (ui *TestUI) createLogTab() *fyne.Container {
// addLogTab 添加日志标签页
func (ui *TestUI) addLogTab() {
// 如果日志标签页已存在,不重复添加
if ui.LogTab != nil {
return
}
// 创建日志查看器
ui.LogViewer = widget.NewMultiLineEntry()
ui.LogViewer.SetPlaceHolder("日志内容将在测试运行时显示...")
ui.LogViewer.Wrapping = fyne.TextWrapWord
ui.LogViewer.SetText("日志文件内容将在这里显示...")
ui.LogViewer.Disable() // 只读
// 刷新按钮
refreshButton := widget.NewButton("刷新日志", ui.refreshLog)
// 清空按钮
clearLogButton := widget.NewButton("清空显示", func() {
if ui.LogViewer != nil {
ui.LogViewer.SetText("")
}
// 刷新日志按钮
refreshButton := widget.NewButton("刷新日志", func() {
ui.refreshLogFromFile()
})
topBar := container.NewHBox(
// 清空日志按钮
clearLogButton := widget.NewButton("清空日志", func() {
ui.LogContent = ""
ui.LogViewer.SetText("")
})
// 导出日志按钮
exportLogButton := widget.NewButton("导出日志", ui.exportLogContent)
// 按钮栏
buttonBar := container.NewHBox(
refreshButton,
clearLogButton,
exportLogButton,
)
// 日志内容区域
logScroll := container.NewScroll(ui.LogViewer)
return container.NewBorder(
topBar, // Top: 操作按钮
// 组合布局
logContent := container.NewBorder(
buttonBar, // Top: 按钮栏
nil, // Bottom
nil, // Left
nil, // Right
logScroll, // Center: 日志内容
)
// 创建并添加日志标签页
ui.LogTab = container.NewTabItem("日志", logContent)
ui.MainTabs.Append(ui.LogTab)
// 初始化日志内容
ui.LogContent = ""
}
// refreshLog 刷新日志内容
func (ui *TestUI) refreshLog() {
// removeLogTab 移除日志标签页
func (ui *TestUI) removeLogTab() {
if ui.LogTab == nil {
return
}
// 从标签页容器中移除
ui.MainTabs.Remove(ui.LogTab)
ui.LogTab = nil
ui.LogViewer = nil
ui.LogContent = ""
}
// refreshLogContent 刷新日志内容
func (ui *TestUI) refreshLogContent() {
if ui.LogViewer == nil {
return
}
// 获取当前目录
currentDir, err := os.Getwd()
if err != nil {
ui.LogViewer.SetText("错误: 无法获取当前目录\n" + err.Error())
return
// 显示存储的日志内容
if ui.LogContent != "" {
ui.LogViewer.SetText(ui.LogContent)
} else {
ui.LogViewer.SetText("暂无日志内容\n\n日志将在测试运行时自动更新。")
}
// 查找所有 .log 文件
logFiles, err := filepath.Glob(filepath.Join(currentDir, "*.log"))
if err != nil {
ui.LogViewer.SetText("错误: 无法搜索日志文件\n" + err.Error())
return
}
if len(logFiles) == 0 {
ui.LogViewer.SetText("当前目录下没有找到 .log 文件\n\n请确保已启用日志记录并运行测试。")
return
}
// 找到最新的日志文件
var latestLog string
var latestTime time.Time
for _, logFile := range logFiles {
info, err := os.Stat(logFile)
if err != nil {
continue
}
if latestLog == "" || info.ModTime().After(latestTime) {
latestLog = logFile
latestTime = info.ModTime()
}
}
if latestLog == "" {
ui.LogViewer.SetText("没有找到有效的日志文件")
return
}
// 读取日志文件内容
content, err := os.ReadFile(latestLog)
if err != nil {
ui.LogViewer.SetText("错误: 无法读取日志文件 " + latestLog + "\n" + err.Error())
return
}
// 显示日志内容
logContent := "日志文件: " + filepath.Base(latestLog) + "\n"
logContent += "修改时间: " + latestTime.Format("2006-01-02 15:04:05") + "\n"
logContent += strings.Repeat("=", 60) + "\n\n"
logContent += string(content)
ui.LogViewer.SetText(logContent)
}
// refreshLogFromFile 从 ecs.log 文件读取日志内容
func (ui *TestUI) refreshLogFromFile() {
if ui.LogViewer == nil {
return
}
// ecs.log 文件应该在当前工作目录下
logFilePath := "ecs.log"
// 尝试读取日志文件
content, err := os.ReadFile(logFilePath)
if err != nil {
// 如果文件不存在或无法读取,显示错误信息
if os.IsNotExist(err) {
ui.LogViewer.SetText("日志文件 ecs.log 不存在\n\n可能测试未生成日志文件或文件已被删除。")
} else {
ui.LogViewer.SetText(fmt.Sprintf("无法读取日志文件: %v", err))
}
return
}
// 更新日志内容
ui.LogContent = string(content)
ui.LogViewer.SetText(ui.LogContent)
}
// exportLogContent 导出日志内容
func (ui *TestUI) exportLogContent() {
if ui.LogViewer == nil || ui.LogViewer.Text == "" {
dialog.ShowInformation("提示", "没有可导出的日志内容", ui.Window)
return
}
// 使用文件保存对话框
dialog.ShowFileSave(func(writer fyne.URIWriteCloser, err error) {
if err != nil {
dialog.ShowError(err, ui.Window)
return
}
if writer == nil {
return
}
defer writer.Close()
// 写入日志内容
_, err = writer.Write([]byte(ui.LogViewer.Text))
if err != nil {
dialog.ShowError(err, ui.Window)
return
}
dialog.ShowInformation("成功", "日志已成功导出", ui.Window)
}, ui.Window)
}
// AppendLog 向日志内容追加文本
func (ui *TestUI) AppendLog(text string) {
if !ui.LogCheck.Checked || ui.LogViewer == nil {
return
}
ui.Mu.Lock()
defer ui.Mu.Unlock()
ui.LogContent += text
ui.LogViewer.SetText(ui.LogContent)
}

View File

@@ -16,11 +16,6 @@ func (ui *TestUI) runTestsWithExecutor() {
startTime := time.Now()
// 清空终端并显示开始信息
ui.Terminal.AppendText("==========================================\n")
ui.Terminal.AppendText(" 融合怪测试 - 开始执行\n")
ui.Terminal.AppendText("==========================================\n\n")
// 创建命令执行器
executor, err := NewCommandExecutor(ui, ui.CancelCtx)
if err != nil {
@@ -32,8 +27,7 @@ func (ui *TestUI) runTestsWithExecutor() {
// 显示将要执行的命令
cmdPreview := executor.GetCommandPreview()
ui.Terminal.AppendText(fmt.Sprintf("执行命令: %s\n\n", cmdPreview))
ui.Terminal.AppendText("==========================================\n\n")
ui.Terminal.AppendText(fmt.Sprintf("执行命令: %s\n", cmdPreview))
// 更新进度
ui.ProgressBar.SetValue(0.1)
@@ -45,36 +39,22 @@ func (ui *TestUI) runTestsWithExecutor() {
// 显示结束信息
endTime := time.Now()
duration := endTime.Sub(startTime)
minutes := int(duration.Minutes())
seconds := int(duration.Seconds()) % 60
ui.Terminal.AppendText("\n\n==========================================\n")
_ = duration // 避免未使用警告
if err != nil {
ui.Terminal.AppendText(fmt.Sprintf("错误: %v\n", err))
ui.Terminal.AppendText(fmt.Sprintf("\n错误: %v\n", err))
ui.StatusLabel.SetText("测试失败")
} else if ui.isCancelled() {
ui.Terminal.AppendText("测试被用户中断\n")
ui.Terminal.AppendText("\n测试被用户中断\n")
ui.StatusLabel.SetText("测试已停止")
} else {
language := "zh"
if ui.LanguageSelect.Selected == "English" {
language = "en"
}
if language == "zh" {
ui.Terminal.AppendText(fmt.Sprintf("花费时间: %d 分 %d 秒\n", minutes, seconds))
} else {
ui.Terminal.AppendText(fmt.Sprintf("Cost Time: %d min %d sec\n", minutes, seconds))
}
ui.StatusLabel.SetText("测试完成")
ui.ProgressBar.SetValue(1.0)
// 如果启用了日志,自动刷新日志内容
if ui.LogCheck != nil && ui.LogCheck.Checked {
time.Sleep(500 * time.Millisecond) // 等待日志文件写入完成
ui.refreshLog()
ui.refreshLogFromFile()
}
}

View File

@@ -65,7 +65,7 @@ func (ui *TestUI) createOptionsPanel() fyne.CanvasObject {
ui.PingCheck = widget.NewCheck("三网PING值检测", nil)
ui.PingCheck.Checked = false
ui.LogCheck = widget.NewCheck("启用日志记录", nil)
ui.LogCheck = widget.NewCheck("启用日志记录", ui.onLogCheckChanged)
ui.LogCheck.Checked = false
// 全选/取消全选按钮

View File

@@ -54,9 +54,10 @@ type TestUI struct {
StatusLabel *widget.Label
// 日志相关
LogViewer *widget.Entry // 日志查看器
LogTab *fyne.Container // 日志标签页内容
MainTabs *container.AppTabs // 主标签页容器
LogViewer *widget.Entry // 日志查看器
LogTab *container.TabItem // 日志标签页
MainTabs *container.AppTabs // 主标签页容器
LogContent string // 日志内容存储
// 运行状态
IsRunning bool