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