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