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 }