github.com/gunjan5/docker@v1.8.2/daemon/logger/fluentd/fluentd.go (about) 1 package fluentd 2 3 import ( 4 "bytes" 5 "fmt" 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 if err := logger.RegisterLogOptValidator(name, ValidateLogOpt); err != nil { 42 logrus.Fatal(err) 43 } 44 } 45 46 func parseConfig(ctx logger.Context) (string, int, string, error) { 47 host := defaultHostName 48 port := defaultPort 49 tag := "docker." + ctx.ContainerID[:12] 50 51 config := ctx.Config 52 53 if address := config["fluentd-address"]; address != "" { 54 if h, p, err := net.SplitHostPort(address); err != nil { 55 if !strings.Contains(err.Error(), "missing port in address") { 56 return "", 0, "", err 57 } 58 host = h 59 } else { 60 portnum, err := strconv.Atoi(p) 61 if err != nil { 62 return "", 0, "", err 63 } 64 host = h 65 port = portnum 66 } 67 } 68 69 if config["fluentd-tag"] != "" { 70 receiver := &Receiver{ 71 ID: ctx.ContainerID[:12], 72 FullID: ctx.ContainerID, 73 Name: ctx.ContainerName, 74 } 75 tmpl, err := template.New("tag").Parse(config["fluentd-tag"]) 76 if err != nil { 77 return "", 0, "", err 78 } 79 buf := new(bytes.Buffer) 80 if err := tmpl.Execute(buf, receiver); err != nil { 81 return "", 0, "", err 82 } 83 tag = buf.String() 84 } 85 86 return host, port, tag, nil 87 } 88 89 func New(ctx logger.Context) (logger.Logger, error) { 90 host, port, tag, err := parseConfig(ctx) 91 if err != nil { 92 return nil, err 93 } 94 logrus.Debugf("logging driver fluentd configured for container:%s, host:%s, port:%d, tag:%s.", ctx.ContainerID, host, port, tag) 95 96 // logger tries to recoonect 2**32 - 1 times 97 // failed (and panic) after 204 years [ 1.5 ** (2**32 - 1) - 1 seconds] 98 log, err := fluent.New(fluent.Config{FluentPort: port, FluentHost: host, RetryWait: 1000, MaxRetry: math.MaxInt32}) 99 if err != nil { 100 return nil, err 101 } 102 return &Fluentd{ 103 tag: tag, 104 containerID: ctx.ContainerID, 105 containerName: ctx.ContainerName, 106 writer: log, 107 }, nil 108 } 109 110 func (f *Fluentd) Log(msg *logger.Message) error { 111 data := map[string]string{ 112 "container_id": f.containerID, 113 "container_name": f.containerName, 114 "source": msg.Source, 115 "log": string(msg.Line), 116 } 117 // fluent-logger-golang buffers logs from failures and disconnections, 118 // and these are transferred again automatically. 119 return f.writer.PostWithTime(f.tag, msg.Timestamp, data) 120 } 121 122 func ValidateLogOpt(cfg map[string]string) error { 123 for key := range cfg { 124 switch key { 125 case "fluentd-address": 126 case "fluentd-tag": 127 default: 128 return fmt.Errorf("unknown log opt '%s' for fluentd log driver", key) 129 } 130 } 131 return nil 132 } 133 134 func (f *Fluentd) Close() error { 135 return f.writer.Close() 136 } 137 138 func (f *Fluentd) Name() string { 139 return name 140 }