github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/logger/plugin.go (about)

     1  package logger // import "github.com/docker/docker/daemon/logger"
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  
     9  	"github.com/docker/docker/api/types/plugins/logdriver"
    10  	"github.com/docker/docker/errdefs"
    11  	getter "github.com/docker/docker/pkg/plugingetter"
    12  	"github.com/docker/docker/pkg/plugins"
    13  	"github.com/docker/docker/pkg/stringid"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  var pluginGetter getter.PluginGetter
    18  
    19  const extName = "LogDriver"
    20  
    21  // logPlugin defines the available functions that logging plugins must implement.
    22  type logPlugin interface {
    23  	StartLogging(streamPath string, info Info) (err error)
    24  	StopLogging(streamPath string) (err error)
    25  	Capabilities() (cap Capability, err error)
    26  	ReadLogs(info Info, config ReadConfig) (stream io.ReadCloser, err error)
    27  }
    28  
    29  // RegisterPluginGetter sets the plugingetter
    30  func RegisterPluginGetter(plugingetter getter.PluginGetter) {
    31  	pluginGetter = plugingetter
    32  }
    33  
    34  // GetDriver returns a logging driver by its name.
    35  // If the driver is empty, it looks for the local driver.
    36  func getPlugin(name string, mode int) (Creator, error) {
    37  	p, err := pluginGetter.Get(name, extName, mode)
    38  	if err != nil {
    39  		return nil, fmt.Errorf("error looking up logging plugin %s: %v", name, err)
    40  	}
    41  
    42  	client, err := makePluginClient(p)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	return makePluginCreator(name, client, p.ScopedPath), nil
    47  }
    48  
    49  func makePluginClient(p getter.CompatPlugin) (logPlugin, error) {
    50  	if pc, ok := p.(getter.PluginWithV1Client); ok {
    51  		return &logPluginProxy{pc.Client()}, nil
    52  	}
    53  	pa, ok := p.(getter.PluginAddr)
    54  	if !ok {
    55  		return nil, errdefs.System(errors.Errorf("got unknown plugin type %T", p))
    56  	}
    57  
    58  	if pa.Protocol() != plugins.ProtocolSchemeHTTPV1 {
    59  		return nil, errors.Errorf("plugin protocol not supported: %s", p)
    60  	}
    61  
    62  	addr := pa.Addr()
    63  	c, err := plugins.NewClientWithTimeout(addr.Network()+"://"+addr.String(), nil, pa.Timeout())
    64  	if err != nil {
    65  		return nil, errors.Wrap(err, "error making plugin client")
    66  	}
    67  	return &logPluginProxy{c}, nil
    68  }
    69  
    70  func makePluginCreator(name string, l logPlugin, scopePath func(s string) string) Creator {
    71  	return func(logCtx Info) (logger Logger, err error) {
    72  		defer func() {
    73  			if err != nil {
    74  				pluginGetter.Get(name, extName, getter.Release)
    75  			}
    76  		}()
    77  
    78  		unscopedPath := filepath.Join("/", "run", "docker", "logging")
    79  		logRoot := scopePath(unscopedPath)
    80  		if err := os.MkdirAll(logRoot, 0700); err != nil {
    81  			return nil, err
    82  		}
    83  
    84  		id := stringid.GenerateRandomID()
    85  		a := &pluginAdapter{
    86  			driverName: name,
    87  			id:         id,
    88  			plugin:     l,
    89  			fifoPath:   filepath.Join(logRoot, id),
    90  			logInfo:    logCtx,
    91  		}
    92  
    93  		cap, err := a.plugin.Capabilities()
    94  		if err == nil {
    95  			a.capabilities = cap
    96  		}
    97  
    98  		stream, err := openPluginStream(a)
    99  		if err != nil {
   100  			return nil, err
   101  		}
   102  
   103  		a.stream = stream
   104  		a.enc = logdriver.NewLogEntryEncoder(a.stream)
   105  
   106  		if err := l.StartLogging(filepath.Join(unscopedPath, id), logCtx); err != nil {
   107  			return nil, errors.Wrapf(err, "error creating logger")
   108  		}
   109  
   110  		if cap.ReadLogs {
   111  			return &pluginAdapterWithRead{a}, nil
   112  		}
   113  
   114  		return a, nil
   115  	}
   116  }