v0.18.12:出問題時一鍵打開紀錄檔資料夾(leo:「不能用一個 debug mode?」)
leo 08-06:「不能用一個 debug mode,就是它會把 log 寫在一個檔案?」
## 回答:log 一直都在寫,缺的是「找得到」
`~/.arcrun-rag/collector.log`(含 collector 的 stderr,以 `[stderr]` 開頭)
與 `app.log` 從 t14 就在寫。這次 Windows 事故的真正死因
(`config 缺必填欄位:manifest`)**一直躺在 collector.log 裡**,
但使用者只看得到畫面上一句話,沒有任何入口通到那些檔案。
⇒ **不做「debug mode 開關」**(多一個要教使用者的東西,而且出事當下才想到要開就來不及了),
改成**永遠寫、出事時一鍵打開**:
- `OpenLogFolder()` 綁定(Windows 走 explorer/Mac 走 open/其餘 xdg-open)
- 首頁在 `engineTrouble` 時才長出「需要回報這個問題?」卡,附按鈕與**路徑文字**
(按鈕失效時仍找得到)。沒事時不顯示——否則會變常駐噪音,真出事反而沒人看。
## 真機證據:v0.18.10 的「說出死因」有效
leo 的 Windows 畫面實拍:
「同步引擎一直啟動失敗 / 已自動重試 8 次都失敗,所以重新開啟也沒有用。
原因:collector direct: config 缺必填欄位:manifest(exit status 2)」
⇒ **與 v0.18.11 修的根因一字不差**,診斷鏈完整閉合:
症狀(閃爍)→ 機制(子行程 exit 2 無限重拉)→ 死因(config 缺 manifest)→ 修正。
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"v0.18.9": "8be9260eb542f527",
|
||||
"v0.18.10": "a440f044a849b7f2",
|
||||
"v0.18.11": "1538689e181444f6"
|
||||
"v0.18.11": "1538689e181444f6",
|
||||
"v0.18.12": "ce37982f05d8cb5b"
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
runtime2 "runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -196,6 +198,10 @@ type UIState struct {
|
||||
ExtractedOK int `json:"extractedOK"` // 首頁「已整理幾份」
|
||||
Steps []Step `json:"steps"` // 首頁狀態時間軸(leo #6)
|
||||
Skipped *UISkipped `json:"skipped"` // 讀不了的檔(沒有就是 null,前端不畫)
|
||||
// EngineTrouble=同步引擎有問題(沒在跑/一直啟動失敗)⇒ 前端才長出「回報問題」卡。
|
||||
// 沒事時不顯示,避免把「哪裡看 log」變成常駐噪音。
|
||||
EngineTrouble bool `json:"engineTrouble"`
|
||||
LogFolder string `json:"logFolder"`
|
||||
}
|
||||
|
||||
// UISkipped=首頁那張「這些檔案現在還處理不了」的卡。
|
||||
@@ -343,6 +349,10 @@ func (a *App) GetState() UIState {
|
||||
st.Syncing, st.StatusBig, st.StatusSub = describeStatus(sync)
|
||||
st.Steps = buildSteps(sync, st.Syncing)
|
||||
st.Skipped = buildSkipped(sync)
|
||||
// 引擎有問題才把「回報問題」卡叫出來(含記錄檔路徑)。
|
||||
// 沒事時不顯示——否則「哪裡看 log」會變成常駐噪音,真出事時反而沒人看。
|
||||
st.EngineTrouble = !collectorAlive()
|
||||
st.LogFolder = appDir()
|
||||
return st
|
||||
}
|
||||
|
||||
@@ -543,6 +553,36 @@ func (a *App) SetAI(useGemini bool, key string) error {
|
||||
// OpenURL 用系統瀏覽器開網址(下載頁/說明文件)。
|
||||
func (a *App) OpenURL(u string) { runtime.BrowserOpenURL(a.ctx, u) }
|
||||
|
||||
// OpenLogFolder 在檔案總管/Finder 裡打開記錄檔資料夾。
|
||||
//
|
||||
// 🔴 leo 2026-08-06:「不能用一個 debug mode,就是它會把 log 寫在一個檔案?」
|
||||
//
|
||||
// 答:**log 一直都有寫**(`~/.arcrun-rag/` 下的 collector.log 與 app.log,
|
||||
// collector 的 stderr 也以 `[stderr]` 開頭落在裡面)。
|
||||
// 缺的不是「有沒有寫」,是**使用者找不到**——出事時他只看得到畫面上那句話,
|
||||
// 沒有任何入口把他帶到檔案。這次 Windows 事故就卡在這:真正的死因
|
||||
// (config 缺 manifest)一直躺在 collector.log 裡,沒人看得到。
|
||||
// ⇒ 不做「debug mode 開關」(多一個要教使用者的東西),而是**永遠寫、一鍵打開**。
|
||||
func (a *App) OpenLogFolder() error {
|
||||
dir := appDir()
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
switch runtime2.GOOS {
|
||||
case "windows":
|
||||
// explorer 開啟後回傳非 0 是常態(它不等視窗關閉),所以不看 error。
|
||||
_ = exec.Command("explorer", dir).Start()
|
||||
case "darwin":
|
||||
return exec.Command("open", dir).Start()
|
||||
default:
|
||||
return exec.Command("xdg-open", dir).Start()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LogFolderPath 給畫面顯示用(讓使用者就算按鈕失效也知道去哪找)。
|
||||
func (a *App) LogFolderPath() string { return appDir() }
|
||||
|
||||
// ── 托盤會呼叫的兩個動作(t194)──
|
||||
|
||||
// ShowWindow 把主視窗叫出來並帶到前景。
|
||||
|
||||
@@ -213,6 +213,7 @@ function renderPage() {
|
||||
function wire() {
|
||||
const on = (id, fn) => { const e = $(id); if (e) e.onclick = fn; };
|
||||
on('uDocs', () => go.OpenURL('https://rag.arcrun.dev/docs/'));
|
||||
on('hLogs', () => go.OpenLogFolder());
|
||||
on('hAcct', showConnect); on('obConnect', showConnect);
|
||||
on('obInstall', () => go.OpenURL('https://install.arcrun.dev/'));
|
||||
on('aiSave', saveAI);
|
||||
|
||||
Reference in New Issue
Block a user