github.com/LazyboyChen7/engine@v17.12.1-ce-rc2+incompatible/api/server/httputils/write_log_stream.go (about) 1 package httputils 2 3 import ( 4 "fmt" 5 "io" 6 "net/url" 7 "sort" 8 9 "golang.org/x/net/context" 10 11 "github.com/docker/docker/api/types" 12 "github.com/docker/docker/api/types/backend" 13 "github.com/docker/docker/pkg/ioutils" 14 "github.com/docker/docker/pkg/jsonmessage" 15 "github.com/docker/docker/pkg/stdcopy" 16 ) 17 18 // WriteLogStream writes an encoded byte stream of log messages from the 19 // messages channel, multiplexing them with a stdcopy.Writer if mux is true 20 func WriteLogStream(_ context.Context, w io.Writer, msgs <-chan *backend.LogMessage, config *types.ContainerLogsOptions, mux bool) { 21 wf := ioutils.NewWriteFlusher(w) 22 defer wf.Close() 23 24 wf.Flush() 25 26 outStream := io.Writer(wf) 27 errStream := outStream 28 sysErrStream := errStream 29 if mux { 30 sysErrStream = stdcopy.NewStdWriter(outStream, stdcopy.Systemerr) 31 errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) 32 outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) 33 } 34 35 for { 36 msg, ok := <-msgs 37 if !ok { 38 return 39 } 40 // check if the message contains an error. if so, write that error 41 // and exit 42 if msg.Err != nil { 43 fmt.Fprintf(sysErrStream, "Error grabbing logs: %v\n", msg.Err) 44 continue 45 } 46 logLine := msg.Line 47 if config.Details { 48 logLine = append(attrsByteSlice(msg.Attrs), ' ') 49 logLine = append(logLine, msg.Line...) 50 } 51 if config.Timestamps { 52 logLine = append([]byte(msg.Timestamp.Format(jsonmessage.RFC3339NanoFixed)+" "), logLine...) 53 } 54 if msg.Source == "stdout" && config.ShowStdout { 55 outStream.Write(logLine) 56 } 57 if msg.Source == "stderr" && config.ShowStderr { 58 errStream.Write(logLine) 59 } 60 } 61 } 62 63 type byKey []backend.LogAttr 64 65 func (b byKey) Len() int { return len(b) } 66 func (b byKey) Less(i, j int) bool { return b[i].Key < b[j].Key } 67 func (b byKey) Swap(i, j int) { b[i], b[j] = b[j], b[i] } 68 69 func attrsByteSlice(a []backend.LogAttr) []byte { 70 // Note this sorts "a" in-place. That is fine here - nothing else is 71 // going to use Attrs or care about the order. 72 sort.Sort(byKey(a)) 73 74 var ret []byte 75 for i, pair := range a { 76 k, v := url.QueryEscape(pair.Key), url.QueryEscape(pair.Value) 77 ret = append(ret, []byte(k)...) 78 ret = append(ret, '=') 79 ret = append(ret, []byte(v)...) 80 if i != len(a)-1 { 81 ret = append(ret, ',') 82 } 83 } 84 return ret 85 }