opencode/internal/logging/writer.go

102 lines
2.0 KiB
Go
Raw Normal View History

2025-03-22 01:20:28 +08:00
package logging
import (
"bytes"
2025-04-10 19:29:44 +08:00
"context"
2025-03-22 01:20:28 +08:00
"fmt"
2025-04-10 19:29:44 +08:00
"strings"
"sync"
2025-03-22 01:20:28 +08:00
"time"
"github.com/go-logfmt/logfmt"
2025-04-25 00:25:52 +08:00
"github.com/opencode-ai/opencode/internal/pubsub"
2025-03-22 01:20:28 +08:00
)
2025-04-10 19:29:44 +08:00
const (
persistKeyArg = "$_persist"
PersistTimeArg = "$_persist_time"
)
type LogData struct {
2025-04-10 01:07:39 +08:00
messages []LogMessage
*pubsub.Broker[LogMessage]
2025-04-10 19:29:44 +08:00
lock sync.Mutex
}
func (l *LogData) Add(msg LogMessage) {
l.lock.Lock()
defer l.lock.Unlock()
l.messages = append(l.messages, msg)
l.Publish(pubsub.CreatedEvent, msg)
}
func (l *LogData) List() []LogMessage {
l.lock.Lock()
defer l.lock.Unlock()
return l.messages
}
var defaultLogData = &LogData{
messages: make([]LogMessage, 0),
Broker: pubsub.NewBroker[LogMessage](),
2025-03-22 01:20:28 +08:00
}
2025-04-10 19:29:44 +08:00
type writer struct{}
2025-03-22 01:20:28 +08:00
func (w *writer) Write(p []byte) (int, error) {
d := logfmt.NewDecoder(bytes.NewReader(p))
for d.ScanRecord() {
2025-04-10 01:07:39 +08:00
msg := LogMessage{
2025-04-10 01:18:51 +08:00
ID: fmt.Sprintf("%d", time.Now().UnixNano()),
Time: time.Now(),
2025-03-22 01:20:28 +08:00
}
for d.ScanKeyval() {
switch string(d.Key()) {
case "time":
parsed, err := time.Parse(time.RFC3339, string(d.Value()))
if err != nil {
return 0, fmt.Errorf("parsing time: %w", err)
}
msg.Time = parsed
case "level":
2025-04-10 19:29:44 +08:00
msg.Level = strings.ToLower(string(d.Value()))
2025-03-22 01:20:28 +08:00
case "msg":
msg.Message = string(d.Value())
default:
2025-04-10 01:07:39 +08:00
if string(d.Key()) == persistKeyArg {
msg.Persist = true
} else if string(d.Key()) == PersistTimeArg {
parsed, err := time.ParseDuration(string(d.Value()))
if err != nil {
continue
}
msg.PersistTime = parsed
} else {
msg.Attributes = append(msg.Attributes, Attr{
Key: string(d.Key()),
Value: string(d.Value()),
})
}
2025-03-22 01:20:28 +08:00
}
}
2025-04-10 19:29:44 +08:00
defaultLogData.Add(msg)
2025-03-22 01:20:28 +08:00
}
if d.Err() != nil {
return 0, d.Err()
}
return len(p), nil
}
2025-04-10 19:29:44 +08:00
func NewWriter() *writer {
w := &writer{}
return w
}
func Subscribe(ctx context.Context) <-chan pubsub.Event[LogMessage] {
return defaultLogData.Subscribe(ctx)
}
func List() []LogMessage {
return defaultLogData.List()
}