1package logger // import "github.com/docker/docker/daemon/logger" 2 3import ( 4 "fmt" 5 "sort" 6 "sync" 7 8 containertypes "github.com/docker/docker/api/types/container" 9 "github.com/docker/docker/pkg/plugingetter" 10 units "github.com/docker/go-units" 11 "github.com/pkg/errors" 12) 13 14// Creator builds a logging driver instance with given context. 15type Creator func(Info) (Logger, error) 16 17// LogOptValidator checks the options specific to the underlying 18// logging implementation. 19type LogOptValidator func(cfg map[string]string) error 20 21type logdriverFactory struct { 22 registry map[string]Creator 23 optValidator map[string]LogOptValidator 24 m sync.Mutex 25} 26 27func (lf *logdriverFactory) list() []string { 28 ls := make([]string, 0, len(lf.registry)) 29 lf.m.Lock() 30 for name := range lf.registry { 31 ls = append(ls, name) 32 } 33 lf.m.Unlock() 34 sort.Strings(ls) 35 return ls 36} 37 38// ListDrivers gets the list of registered log driver names 39func ListDrivers() []string { 40 return factory.list() 41} 42 43func (lf *logdriverFactory) register(name string, c Creator) error { 44 registered, err := lf.driverRegistered(name) 45 if err != nil { 46 return err 47 } 48 if registered { 49 return fmt.Errorf("logger: log driver named '%s' is already registered", name) 50 } 51 52 lf.m.Lock() 53 lf.registry[name] = c 54 lf.m.Unlock() 55 return nil 56} 57 58func (lf *logdriverFactory) driverRegistered(name string) (bool, error) { 59 lf.m.Lock() 60 _, ok := lf.registry[name] 61 lf.m.Unlock() 62 if !ok { 63 if pluginGetter != nil { // this can be nil when the init functions are running 64 l, err := getPlugin(name, plugingetter.Lookup) 65 if err != nil { 66 return false, err 67 } 68 if l != nil { 69 return true, nil 70 } 71 } 72 } 73 return ok, nil 74} 75 76func (lf *logdriverFactory) registerLogOptValidator(name string, l LogOptValidator) error { 77 lf.m.Lock() 78 defer lf.m.Unlock() 79 80 if _, ok := lf.optValidator[name]; ok { 81 return fmt.Errorf("logger: log validator named '%s' is already registered", name) 82 } 83 lf.optValidator[name] = l 84 return nil 85} 86 87func (lf *logdriverFactory) get(name string) (Creator, error) { 88 lf.m.Lock() 89 defer lf.m.Unlock() 90 91 c, ok := lf.registry[name] 92 if ok { 93 return c, nil 94 } 95 96 c, err := getPlugin(name, plugingetter.Acquire) 97 return c, errors.Wrapf(err, "logger: no log driver named '%s' is registered", name) 98} 99 100func (lf *logdriverFactory) getLogOptValidator(name string) LogOptValidator { 101 lf.m.Lock() 102 defer lf.m.Unlock() 103 104 c := lf.optValidator[name] 105 return c 106} 107 108var factory = &logdriverFactory{registry: make(map[string]Creator), optValidator: make(map[string]LogOptValidator)} // global factory instance 109 110// RegisterLogDriver registers the given logging driver builder with given logging 111// driver name. 112func RegisterLogDriver(name string, c Creator) error { 113 return factory.register(name, c) 114} 115 116// RegisterLogOptValidator registers the logging option validator with 117// the given logging driver name. 118func RegisterLogOptValidator(name string, l LogOptValidator) error { 119 return factory.registerLogOptValidator(name, l) 120} 121 122// GetLogDriver provides the logging driver builder for a logging driver name. 123func GetLogDriver(name string) (Creator, error) { 124 return factory.get(name) 125} 126 127var builtInLogOpts = map[string]bool{ 128 "mode": true, 129 "max-buffer-size": true, 130} 131 132// ValidateLogOpts checks the options for the given log driver. The 133// options supported are specific to the LogDriver implementation. 134func ValidateLogOpts(name string, cfg map[string]string) error { 135 if name == "none" { 136 return nil 137 } 138 139 switch containertypes.LogMode(cfg["mode"]) { 140 case containertypes.LogModeBlocking, containertypes.LogModeNonBlock, containertypes.LogModeUnset: 141 default: 142 return fmt.Errorf("logger: logging mode not supported: %s", cfg["mode"]) 143 } 144 145 if s, ok := cfg["max-buffer-size"]; ok { 146 if containertypes.LogMode(cfg["mode"]) != containertypes.LogModeNonBlock { 147 return fmt.Errorf("logger: max-buffer-size option is only supported with 'mode=%s'", containertypes.LogModeNonBlock) 148 } 149 if _, err := units.RAMInBytes(s); err != nil { 150 return errors.Wrap(err, "error parsing option max-buffer-size") 151 } 152 } 153 154 if err := validateExternal(cfg); err != nil { 155 return err 156 } 157 158 registered, err := factory.driverRegistered(name) 159 if err != nil { 160 return err 161 } 162 if !registered { 163 return fmt.Errorf("logger: no log driver named '%s' is registered", name) 164 } 165 166 filteredOpts := make(map[string]string, len(builtInLogOpts)) 167 for k, v := range cfg { 168 if !builtInLogOpts[k] { 169 filteredOpts[k] = v 170 } 171 } 172 173 validator := factory.getLogOptValidator(name) 174 if validator != nil { 175 return validator(filteredOpts) 176 } 177 return nil 178} 179