Browse code

fluentd logger: support all options besides Unix sockets

Mostly useful for docker/docker#19438.

Signed-off-by: Pierre Carrier <pierre@meteor.com>

Pierre Carrier authored on 2016/01/24 22:51:03
Showing 3 changed files
... ...
@@ -8,10 +8,12 @@ import (
8 8
 	"net"
9 9
 	"strconv"
10 10
 	"strings"
11
+	"time"
11 12
 
12 13
 	"github.com/Sirupsen/logrus"
13 14
 	"github.com/docker/docker/daemon/logger"
14 15
 	"github.com/docker/docker/daemon/logger/loggerutils"
16
+	"github.com/docker/go-units"
15 17
 	"github.com/fluent/fluent-logger-golang/fluent"
16 18
 )
17 19
 
... ...
@@ -24,11 +26,25 @@ type fluentd struct {
24 24
 }
25 25
 
26 26
 const (
27
-	name               = "fluentd"
28
-	defaultHostName    = "localhost"
27
+	name = "fluentd"
28
+
29
+	defaultHost        = "127.0.0.1"
29 30
 	defaultPort        = 24224
31
+	defaultBufferLimit = 1024 * 1024
30 32
 	defaultTagPrefix   = "docker"
31
-	defaultBufferLimit = 1 * 1024 * 1024 // 1M buffer by default
33
+
34
+	// logger tries to reconnect 2**32 - 1 times
35
+	// failed (and panic) after 204 years [ 1.5 ** (2**32 - 1) - 1 seconds]
36
+	defaultRetryWait              = 1000
37
+	defaultTimeout                = 3 * time.Second
38
+	defaultMaxRetries             = math.MaxInt32
39
+	defaultReconnectWaitIncreRate = 1.5
40
+
41
+	addressKey      = "fluentd-address"
42
+	bufferLimitKey  = "fluentd-buffer-limit"
43
+	retryWaitKey    = "fluentd-retry-wait"
44
+	maxRetriesKey   = "fluentd-max-retries"
45
+	asyncConnectKey = "fluentd-async-connect"
32 46
 )
33 47
 
