
This currently logs to a json file with the stream type. This is slow and hard on the cpu and memory so we need to swich this over to something like protobufs for the binary logs but this is just a start. Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
114 lines
1.9 KiB
Go
114 lines
1.9 KiB
Go
package containerd
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
)
|
|
|
|
type logConfig struct {
|
|
BundlePath string
|
|
LogSize int64 // in bytes
|
|
Stdin io.WriteCloser
|
|
Stdout io.ReadCloser
|
|
Stderr io.ReadCloser
|
|
}
|
|
|
|
func newLogger(i *logConfig) (*logger, error) {
|
|
l := &logger{
|
|
config: i,
|
|
messages: make(chan *Message, DefaultBufferSize),
|
|
}
|
|
hout := &logHandler{
|
|
stream: "stdout",
|
|
messages: l.messages,
|
|
}
|
|
herr := &logHandler{
|
|
stream: "stderr",
|
|
messages: l.messages,
|
|
}
|
|
l.wg.Add(2)
|
|
go func() {
|
|
defer l.wg.Done()
|
|
io.Copy(hout, i.Stdout)
|
|
}()
|
|
go func() {
|
|
defer l.wg.Done()
|
|
io.Copy(herr, i.Stderr)
|
|
}()
|
|
return l, l.start()
|
|
}
|
|
|
|
type Message struct {
|
|
Stream string `json:"stream"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Data []byte `json:"data"`
|
|
}
|
|
|
|
type logger struct {
|
|
config *logConfig
|
|
f *os.File
|
|
wg sync.WaitGroup
|
|
messages chan *Message
|
|
}
|
|
|
|
type logHandler struct {
|
|
stream string
|
|
messages chan *Message
|
|
}
|
|
|
|
func (h *logHandler) Write(b []byte) (int, error) {
|
|
h.messages <- &Message{
|
|
Stream: h.stream,
|
|
Timestamp: time.Now(),
|
|
Data: b,
|
|
}
|
|
return len(b), nil
|
|
}
|
|
|
|
func (l *logger) start() error {
|
|
f, err := os.OpenFile(
|
|
filepath.Join(l.config.BundlePath, "logs.json"),
|
|
os.O_CREATE|os.O_WRONLY|os.O_APPEND,
|
|
0655,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
l.f = f
|
|
l.wg.Add(1)
|
|
go func() {
|
|
l.wg.Done()
|
|
enc := json.NewEncoder(f)
|
|
for m := range l.messages {
|
|
if err := enc.Encode(m); err != nil {
|
|
logrus.WithField("error", err).Error("write log message")
|
|
}
|
|
}
|
|
}()
|
|
return nil
|
|
}
|
|
|
|
func (l *logger) Close() (err error) {
|
|
for _, c := range []io.Closer{
|
|
l.config.Stdin,
|
|
l.config.Stdout,
|
|
l.config.Stderr,
|
|
} {
|
|
if cerr := c.Close(); err == nil {
|
|
err = cerr
|
|
}
|
|
}
|
|
close(l.messages)
|
|
l.wg.Wait()
|
|
if ferr := l.f.Close(); err == nil {
|
|
err = ferr
|
|
}
|
|
return err
|
|
}
|