package logger // import "github.com/docker/docker/daemon/logger" import ( "fmt" "io" "os" "path/filepath" "github.com/docker/docker/api/types/plugins/logdriver" "github.com/docker/docker/errdefs" getter "github.com/docker/docker/pkg/plugingetter" "github.com/docker/docker/pkg/plugins" "github.com/docker/docker/pkg/stringid" "github.com/pkg/errors" ) var pluginGetter getter.PluginGetter const extName = "LogDriver" // logPlugin defines the available functions that logging plugins must implement. type logPlugin interface { StartLogging(streamPath string, info Info) (err error) StopLogging(streamPath string) (err error) Capabilities() (cap Capability, err error) ReadLogs(info Info, config ReadConfig) (stream io.ReadCloser, err error) } // RegisterPluginGetter sets the plugingetter func RegisterPluginGetter(plugingetter getter.PluginGetter) { pluginGetter = plugingetter } // getPlugin returns a logging driver by its name. // If the driver is empty, it looks for the local driver. func getPlugin(name string, mode int) (Creator, error) { p, err := pluginGetter.Get(name, extName, mode) if err != nil { return nil, fmt.Errorf("error looking up logging plugin %s: %v", name, err) } client, err := makePluginClient(p) if err != nil { return nil, err } return makePluginCreator(name, client, p.ScopedPath), nil } func makePluginClient(p getter.CompatPlugin) (logPlugin, error) { if pc, ok := p.(getter.PluginWithV1Client); ok { return &logPluginProxy{pc.Client()}, nil } pa, ok := p.(getter.PluginAddr) if !ok { return nil, errdefs.System(errors.Errorf("got unknown plugin type %T", p)) } if pa.Protocol() != plugins.ProtocolSchemeHTTPV1 { return nil, errors.Errorf("plugin protocol not supported: %s", p) } addr := pa.Addr() c, err := plugins.NewClientWithTimeout(addr.Network()+"://"+addr.String(), nil, pa.Timeout()) if err != nil { return nil, errors.Wrap(err, "error making plugin client") } return &logPluginProxy{c}, nil } func makePluginCreator(name string, l logPlugin, scopePath func(s string) string) Creator { return func(logCtx Info) (logger Logger, err error) { defer func() { if err != nil { pluginGetter.Get(name, extName, getter.Release) } }() unscopedPath := filepath.Join("/", "run", "docker", "logging") logRoot := scopePath(unscopedPath) if err := os.MkdirAll(logRoot, 0o700); err != nil { return nil, err } id := stringid.GenerateRandomID() a := &pluginAdapter{ driverName: name, id: id, plugin: l, fifoPath: filepath.Join(logRoot, id), logInfo: logCtx, } cap, err := a.plugin.Capabilities() if err == nil { a.capabilities = cap } stream, err := openPluginStream(a) if err != nil { return nil, err } a.stream = stream a.enc = logdriver.NewLogEntryEncoder(a.stream) if err := l.StartLogging(filepath.Join(unscopedPath, id), logCtx); err != nil { return nil, errors.Wrapf(err, "error creating logger") } if cap.ReadLogs { return &pluginAdapterWithRead{a}, nil } return a, nil } }