Add /logs endpoint to monitor upstream processes

- outputs last 10KB of logs from upstream processes
- supports streaming
This commit is contained in:
Benson Wong
2024-10-30 21:02:30 -07:00
parent 1510b3fbd9
commit 0f133f5b74
3 changed files with 155 additions and 5 deletions

83
proxy/logMonitor.go Normal file
View File

@@ -0,0 +1,83 @@
package proxy
import (
"container/ring"
"os"
"sync"
)
type LogMonitor struct {
clients map[chan string]bool
mu sync.RWMutex
buffer *ring.Ring
bufferMu sync.RWMutex
}
func NewLogMonitor() *LogMonitor {
return &LogMonitor{
clients: make(map[chan string]bool),
buffer: ring.New(10 * 1024), // keep 10KB of buffered logs
}
}
func (w *LogMonitor) Write(p []byte) (n int, err error) {
n, err = os.Stdout.Write(p)
if err != nil {
return n, err
}
content := string(p)
w.bufferMu.Lock()
w.buffer.Value = content
w.buffer = w.buffer.Next()
w.bufferMu.Unlock()
w.Broadcast(content)
return n, nil
}
func (w *LogMonitor) getHistory() string {
w.bufferMu.RLock()
defer w.bufferMu.RUnlock()
var history string
w.buffer.Do(func(p interface{}) {
if p != nil {
if content, ok := p.(string); ok {
history += content
}
}
})
return history
}
func (w *LogMonitor) Subscribe() chan string {
w.mu.Lock()
defer w.mu.Unlock()
ch := make(chan string, 100)
w.clients[ch] = true
return ch
}
func (w *LogMonitor) Unsubscribe(ch chan string) {
w.mu.Lock()
defer w.mu.Unlock()
delete(w.clients, ch)
close(ch)
}
func (w *LogMonitor) Broadcast(msg string) {
w.mu.RLock()
defer w.mu.RUnlock()
for client := range w.clients {
select {
case client <- msg:
default:
// If client buffer is full, skip
}
}
}