Files
fn-serverless/api/runner/func_logger.go
2017-06-21 08:24:06 -07:00

105 lines
2.3 KiB
Go

package runner
import (
"bytes"
"context"
"errors"
"io"
"github.com/Sirupsen/logrus"
"gitlab-odx.oracle.com/odx/functions/api/models"
"gitlab-odx.oracle.com/odx/functions/api/runner/common"
)
type FuncLogger interface {
Writer(ctx context.Context, appName, path, image, reqID string) io.WriteCloser
}
// FuncLogger reads STDERR output from a container and outputs it in a parsed structured log format, see: https://github.com/treeder/functions/issues/76
type DefaultFuncLogger struct {
logDB models.FnLog
}
func NewFuncLogger(logDB models.FnLog) FuncLogger {
return &DefaultFuncLogger{logDB}
}
type writer struct {
bytes.Buffer
stderr bytes.Buffer // for logging to stderr
db models.FnLog
ctx context.Context
reqID string
appName string
image string
path string
}
func (w *writer) Close() error {
w.flush()
return w.db.InsertLog(context.TODO(), w.reqID, w.String())
}
func (w *writer) Write(b []byte) (int, error) {
n, err := w.Buffer.Write(b)
// temp or should move to another FuncLogger implementation
w.writeStdErr(b)
return n, err
}
func (w *writer) writeStdErr(b []byte) {
// for now, also write to stderr so we can debug quick ;)
// TODO this should be a separate FuncLogger but time is running short !
endLine := bytes.IndexByte(b, '\n')
if endLine < 0 {
w.stderr.Write(b)
return
}
// we have a new line, so:
w.stderr.Write(b[0:endLine])
w.flush()
w.writeStdErr(b[endLine+1:])
}
func (w *writer) flush() {
log := common.Logger(w.ctx)
log = log.WithFields(logrus.Fields{"user_log": true, "app_name": w.appName, "path": w.path, "image": w.image, "call_id": w.reqID})
log.Println(w.stderr.String())
w.stderr.Reset()
}
// overrides Write, keeps Close
type limitWriter struct {
n, max int
io.WriteCloser
}
func newLimitWriter(max int, w io.WriteCloser) io.WriteCloser {
return &limitWriter{max: max, WriteCloser: w}
}
func (l *limitWriter) Write(b []byte) (int, error) {
if l.n > l.max {
return 0, errors.New("max log size exceeded, truncating log")
}
n, err := l.WriteCloser.Write(b)
l.n += n
return n, err
}
func (l *DefaultFuncLogger) Writer(ctx context.Context, appName, path, image, reqID string) io.WriteCloser {
const MB = 1 * 1024 * 1024
return newLimitWriter(MB, &writer{
db: l.logDB,
ctx: ctx,
appName: appName,
path: path,
image: image,
reqID: reqID,
})
}