Explorar el Código

fluentd logger: support all options besides Unix sockets

Mostly useful for docker/docker#19438.

Signed-off-by: Pierre Carrier <pierre@meteor.com>
Pierre Carrier hace 9 años
padre
commit
13086f387b
Se han modificado 3 ficheros con 91 adiciones y 17 borrados
  1. 78 12
      daemon/logger/fluentd/fluentd.go
  2. 4 1
      docs/admin/logging/fluentd.md
  3. 9 4
      docs/admin/logging/overview.md

+ 78 - 12
daemon/logger/fluentd/fluentd.go

@@ -8,10 +8,12 @@ import (
 	"net"
 	"strconv"
 	"strings"
+	"time"
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/logger"
 	"github.com/docker/docker/daemon/logger/loggerutils"
+	"github.com/docker/go-units"
 	"github.com/fluent/fluent-logger-golang/fluent"
 )
 
@@ -24,11 +26,25 @@ type fluentd struct {
 }
 
 const (
-	name               = "fluentd"
-	defaultHostName    = "localhost"
+	name = "fluentd"
+
+	defaultHost        = "127.0.0.1"
 	defaultPort        = 24224
+	defaultBufferLimit = 1024 * 1024
 	defaultTagPrefix   = "docker"
-	defaultBufferLimit = 1 * 1024 * 1024 // 1M buffer by default
+
+	// logger tries to reconnect 2**32 - 1 times
+	// failed (and panic) after 204 years [ 1.5 ** (2**32 - 1) - 1 seconds]
+	defaultRetryWait              = 1000
+	defaultTimeout                = 3 * time.Second
+	defaultMaxRetries             = math.MaxInt32
+	defaultReconnectWaitIncreRate = 1.5
+
+	addressKey      = "fluentd-address"
+	bufferLimitKey  = "fluentd-buffer-limit"
+	retryWaitKey    = "fluentd-retry-wait"
+	maxRetriesKey   = "fluentd-max-retries"
+	asyncConnectKey = "fluentd-async-connect"
 )
 
 func init() {
@@ -44,7 +60,7 @@ func init() {
 // the context. Supported context configuration variables are
 // fluentd-address & fluentd-tag.
 func New(ctx logger.Context) (logger.Logger, error) {
-	host, port, err := parseAddress(ctx.Config["fluentd-address"])
+	host, port, err := parseAddress(ctx.Config[addressKey])
 	if err != nil {
 		return nil, err
 	}
@@ -53,11 +69,56 @@ func New(ctx logger.Context) (logger.Logger, error) {
 	if err != nil {
 		return nil, err
 	}
+
 	extra := ctx.ExtraAttributes(nil)
-	logrus.Debugf("logging driver fluentd configured for container:%s, host:%s, port:%d, tag:%s, extra:%v.", ctx.ContainerID, host, port, tag, extra)
-	// logger tries to reconnect 2**32 - 1 times
-	// failed (and panic) after 204 years [ 1.5 ** (2**32 - 1) - 1 seconds]
-	log, err := fluent.New(fluent.Config{FluentPort: port, FluentHost: host, RetryWait: 1000, MaxRetry: math.MaxInt32})
+
+	bufferLimit := defaultBufferLimit
+	if ctx.Config[bufferLimitKey] != "" {
+		bl64, err := units.RAMInBytes(ctx.Config[bufferLimitKey])
+		if err != nil {
+			return nil, err
+		}
+		bufferLimit = int(bl64)
+	}
+
+	retryWait := defaultRetryWait
+	if ctx.Config[retryWaitKey] != "" {
+		rwd, err := time.ParseDuration(ctx.Config[retryWaitKey])
+		if err != nil {
+			return nil, err
+		}
+		retryWait = int(rwd.Seconds() * 1000)
+	}
+
+	maxRetries := defaultMaxRetries
+	if ctx.Config[maxRetriesKey] != "" {
+		mr64, err := strconv.ParseUint(ctx.Config[maxRetriesKey], 10, strconv.IntSize)
+		if err != nil {
+			return nil, err
+		}
+		maxRetries = int(mr64)
+	}
+
+	asyncConnect := false
+	if ctx.Config[asyncConnectKey] != "" {
+		if asyncConnect, err = strconv.ParseBool(ctx.Config[asyncConnectKey]); err != nil {
+			return nil, err
+		}
+	}
+
+	fluentConfig := fluent.Config{
+		FluentPort:   port,
+		FluentHost:   host,
+		BufferLimit:  bufferLimit,
+		RetryWait:    retryWait,
+		MaxRetry:     maxRetries,
+		AsyncConnect: asyncConnect,
+	}
+
+	logrus.WithField("container", ctx.ContainerID).WithField("config", fluentConfig).
+		Debug("logging driver fluentd configured")
+
+	log, err := fluent.New(fluentConfig)
 	if err != nil {
 		return nil, err
 	}
@@ -97,11 +158,16 @@ func (f *fluentd) Name() string {
 func ValidateLogOpt(cfg map[string]string) error {
 	for key := range cfg {
 		switch key {
-		case "fluentd-address":
+		case "env":
 		case "fluentd-tag":
-		case "tag":
 		case "labels":
-		case "env":
+		case "tag":
+		case addressKey:
+		case bufferLimitKey:
+		case retryWaitKey:
+		case maxRetriesKey:
+		case asyncConnectKey:
+			// Accepted
 		default:
 			return fmt.Errorf("unknown log opt '%s' for fluentd log driver", key)
 		}
@@ -116,7 +182,7 @@ func ValidateLogOpt(cfg map[string]string) error {
 
 func parseAddress(address string) (string, int, error) {
 	if address == "" {
-		return defaultHostName, defaultPort, nil
+		return defaultHost, defaultPort, nil
 	}
 
 	host, port, err := net.SplitHostPort(address)

+ 4 - 1
docs/admin/logging/fluentd.md

@@ -54,7 +54,7 @@ connects to this daemon through `localhost:24224` by default. Use the
     docker run --log-driver=fluentd --log-opt fluentd-address=myhost.local:24224
 
 If container cannot connect to the Fluentd daemon, the container stops
-immediately.
+immediately unless the `fluentd-async-connect` option is used.
 
 ## Options
 
@@ -78,6 +78,9 @@ the log tag format.
 
 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.
 
+### fluentd-async-connect
+
+Docker connects to Fluentd in the background. Messages are buffered until the connection is established.
 
 ## Fluentd daemon management with Docker
 

+ 9 - 4
docs/admin/logging/overview.md

@@ -189,15 +189,20 @@ run slower but compress more. Default value is 1 (BestSpeed).
 You can use the `--log-opt NAME=VALUE` flag to specify these additional Fluentd logging driver options.
 
  - `fluentd-address`: specify `host:port` to connect [localhost:24224]
- - `tag`: specify tag for `fluentd` message,
+ - `tag`: specify tag for `fluentd` message
+ - `fluentd-buffer-limit`: specify the maximum size of the fluentd log buffer [8MB]
+ - `fluentd-retry-wait`: initial delay before a connection retry (after which it increases exponentially) [1000ms]
+ - `fluentd-max-retries`: maximum number of connection retries before abrupt failure of docker [1073741824]
+ - `fluentd-async-connect`: whether to block on initial connection or not [false]
 
 For example, to specify both additional options:
 
 `docker run --log-driver=fluentd --log-opt fluentd-address=localhost:24224 --log-opt tag=docker.{{.Name}}`
 
-If container cannot connect to the Fluentd daemon on the specified address,
-the container stops immediately. For detailed information on working with this
-logging driver, see [the fluentd logging driver](fluentd.md)
+If container cannot connect to the Fluentd daemon on the specified address and
+`fluentd-async-connect` is not enabled, the container stops immediately.
+For detailed information on working with this logging driver,
+see [the fluentd logging driver](fluentd.md)
 
 
 ## Specify Amazon CloudWatch Logs options