Skip to content

Commit

Permalink
feature: use ringBuffer to make log not blocking and configurable
Browse files Browse the repository at this point in the history
Signed-off-by: Starnop <[email protected]>
  • Loading branch information
starnop committed Nov 5, 2018
1 parent b83956b commit cadf71a
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 2 deletions.
92 changes: 92 additions & 0 deletions daemon/logger/bufferlog/bufferlog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package bufferlog

import (
"github.com/alibaba/pouch/daemon/logger"
rb "github.com/alibaba/pouch/pkg/ringbuffer"

"github.com/docker/go-units"
"github.com/sirupsen/logrus"
)

type BufferLog struct {
ringBuffer *rb.RingBuffer
logger logger.LogDriver
}

// NewBufferLog return a new BufferLog.
func NewBufferLog(logDriver logger.LogDriver, info logger.Info) (logger.LogDriver, error) {
bufferSize := int64(-1)
// translate the max buffer size if not nil
if s, ok := info.LogConfig["max-buffer-size"]; ok {
var err error
bufferSize, err = units.RAMInBytes(s)
if err != nil {
return nil, err
}
}

bl := &BufferLog{
logger: logDriver,
ringBuffer: rb.New(int(bufferSize)),
}

// use a goroutine to write logs continuously with specified log driver
go bl.run()
return bl, nil
}

// Name return the log driver's name.
func (bl *BufferLog) Name() string {
return bl.logger.Name()
}

// WriteLogMessage will write the LogMessage to the ringBuffer.
func (bl *BufferLog) WriteLogMessage(msg *logger.LogMessage) error {
covered, err := bl.ringBuffer.Push(msg)
if covered {
logrus.Warnf("data coverage occurs: %v", msg)
}
return err
}

// Close close the ringBuffer and drain the messages.
func (bl *BufferLog) Close() error {
bl.ringBuffer.Close()
var hasErr bool
for _, msg := range bl.ringBuffer.Drain() {
msgTemp, ok := msg.(*logger.LogMessage)
if !ok {
// TODO anything else should be done?
logrus.Warnf("failed to do type assertion when closing: %v", msg)
continue
}
if hasErr {
bl.ringBuffer.Push(msgTemp)
continue
}
if err := bl.logger.WriteLogMessage(msgTemp); err != nil {
logrus.Warnf("failed to write log %v when closing with log driver %s", msgTemp, bl.logger.Name())
hasErr = true
}
}

return bl.logger.Close()
}

// write logs continuously with specified log driver from ringBuffer.
func (bl *BufferLog) run() {
for {
msg, err := bl.ringBuffer.Pop()
if err != nil {
return
}
msgTemp, ok := msg.(*logger.LogMessage)
if !ok {
logrus.Warnf("failed to do type assertion: %v", msg)
return
}
if err := bl.logger.WriteLogMessage(msgTemp); err != nil {
logrus.Warnf("failed to write log %v with log driver %s", msgTemp, bl.logger.Name())
}
}
}
23 changes: 21 additions & 2 deletions daemon/mgr/container_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,46 @@ import (

"github.com/alibaba/pouch/apis/types"
"github.com/alibaba/pouch/daemon/logger"
"github.com/alibaba/pouch/daemon/logger/bufferlog"
"github.com/alibaba/pouch/daemon/logger/jsonfile"
"github.com/alibaba/pouch/daemon/logger/syslog"

"github.com/sirupsen/logrus"
)

const (
// LogNonBlocking means to use buffer to make logs non blocking.
LogNonBlocking = "non-blocking"
)

func logOptionsForContainerio(c *Container, info logger.Info) (logger.LogDriver, error) {
var ld logger.LogDriver
var err error

cfg := c.HostConfig.LogConfig
if cfg == nil || cfg.LogDriver == types.LogConfigLogDriverNone {
return nil, nil
}

switch cfg.LogDriver {
case types.LogConfigLogDriverJSONFile:
return jsonfile.Init(info)
ld, err = jsonfile.Init(info)
case types.LogConfigLogDriverSyslog:
return syslog.Init(info)
ld, err = syslog.Init(info)
default:
logrus.Warnf("not support (%v) log driver yet", cfg.LogDriver)
return nil, nil
}

if err != nil {
return nil, err
}

if info.LogConfig["mode"] == LogNonBlocking {
return bufferlog.NewBufferLog(ld, info)
}

return ld, err
}

// convContainerToLoggerInfo uses logger.Info to wrap container information.
Expand Down

0 comments on commit cadf71a

Please sign in to comment.