Skip to content

Commit 94fb5d1

Browse files
Enhance diagnostics logging: add application log section, improve crash dump handling, and allow custom log output destination (jetkvm#1081)
1 parent 2f3173b commit 94fb5d1

4 files changed

Lines changed: 50 additions & 17 deletions

File tree

internal/diagnostics/diagnostics.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
package diagnostics
44

55
import (
6+
"io"
7+
68
"github.com/jetkvm/kvm/internal/logging"
79
"github.com/rs/zerolog"
810
)
@@ -29,6 +31,8 @@ type SessionInfo struct {
2931
type Options struct {
3032
// GetSessionInfo returns session diagnostics. Optional.
3133
GetSessionInfo func() SessionInfo
34+
// Writer is an optional output destination. If set, logs go here instead of default.
35+
Writer io.Writer
3236
}
3337

3438
// Diagnostics provides comprehensive system diagnostics logging.
@@ -38,7 +42,12 @@ type Diagnostics struct {
3842
}
3943

4044
// New creates a new Diagnostics instance using the default diagnostics logger.
45+
// If opts.Writer is set, logs are written there instead of the default logger.
4146
func New(opts Options) *Diagnostics {
47+
if opts.Writer != nil {
48+
logger := zerolog.New(opts.Writer)
49+
return &Diagnostics{logger: &logger, options: opts}
50+
}
4251
return NewWithLogger(diagLogger, opts)
4352
}
4453

jsonrpc.go

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -679,8 +679,24 @@ func rpcResetConfig() error {
679679
func rpcGetDiagnostics() (string, error) {
680680
var sb strings.Builder
681681

682-
// Trigger diagnostics logging (will be written to last.log)
682+
// Section 1: Application log (last.log) - last 500 lines
683+
sb.WriteString("=== APPLICATION LOG ===\n")
684+
if data, err := os.ReadFile(supervisor.AppLogPath); err == nil {
685+
content := cleanLogOutput(string(data))
686+
lines := strings.Split(content, "\n")
687+
if len(lines) > 500 {
688+
content = "... (truncated, showing last 500 lines)\n" + strings.Join(lines[len(lines)-500:], "\n")
689+
}
690+
sb.WriteString(content)
691+
} else {
692+
sb.WriteString(fmt.Sprintf("Error reading log: %v\n", err))
693+
}
694+
sb.WriteString("\n\n")
695+
696+
// Collect diagnostics to a buffer (not to last.log)
697+
var diagBuf strings.Builder
683698
diag := diagnostics.New(diagnostics.Options{
699+
Writer: &diagBuf,
684700
GetSessionInfo: func() diagnostics.SessionInfo {
685701
info := diagnostics.SessionInfo{
686702
ActiveSessions: getActiveSessions(),
@@ -698,16 +714,12 @@ func rpcGetDiagnostics() (string, error) {
698714
})
699715
diag.LogAll("download")
700716

701-
// Section 1: Application log (last.log)
702-
sb.WriteString("=== APPLICATION LOG ===\n")
703-
if data, err := os.ReadFile(supervisor.AppLogPath); err == nil {
704-
sb.WriteString(cleanLogOutput(string(data)))
705-
} else {
706-
sb.WriteString(fmt.Sprintf("Error reading log: %v\n", err))
707-
}
708-
sb.WriteString("\n\n")
717+
// Section 2: System diagnostics
718+
sb.WriteString("=== SYSTEM DIAGNOSTICS ===\n")
719+
sb.WriteString(diagBuf.String())
720+
sb.WriteString("\n")
709721

710-
// Section 2: Last crash log
722+
// Section 3: Last crash log
711723
lastCrashPath := filepath.Join(supervisor.ErrorDumpDir, supervisor.ErrorDumpLastFile)
712724
sb.WriteString("=== LAST CRASH LOG ===\n")
713725
if data, err := os.ReadFile(lastCrashPath); err == nil {
@@ -717,7 +729,7 @@ func rpcGetDiagnostics() (string, error) {
717729
}
718730
sb.WriteString("\n\n")
719731

720-
// Section 3: Last 3 crash dumps (excluding last-crash.log)
732+
// Section 4: Recent crash dumps (excluding last-crash.log)
721733
sb.WriteString("=== RECENT CRASH DUMPS ===\n")
722734
if entries, err := os.ReadDir(supervisor.ErrorDumpDir); err == nil {
723735
type fileInfo struct {
@@ -743,15 +755,25 @@ func rpcGetDiagnostics() (string, error) {
743755
sort.Slice(crashFiles, func(i, j int) bool {
744756
return crashFiles[i].modTime.After(crashFiles[j].modTime)
745757
})
746-
// Take last 3
747-
if len(crashFiles) > 15 {
748-
crashFiles = crashFiles[:15]
758+
759+
// Take 12 most recent crash dumps
760+
if len(crashFiles) > 12 {
761+
crashFiles = crashFiles[:12]
749762
}
750-
for _, cf := range crashFiles {
763+
764+
for i, cf := range crashFiles {
751765
sb.WriteString(fmt.Sprintf("--- %s ---\n", cf.name))
752766
crashPath := filepath.Join(supervisor.ErrorDumpDir, cf.name)
753767
if data, err := os.ReadFile(crashPath); err == nil {
754-
sb.WriteString(cleanLogOutput(string(data)))
768+
content := cleanLogOutput(string(data))
769+
// First file is full, rest are last 50 lines
770+
if i > 0 {
771+
lines := strings.Split(content, "\n")
772+
if len(lines) > 100 {
773+
content = "... (truncated)\n" + strings.Join(lines[len(lines)-50:], "\n")
774+
}
775+
}
776+
sb.WriteString(content)
755777
} else {
756778
sb.WriteString(fmt.Sprintf("Error reading: %v\n", err))
757779
}
@@ -765,7 +787,7 @@ func rpcGetDiagnostics() (string, error) {
765787
}
766788
sb.WriteString("\n")
767789

768-
// Section 4: Configuration
790+
// Section 5: Configuration
769791
sb.WriteString("=== CONFIGURATION ===\n")
770792
if data, err := os.ReadFile(configPath); err == nil {
771793
sb.WriteString(string(data))

ui/src/components/FailSafeModeOverlay.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ Please attach the recovery logs file that was downloaded to your computer:
145145
size="SM"
146146
disabled={isDownloadingLogs}
147147
LeadingIcon={GitHubIcon}
148+
loading={isDownloadingLogs}
148149
text={
149150
isDownloadingLogs ? "Downloading Logs..." : "Download Logs & Report Issue"
150151
}

ui/src/routes/devices.$id.settings.advanced.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ export default function SettingsAdvancedRoute() {
521521
>
522522
<Button
523523
size="SM"
524+
disabled={diagnosticsLoading}
524525
theme="light"
525526
text={m.advanced_download_diagnostics_button()}
526527
loading={diagnosticsLoading}

0 commit comments

Comments
 (0)