mirror of
https://github.com/amir20/dozzle.git
synced 2025-12-21 21:33:18 +01:00
102 lines
1.7 KiB
Go
102 lines
1.7 KiB
Go
package docker
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"io"
|
|
"sync"
|
|
|
|
"github.com/amir20/dozzle/internal/container"
|
|
)
|
|
|
|
var ErrBadHeader = errors.New("bad header")
|
|
|
|
type StdType int
|
|
|
|
const (
|
|
stdout StdType = iota
|
|
stderr
|
|
)
|
|
|
|
type LogReader struct {
|
|
reader *bufio.Reader
|
|
tty bool
|
|
pool *sync.Pool
|
|
}
|
|
|
|
func NewLogReader(r io.Reader, tty bool) *LogReader {
|
|
return &LogReader{
|
|
reader: bufio.NewReader(r),
|
|
tty: tty,
|
|
pool: &sync.Pool{
|
|
New: func() interface{} {
|
|
return bytes.NewBuffer(make([]byte, 0, 4096))
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (d *LogReader) Read() (string, container.StdType, error) {
|
|
message, stdType, err := d.readEvent()
|
|
if err != nil {
|
|
return "", 0, err
|
|
}
|
|
|
|
var std container.StdType
|
|
switch stdType {
|
|
case stdout:
|
|
std = container.STDOUT
|
|
case stderr:
|
|
std = container.STDERR
|
|
}
|
|
|
|
return message, std, nil
|
|
|
|
}
|
|
|
|
func (d *LogReader) readEvent() (string, StdType, error) {
|
|
header := []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
|
buffer := d.pool.Get().(*bytes.Buffer)
|
|
buffer.Reset()
|
|
defer d.pool.Put(buffer)
|
|
|
|
var streamType StdType = stdout
|
|
|
|
if d.tty {
|
|
message, err := d.reader.ReadString('\n')
|
|
if err != nil {
|
|
return message, streamType, err
|
|
}
|
|
return message, streamType, nil
|
|
} else {
|
|
n, err := io.ReadFull(d.reader, header)
|
|
if err != nil {
|
|
return "", streamType, err
|
|
}
|
|
if n != 8 {
|
|
message, _ := d.reader.ReadString('\n')
|
|
return message, streamType, ErrBadHeader
|
|
}
|
|
|
|
switch header[0] {
|
|
case 1:
|
|
streamType = stdout
|
|
case 2:
|
|
streamType = stderr
|
|
}
|
|
|
|
count := binary.BigEndian.Uint32(header[4:])
|
|
if count == 0 {
|
|
return "", streamType, nil
|
|
}
|
|
|
|
_, err = io.CopyN(buffer, d.reader, int64(count))
|
|
if err != nil {
|
|
return "", streamType, err
|
|
}
|
|
return buffer.String(), streamType, nil
|
|
}
|
|
}
|