Add comprehensive Claude Code monitoring and realtime streaming to the K8s dashboard. Includes API endpoints for health, stats, summary, inventory, and live event streaming. Frontend provides overview, usage, inventory, debug, and live feed views.
106 lines
1.9 KiB
Go
106 lines
1.9 KiB
Go
package claude
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
func TailHistoryFile(stop <-chan struct{}, hub *EventHub, path string) {
|
|
var offset int64
|
|
|
|
for {
|
|
select {
|
|
case <-stop:
|
|
return
|
|
default:
|
|
}
|
|
|
|
stat, err := os.Stat(path)
|
|
if err != nil {
|
|
if !os.IsNotExist(err) {
|
|
hub.Publish(Event{
|
|
TS: time.Now(),
|
|
Type: EventTypeServerError,
|
|
Data: map[string]any{"error": err.Error()},
|
|
})
|
|
}
|
|
time.Sleep(1 * time.Second)
|
|
continue
|
|
}
|
|
|
|
size := stat.Size()
|
|
if size > offset {
|
|
if err := processNewBytes(path, offset, size, hub); err != nil {
|
|
hub.Publish(Event{
|
|
TS: time.Now(),
|
|
Type: EventTypeServerError,
|
|
Data: map[string]any{"error": err.Error()},
|
|
})
|
|
}
|
|
offset = size
|
|
} else if size < offset {
|
|
offset = 0
|
|
hub.Publish(Event{
|
|
TS: time.Now(),
|
|
Type: EventTypeServerNotice,
|
|
Data: map[string]any{"msg": "file truncated, resetting offset"},
|
|
})
|
|
}
|
|
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
func processNewBytes(path string, oldSize, newSize int64, hub *EventHub) error {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
if _, err := f.Seek(oldSize, 0); err != nil {
|
|
return err
|
|
}
|
|
|
|
scanner := bufio.NewScanner(f)
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
if line == "" {
|
|
continue
|
|
}
|
|
|
|
data := map[string]any{
|
|
"rawLine": line,
|
|
}
|
|
|
|
var jsonData map[string]any
|
|
if err := json.Unmarshal([]byte(line), &jsonData); err != nil {
|
|
data["parseError"] = err.Error()
|
|
} else {
|
|
data["json"] = jsonData
|
|
|
|
summary := map[string]string{}
|
|
if v, ok := jsonData["sessionId"].(string); ok {
|
|
summary["sessionId"] = v
|
|
}
|
|
if v, ok := jsonData["project"].(string); ok {
|
|
summary["project"] = v
|
|
}
|
|
if v, ok := jsonData["display"].(string); ok {
|
|
summary["display"] = v
|
|
}
|
|
data["summary"] = summary
|
|
}
|
|
|
|
hub.Publish(Event{
|
|
TS: time.Now(),
|
|
Type: EventTypeHistoryAppend,
|
|
Data: data,
|
|
})
|
|
}
|
|
|
|
return scanner.Err()
|
|
}
|