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