github.com/rsampaio/docker@v0.7.2-0.20150827203920-fdc73cc3fc31/daemon/logger/gelf/gelf.go (about) 1 // +build linux 2 3 // Package gelf provides the log driver for forwarding server logs to 4 // endpoints that support the Graylog Extended Log Format. 5 package gelf 6 7 import ( 8 "bytes" 9 "fmt" 10 "net" 11 "net/url" 12 "time" 13 14 "github.com/Graylog2/go-gelf/gelf" 15 "github.com/Sirupsen/logrus" 16 "github.com/docker/docker/daemon/logger" 17 "github.com/docker/docker/pkg/urlutil" 18 ) 19 20 const name = "gelf" 21 22 type gelfLogger struct { 23 writer *gelf.Writer 24 ctx logger.Context 25 fields gelfFields 26 } 27 28 type gelfFields struct { 29 hostname string 30 containerID string 31 containerName string 32 imageID string 33 imageName string 34 command string 35 tag string 36 created time.Time 37 } 38 39 func init() { 40 if err := logger.RegisterLogDriver(name, New); err != nil { 41 logrus.Fatal(err) 42 } 43 if err := logger.RegisterLogOptValidator(name, ValidateLogOpt); err != nil { 44 logrus.Fatal(err) 45 } 46 } 47 48 // New creates a gelf logger using the configuration passed in on the 49 // context. Supported context configuration variables are 50 // gelf-address, & gelf-tag. 51 func New(ctx logger.Context) (logger.Logger, error) { 52 // parse gelf address 53 address, err := parseAddress(ctx.Config["gelf-address"]) 54 if err != nil { 55 return nil, err 56 } 57 58 // collect extra data for GELF message 59 hostname, err := ctx.Hostname() 60 if err != nil { 61 return nil, fmt.Errorf("gelf: cannot access hostname to set source field") 62 } 63 64 // remove trailing slash from container name 65 containerName := bytes.TrimLeft([]byte(ctx.ContainerName), "/") 66 67 fields := gelfFields{ 68 hostname: hostname, 69 containerID: ctx.ContainerID, 70 containerName: string(containerName), 71 imageID: ctx.ContainerImageID, 72 imageName: ctx.ContainerImageName, 73 command: ctx.Command(), 74 tag: ctx.Config["gelf-tag"], 75 created: ctx.ContainerCreated, 76 } 77 78 // create new gelfWriter 79 gelfWriter, err := gelf.NewWriter(address) 80 if err != nil { 81 return nil, fmt.Errorf("gelf: cannot connect to GELF endpoint: %s %v", address, err) 82 } 83 84 return &gelfLogger{ 85 writer: gelfWriter, 86 ctx: ctx, 87 fields: fields, 88 }, nil 89 } 90 91 func (s *gelfLogger) Log(msg *logger.Message) error { 92 // remove trailing and leading whitespace 93 short := bytes.TrimSpace([]byte(msg.Line)) 94 95 level := gelf.LOG_INFO 96 if msg.Source == "stderr" { 97 level = gelf.LOG_ERR 98 } 99 100 m := gelf.Message{ 101 Version: "1.1", 102 Host: s.fields.hostname, 103 Short: string(short), 104 TimeUnix: float64(msg.Timestamp.UnixNano()/int64(time.Millisecond)) / 1000.0, 105 Level: level, 106 Extra: map[string]interface{}{ 107 "_container_id": s.fields.containerID, 108 "_container_name": s.fields.containerName, 109 "_image_id": s.fields.imageID, 110 "_image_name": s.fields.imageName, 111 "_command": s.fields.command, 112 "_tag": s.fields.tag, 113 "_created": s.fields.created, 114 }, 115 } 116 117 if err := s.writer.WriteMessage(&m); err != nil { 118 return fmt.Errorf("gelf: cannot send GELF message: %v", err) 119 } 120 return nil 121 } 122 123 func (s *gelfLogger) Close() error { 124 return s.writer.Close() 125 } 126 127 func (s *gelfLogger) Name() string { 128 return name 129 } 130 131 // ValidateLogOpt looks for gelf specific log options gelf-address, & 132 // gelf-tag. 133 func ValidateLogOpt(cfg map[string]string) error { 134 for key := range cfg { 135 switch key { 136 case "gelf-address": 137 case "gelf-tag": 138 default: 139 return fmt.Errorf("unknown log opt '%s' for gelf log driver", key) 140 } 141 } 142 return nil 143 } 144 145 func parseAddress(address string) (string, error) { 146 if urlutil.IsTransportURL(address) { 147 url, err := url.Parse(address) 148 if err != nil { 149 return "", err 150 } 151 152 // we support only udp 153 if url.Scheme != "udp" { 154 return "", fmt.Errorf("gelf: endpoint needs to be UDP") 155 } 156 157 // get host and port 158 if _, _, err = net.SplitHostPort(url.Host); err != nil { 159 return "", fmt.Errorf("gelf: please provide gelf-address as udp://host:port") 160 } 161 162 return url.Host, nil 163 } 164 165 return "", nil 166 }