34 48
 func init() {
... ...
@@ -44,7 +60,7 @@ func init() {
44 44
 // the context. Supported context configuration variables are
45 45
 // fluentd-address & fluentd-tag.
46 46
 func New(ctx logger.Context) (logger.Logger, error) {
47
-	host, port, err := parseAddress(ctx.Config["fluentd-address"])
47
+	host, port, err := parseAddress(ctx.Config[addressKey])
48 48
 	if err != nil {
49 49
 		return nil, err
50 50
 	}
... ...
@@ -53,11 +69,56 @@ func New(ctx logger.Context) (logger.Logger, error) {
53 53
 	if err != nil {
54 54
 		return nil, err
55 55
 	}
56
+
56 57
 	extra := ctx.ExtraAttributes(nil)
57
-	logrus.Debugf("logging driver fluentd configured for container:%s, host:%s, port:%d, tag:%s, extra:%v.", ctx.ContainerID, host, port, tag, extra)
58
-	// logger tries to reconnect 2**32 - 1 times
59
-	// failed (and panic) after 204 years [ 1.5 ** (2**32 - 1) - 1 seconds]
60
-	log, err := fluent.New(fluent.Config{FluentPort: port, FluentHost: host, RetryWait: 1000, MaxRetry: math.MaxInt32})
58
+
59
+	bufferLimit := defaultBufferLimit
60
+	if ctx.Config[bufferLimitKey] != "" {
61
+		bl64, err := units.RAMInBytes(ctx.Config[bufferLimitKey])
62
+		if err != nil {
63
+			return nil, err
64
+		}
65
+		bufferLimit = int(bl64)
66
+	}
67
+
68
+	retryWait := defaultRetryWait
69
+	if ctx.Config[retryWaitKey] != "" {
70
+		rwd, err := time.ParseDuration(ctx.Config[retryWaitKey])
71
+		if err != nil {
72
+			return nil, err
73
+		}
74
+		retryWait = int(rwd.Seconds() * 1000)
75
+	}
76
+
77
+	maxRetries := defaultMaxRetries
78
+	if ctx.Config[maxRetriesKey] != "" {
79
+		mr64, err := strconv.ParseUint(ctx.Config[maxRetriesKey], 10, strconv.IntSize)
80
+		if err != nil {
81
+			return nil, err
82
+		}
83
+		maxRetries = int(mr64)
84
+	}
85
+
86
+	asyncConnect := false
87
+	if ctx.Config[asyncConnectKey] != "" {
88
+		if asyncConnect, err = strconv.ParseBool(ctx.Config[asyncConnectKey]); err != nil {
89
+			return nil, err
90
+		}
91
+	}
92
+
93
+	fluentConfig := fluent.Config{
94
+		FluentPort:   port,
95
+		FluentHost:   host,
96
+		BufferLimit:  bufferLimit,
97
+		RetryWait:    retryWait,
98
+		MaxRetry:     maxRetries,
99
+		AsyncConnect: asyncConnect,
100
+	}
101
+
102
+	logrus.WithField("container", ctx.ContainerID).WithField("config", fluentConfig).
103
+		Debug("logging driver fluentd configured")
104
+
105
+	log, err := fluent.New(fluentConfig)
61 106
 	if err != nil {
62 107
 		return nil, err
63 108
 	}
... ...
@@ -97,11 +158,16 @@ func (f *fluentd) Name() string {
97 97
 func ValidateLogOpt(cfg map[string]string) error {
98 98
 	for key := range cfg {
99 99
 		switch key {
100
-		case "fluentd-address":
100
+		case "env":
101 101
 		case "fluentd-tag":
102
-		case "tag":
103 102
 		case "labels":
104
-		case "env":
103
+		case "tag":
104
+		case addressKey:
105
+		case bufferLimitKey:
106
+		case retryWaitKey:
107
+		case maxRetriesKey:
108
+		case asyncConnectKey:
109
+			// Accepted
105 110
 		default:
106 111
 			return fmt.Errorf("unknown log opt '%s' for fluentd log driver", key)
107 112
 		}
... ...
@@ -116,7 +182,7 @@ func ValidateLogOpt(cfg map[string]string) error {
116 116
 
117 117
 func parseAddress(address string) (string, int, error) {
118 118
 	if address == "" {
119
-		return defaultHostName, defaultPort, nil
119
+		return defaultHost, defaultPort, nil
120 120
 	}
121 121
 
122 122
 	host, port, err := net.SplitHostPort(address)
... ...
@@ -54,7 +54,7 @@ connects to this daemon through `localhost:24224` by default. Use the
54 54
     docker run --log-driver=fluentd --log-opt fluentd-address=myhost.local:24224
55 55
 
56 56
 If container cannot connect to the Fluentd daemon, the container stops
57
-immediately.
57
+immediately unless the `fluentd-async-connect` option is used.
58 58
 
59 59
 ## Options
60 60
 
... ...
@@ -78,6 +78,9 @@ the log tag format.
78 78
 
79 79
 The `labels` and `env` options each take a comma-separated list of keys. If there is collision between `label` and `env` keys, the value of the `env` takes precedence. Both options add additional fields to the extra attributes of a logging message.
80 80
 
81
+### fluentd-async-connect
82
+
83
+Docker connects to Fluentd in the background. Messages are buffered until the connection is established.
81 84
 
82 85
 ## Fluentd daemon management with Docker
83 86
 
... ...
@@ -189,15 +189,20 @@ run slower but compress more. Default value is 1 (BestSpeed).
189 189
 You can use the `--log-opt NAME=VALUE` flag to specify these additional Fluentd logging driver options.
190 190
 
191 191
  - `fluentd-address`: specify `host:port` to connect [localhost:24224]
192
- - `tag`: specify tag for `fluentd` message,
192
+ - `tag`: specify tag for `fluentd` message
193
+ - `fluentd-buffer-limit`: specify the maximum size of the fluentd log buffer [8MB]
194
+ - `fluentd-retry-wait`: initial delay before a connection retry (after which it increases exponentially) [1000ms]
195
+ - `fluentd-max-retries`: maximum number of connection retries before abrupt failure of docker [1073741824]
196
+ - `fluentd-async-connect`: whether to block on initial connection or not [false]
193 197
 
194 198
 For example, to specify both additional options:
195 199
 
196 200
 `docker run --log-driver=fluentd --log-opt fluentd-address=localhost:24224 --log-opt tag=docker.{{.Name}}`
197 201
 
198
-If container cannot connect to the Fluentd daemon on the specified address,
199
-the container stops immediately. For detailed information on working with this
200
-logging driver, see [the fluentd logging driver](fluentd.md)
202
+If container cannot connect to the Fluentd daemon on the specified address and
203
+`fluentd-async-connect` is not enabled, the container stops immediately.
204
+For detailed information on working with this logging driver,
205
+see [the fluentd logging driver](fluentd.md)
201 206
 
202 207
 
203 208
 ## Specify Amazon CloudWatch Logs options