99121d07d8
Horizontal bar chart showing latency distribution across 5 buckets: 0-50ms, 50-100ms, 100-200ms, 200-500ms, 500ms+. Color-coded green (fast), yellow (medium), red (slow). Shows count per bucket. Appears in the full-screen detail panel (Enter) after the sparkline stats. Skipped for push monitors (no latency data).
90 lines
1.6 KiB
Go
90 lines
1.6 KiB
Go
package tui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
type latencyBucket struct {
|
|
label string
|
|
min int64
|
|
max int64
|
|
count int
|
|
}
|
|
|
|
func (m Model) latencyHistogram(latencies []time.Duration, statuses []bool, width int) string {
|
|
if len(latencies) == 0 || width < 30 {
|
|
return ""
|
|
}
|
|
|
|
buckets := []latencyBucket{
|
|
{"0-50ms", 0, 50, 0},
|
|
{"50-100ms", 50, 100, 0},
|
|
{"100-200ms", 100, 200, 0},
|
|
{"200-500ms", 200, 500, 0},
|
|
{"500ms+", 500, 999999, 0},
|
|
}
|
|
|
|
for i, l := range latencies {
|
|
if i < len(statuses) && !statuses[i] {
|
|
continue
|
|
}
|
|
ms := l.Milliseconds()
|
|
for j := range buckets {
|
|
if ms >= buckets[j].min && ms < buckets[j].max {
|
|
buckets[j].count++
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
maxCount := 0
|
|
for _, b := range buckets {
|
|
if b.count > maxCount {
|
|
maxCount = b.count
|
|
}
|
|
}
|
|
if maxCount == 0 {
|
|
return ""
|
|
}
|
|
|
|
labelW := 10
|
|
countW := len(fmt.Sprintf("%d", maxCount))
|
|
barW := width - labelW - countW - 4
|
|
if barW < 5 {
|
|
barW = 5
|
|
}
|
|
|
|
var sb strings.Builder
|
|
for _, b := range buckets {
|
|
fill := 0
|
|
if maxCount > 0 {
|
|
fill = b.count * barW / maxCount
|
|
}
|
|
|
|
var barColor lipgloss.Style
|
|
switch {
|
|
case b.min < 100:
|
|
barColor = m.st.specialStyle
|
|
case b.min < 500:
|
|
barColor = m.st.warnStyle
|
|
default:
|
|
barColor = m.st.dangerStyle
|
|
}
|
|
|
|
bar := barColor.Render(strings.Repeat("█", fill))
|
|
if fill < barW {
|
|
bar += m.st.subtleStyle.Render(strings.Repeat("░", barW-fill))
|
|
}
|
|
|
|
label := fmt.Sprintf("%*s", labelW, b.label)
|
|
count := fmt.Sprintf("%*d", countW, b.count)
|
|
sb.WriteString(" " + m.st.subtleStyle.Render(label) + " " + bar + " " + count + "\n")
|
|
}
|
|
|
|
return sb.String()
|
|
}
|