Add basic logging to file support

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>
This commit is contained in:
Michael Crosby
2015-12-10 17:07:21 -08:00
parent 8469b6d6a4
commit e5545a1461
12 changed files with 278 additions and 58 deletions

113
log.go Normal file
View File

@@ -0,0 +1,113 @@
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
}