1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/daemon/logger/factory.go
Brian Goff 27bd6842f8 Implement plugins for logging drivers
Logging plugins use the same HTTP interface as other plugins for basic
command operations meanwhile actual logging operations are handled (on
Unix) via a fifo.

The plugin interface looks like so:

```go
type loggingPlugin interface {
  StartLogging(fifoPath string, loggingContext Context) error
  StopLogging(fifoPath)
```

This means a plugin must implement `LoggingDriver.StartLogging` and
`LoggingDriver.StopLogging` endpoints and be able to consume the passed
in fifo.

Logs are sent via stream encoder to the fifo encoded with protobuf.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2017-04-10 13:17:20 -04:00

145 lines
3.9 KiB
Go

package logger
import (
"fmt"
"sync"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/plugingetter"
units "github.com/docker/go-units"
"github.com/pkg/errors"
)
// Creator builds a logging driver instance with given context.
type Creator func(Info) (Logger, error)
// LogOptValidator checks the options specific to the underlying
// logging implementation.
type LogOptValidator func(cfg map[string]string) error
type logdriverFactory struct {
registry map[string]Creator
optValidator map[string]LogOptValidator
m sync.Mutex
}
func (lf *logdriverFactory) register(name string, c Creator) error {
if lf.driverRegistered(name) {
return fmt.Errorf("logger: log driver named '%s' is already registered", name)
}
lf.m.Lock()
lf.registry[name] = c
lf.m.Unlock()
return nil
}
func (lf *logdriverFactory) driverRegistered(name string) bool {
lf.m.Lock()
_, ok := lf.registry[name]
lf.m.Unlock()
if !ok {
if pluginGetter != nil { // this can be nil when the init functions are running
if l, _ := getPlugin(name, plugingetter.Lookup); l != nil {
return true
}
}
}
return ok
}
func (lf *logdriverFactory) registerLogOptValidator(name string, l LogOptValidator) error {
lf.m.Lock()
defer lf.m.Unlock()
if _, ok := lf.optValidator[name]; ok {
return fmt.Errorf("logger: log validator named '%s' is already registered", name)
}
lf.optValidator[name] = l
return nil
}
func (lf *logdriverFactory) get(name string) (Creator, error) {
lf.m.Lock()
defer lf.m.Unlock()
c, ok := lf.registry[name]
if ok {
return c, nil
}
c, err := getPlugin(name, plugingetter.Acquire)
return c, errors.Wrapf(err, "logger: no log driver named '%s' is registered", name)
}
func (lf *logdriverFactory) getLogOptValidator(name string) LogOptValidator {
lf.m.Lock()
defer lf.m.Unlock()
c, _ := lf.optValidator[name]
return c
}
var factory = &logdriverFactory{registry: make(map[string]Creator), optValidator: make(map[string]LogOptValidator)} // global factory instance
// RegisterLogDriver registers the given logging driver builder with given logging
// driver name.
func RegisterLogDriver(name string, c Creator) error {
return factory.register(name, c)
}
// RegisterLogOptValidator registers the logging option validator with
// the given logging driver name.
func RegisterLogOptValidator(name string, l LogOptValidator) error {
return factory.registerLogOptValidator(name, l)
}
// GetLogDriver provides the logging driver builder for a logging driver name.
func GetLogDriver(name string) (Creator, error) {
return factory.get(name)
}
var builtInLogOpts = map[string]bool{
"mode": true,
"max-buffer-size": true,
}
// ValidateLogOpts checks the options for the given log driver. The
// options supported are specific to the LogDriver implementation.
func ValidateLogOpts(name string, cfg map[string]string) error {
if name == "none" {
return nil
}
switch containertypes.LogMode(cfg["mode"]) {
case containertypes.LogModeBlocking, containertypes.LogModeNonBlock, containertypes.LogModeUnset:
default:
return fmt.Errorf("logger: logging mode not supported: %s", cfg["mode"])
}
if s, ok := cfg["max-buffer-size"]; ok {
if containertypes.LogMode(cfg["mode"]) != containertypes.LogModeNonBlock {
return fmt.Errorf("logger: max-buffer-size option is only supported with 'mode=%s'", containertypes.LogModeNonBlock)
}
if _, err := units.RAMInBytes(s); err != nil {
return errors.Wrap(err, "error parsing option max-buffer-size")
}
}
if !factory.driverRegistered(name) {
return fmt.Errorf("logger: no log driver named '%s' is registered", name)
}
filteredOpts := make(map[string]string, len(builtInLogOpts))
for k, v := range cfg {
if !builtInLogOpts[k] {
filteredOpts[k] = v
}
}
validator := factory.getLogOptValidator(name)
if validator != nil {
return validator(filteredOpts)
}
return nil
}