github.com/chenchun/docker@v1.3.2-0.20150629222414-20467faf132b/daemon/logger/fluentd/fluentd.go (about)

     1  package fluentd
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"math"
     7  	"net"
     8  	"strconv"
     9  	"strings"
    10  	"text/template"
    11  
    12  	"github.com/Sirupsen/logrus"
    13  	"github.com/docker/docker/daemon/logger"
    14  	"github.com/fluent/fluent-logger-golang/fluent"
    15  )
    16  
    17  type Fluentd struct {
    18  	tag           string
    19  	containerID   string
    20  	containerName string
    21  	writer        *fluent.Fluent
    22  }
    23  
    24  type Receiver struct {
    25  	ID     string
    26  	FullID string
    27  	Name   string
    28  }
    29  
    30  const (
    31  	name             = "fluentd"
    32  	defaultHostName  = "localhost"
    33  	defaultPort      = 24224
    34  	defaultTagPrefix = "docker"
    35  )
    36  
    37  func init() {
    38  	if err := logger.RegisterLogDriver(name, New); err != nil {
    39  		logrus.Fatal(err)
    40  	}
    41  }
    42  
    43  func parseConfig(ctx logger.Context) (string, int, string, error) {
    44  	host := defaultHostName
    45  	port := defaultPort
    46  	tag := "docker." + ctx.ContainerID[:12]
    47  
    48  	config := ctx.Config
    49  
    50  	if address := config["fluentd-address"]; address != "" {
    51  		if h, p, err := net.SplitHostPort(address); err != nil {
    52  			if !strings.Contains(err.Error(), "missing port in address") {
    53  				return "", 0, "", err
    54  			}
    55  			host = h
    56  		} else {
    57  			portnum, err := strconv.Atoi(p)
    58  			if err != nil {
    59  				return "", 0, "", err
    60  			}
    61  			host = h
    62  			port = portnum
    63  		}
    64  	}
    65  
    66  	if config["fluentd-tag"] != "" {
    67  		receiver := &Receiver{
    68  			ID:     ctx.ContainerID[:12],
    69  			FullID: ctx.ContainerID,
    70  			Name:   ctx.ContainerName,
    71  		}
    72  		tmpl, err := template.New("tag").Parse(config["fluentd-tag"])
    73  		if err != nil {
    74  			return "", 0, "", err
    75  		}
    76  		buf := new(bytes.Buffer)
    77  		if err := tmpl.Execute(buf, receiver); err != nil {
    78  			return "", 0, "", err
    79  		}
    80  		tag = buf.String()
    81  	}
    82  
    83  	return host, port, tag, nil
    84  }
    85  
    86  func New(ctx logger.Context) (logger.Logger, error) {
    87  	host, port, tag, err := parseConfig(ctx)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	logrus.Debugf("logging driver fluentd configured for container:%s, host:%s, port:%d, tag:%s.", ctx.ContainerID, host, port, tag)
    92  
    93  	// logger tries to recoonect 2**64 - 1 times
    94  	// failed (and panic) after 204 years [ 1.5 ** (2**32 - 1) - 1 seconds]
    95  	log, err := fluent.New(fluent.Config{FluentPort: port, FluentHost: host, RetryWait: 1000, MaxRetry: math.MaxUint32})
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	return &Fluentd{
   100  		tag:           tag,
   101  		containerID:   ctx.ContainerID,
   102  		containerName: ctx.ContainerName,
   103  		writer:        log,
   104  	}, nil
   105  }
   106  
   107  func (f *Fluentd) Log(msg *logger.Message) error {
   108  	data := map[string]string{
   109  		"container_id":   f.containerID,
   110  		"container_name": f.containerName,
   111  		"source":         msg.Source,
   112  		"log":            string(msg.Line),
   113  	}
   114  	// fluent-logger-golang buffers logs from failures and disconnections,
   115  	// and these are transferred again automatically.
   116  	return f.writer.PostWithTime(f.tag, msg.Timestamp, data)
   117  }
   118  
   119  func (f *Fluentd) Close() error {
   120  	return f.writer.Close()
   121  }
   122  
   123  func (f *Fluentd) Name() string {
   124  	return name
   125  }
   126  
   127  func (s *Fluentd) GetReader() (io.Reader, error) {
   128  	return nil, logger.ReadLogsNotSupported
   129  }