Add Claude integration to dashboard
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.
This commit is contained in:
105
dashboard/internal/claude/history_tailer.go
Normal file
105
dashboard/internal/claude/history_tailer.go
Normal file
@@ -0,0 +1,105 @@
|
||||
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()
|
||||
}
|
||||
Reference in New Issue
Block a user