blob: 084e3d1b84c1ebcd53ecf2d8003d2984e99f74c9 [file] [log] [blame]
package main
import (
"bytes"
"strings"
"sync"
"time"
)
type LogItem struct {
RunId string `json:"runId"`
TimestampMilli int64 `json:"timestampMilli"`
Commit string `json:"commit,omitempty"`
Contents []byte `json:"contents"`
}
type Logger struct {
l sync.Mutex
runId string
commitHash string
items []LogItem
curr LogItem
}
func NewLogger(runId string) *Logger {
return &Logger{
l: sync.Mutex{},
runId: runId,
items: []LogItem{},
curr: LogItem{
RunId: runId,
Contents: []byte{},
},
}
}
func (l *Logger) Write(p []byte) (n int, err error) {
l.l.Lock()
defer l.l.Unlock()
cnt := 0
// TODO(gio): Reset s.logs periodically
for len(p) > 0 {
pos := bytes.Index(p, []byte("\n"))
if pos != -1 {
if l.curr.TimestampMilli == 0 {
l.curr.TimestampMilli = time.Now().UnixMilli()
}
l.curr.Contents = append(l.curr.Contents, p[:pos]...)
l.items = append(l.items, l.curr)
l.curr = LogItem{
RunId: l.runId,
Contents: []byte{},
}
p = p[pos+len([]byte("\n")):]
cnt += pos + len([]byte("\n"))
} else {
if l.curr.TimestampMilli == 0 {
l.curr.TimestampMilli = time.Now().UnixMilli()
}
l.curr.Contents = append(l.curr.Contents, p...)
cnt += len(p)
p = []byte{}
}
}
return cnt, nil
}
func (l *Logger) Items() []LogItem {
l.l.Lock()
defer l.l.Unlock()
ret := []LogItem{}
for _, i := range l.items {
ret = append(ret, i)
}
return ret
}
func (l *Logger) Trim(n int) {
l.l.Lock()
defer l.l.Unlock()
l.items = l.items[n:]
}
func (l *Logger) Contents() (string, error) {
l.l.Lock()
defer l.l.Unlock()
var ret strings.Builder
for _, i := range l.items {
if _, err := ret.Write(i.Contents); err != nil {
return "", err
}
if _, err := ret.WriteString("\n"); err != nil {
return "", err
}
}
return ret.String(), nil
}