Skip to content

Commit bba63a0

Browse files
committed
fix: log slow app update and render paths
1 parent 47c3464 commit bba63a0

4 files changed

Lines changed: 86 additions & 0 deletions

File tree

‎internal/app/app.go‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package app
44
import (
55
"context"
66
"fmt"
7+
"time"
78

89
tea "charm.land/bubbletea/v2"
910

@@ -183,6 +184,9 @@ func (m *Model) checkForUpdate() tea.Cmd {
183184

184185
// Update handles messages.
185186
func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
187+
start := time.Now()
188+
defer m.logSlowUpdate(start, msg)
189+
186190
if cmd, handled := m.handleGlobalMessage(msg); handled {
187191
return m, cmd
188192
}

‎internal/app/app_layout_view.go‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package app
22

33
import (
4+
"time"
5+
46
"charm.land/bubbles/v2/key"
57
tea "charm.land/bubbletea/v2"
68
"charm.land/lipgloss/v2"
@@ -84,6 +86,9 @@ func (m *Model) updateKeyBar() {
8486

8587
// View renders the app.
8688
func (m *Model) View() tea.View {
89+
start := time.Now()
90+
defer m.logSlowRender(start)
91+
8792
colors := m.theme
8893

8994
// Show message if window is too small

‎internal/app/perf_logging.go‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package app
2+
3+
import (
4+
"fmt"
5+
"time"
6+
)
7+
8+
const (
9+
slowUpdateInfoThreshold = 50 * time.Millisecond
10+
slowUpdateWarnThreshold = 200 * time.Millisecond
11+
slowRenderInfoThreshold = 50 * time.Millisecond
12+
slowRenderWarnThreshold = 200 * time.Millisecond
13+
)
14+
15+
func (m *Model) logSlowUpdate(start time.Time, msg any) {
16+
d := time.Since(start)
17+
if d < slowUpdateInfoThreshold {
18+
return
19+
}
20+
21+
args := m.perfLogArgs(d)
22+
args = append(args, "msg_type", fmt.Sprintf("%T", msg))
23+
24+
if d >= slowUpdateWarnThreshold {
25+
m.scope.Warn("slow app update", args...)
26+
return
27+
}
28+
m.scope.Info("slow app update", args...)
29+
}
30+
31+
func (m *Model) logSlowRender(start time.Time) {
32+
d := time.Since(start)
33+
if d < slowRenderInfoThreshold {
34+
return
35+
}
36+
37+
args := m.perfLogArgs(d)
38+
if d >= slowRenderWarnThreshold {
39+
m.scope.Warn("slow app render", args...)
40+
return
41+
}
42+
m.scope.Info("slow app render", args...)
43+
}
44+
45+
func (m *Model) perfLogArgs(d time.Duration) []any {
46+
return []any{
47+
"duration_ms", d.Milliseconds(),
48+
"state", m.stateName(),
49+
"width", m.width,
50+
"height", m.height,
51+
"drawer_open", m.statusBar.IsDrawerOpen(),
52+
"drawer_tab", m.statusBar.ActiveTabLabel(),
53+
"palette_open", m.palette != nil,
54+
"quit_dialog_open", m.quitDlg != nil,
55+
}
56+
}
57+
58+
func (m *Model) stateName() string {
59+
switch m.state {
60+
case stateOnboarding:
61+
return "onboarding"
62+
case stateChat:
63+
return "chat"
64+
default:
65+
return "unknown"
66+
}
67+
}
68+

‎internal/app/statusbar/statusbar_drawer.go‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ func (m *Model) IsDrawerOpen() bool {
3737
return m.drawerOpen
3838
}
3939

40+
// ActiveTabLabel returns the active drawer tab label.
41+
func (m *Model) ActiveTabLabel() string {
42+
tab := m.activeTabModel()
43+
if tab == nil {
44+
return ""
45+
}
46+
return tab.Label()
47+
}
48+
4049
// HandleKeyPress forwards key events to the active tab's key handler.
4150
func (m *Model) HandleKeyPress(msg tea.KeyPressMsg) tea.Cmd {
4251
tab := m.activeTabModel()

0 commit comments

Comments
 (0)