mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
93 lines
2.5 KiB
Go
93 lines
2.5 KiB
Go
![]() |
package httputils
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"sort"
|
||
|
"strings"
|
||
|
|
||
|
"golang.org/x/net/context"
|
||
|
|
||
|
"github.com/docker/docker/api/types"
|
||
|
"github.com/docker/docker/api/types/backend"
|
||
|
"github.com/docker/docker/pkg/ioutils"
|
||
|
"github.com/docker/docker/pkg/jsonlog"
|
||
|
"github.com/docker/docker/pkg/stdcopy"
|
||
|
)
|
||
|
|
||
|
// WriteLogStream writes an encoded byte stream of log messages from the
|
||
|
// messages channel, multiplexing them with a stdcopy.Writer if mux is true
|
||
|
func WriteLogStream(ctx context.Context, w io.Writer, msgs <-chan *backend.LogMessage, config *types.ContainerLogsOptions, mux bool) {
|
||
|
wf := ioutils.NewWriteFlusher(w)
|
||
|
defer wf.Close()
|
||
|
|
||
|
wf.Flush()
|
||
|
|
||
|
// this might seem like doing below is clear:
|
||
|
// var outStream io.Writer = wf
|
||
|
// however, this GREATLY DISPLEASES golint, and if you do that, it will
|
||
|
// fail CI. we need outstream to be type writer because if we mux streams,
|
||
|
// we will need to reassign all of the streams to be stdwriters, which only
|
||
|
// conforms to the io.Writer interface.
|
||
|
var outStream io.Writer
|
||
|
outStream = wf
|
||
|
errStream := outStream
|
||
|
sysErrStream := errStream
|
||
|
if mux {
|
||
|
sysErrStream = stdcopy.NewStdWriter(outStream, stdcopy.Systemerr)
|
||
|
errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
|
||
|
outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
msg, ok := <-msgs
|
||
|
if !ok {
|
||
|
return
|
||
|
}
|
||
|
// check if the message contains an error. if so, write that error
|
||
|
// and exit
|
||
|
if msg.Err != nil {
|
||
|
fmt.Fprintf(sysErrStream, "Error grabbing logs: %v\n", msg.Err)
|
||
|
continue
|
||
|
}
|
||
|
logLine := msg.Line
|
||
|
if config.Details {
|
||
|
logLine = append([]byte(stringAttrs(msg.Attrs)+" "), logLine...)
|
||
|
}
|
||
|
if config.Timestamps {
|
||
|
// TODO(dperny) the format is defined in
|
||
|
// daemon/logger/logger.go as logger.TimeFormat. importing
|
||
|
// logger is verboten (not part of backend) so idk if just
|
||
|
// importing the same thing from jsonlog is good enough
|
||
|
logLine = append([]byte(msg.Timestamp.Format(jsonlog.RFC3339NanoFixed)+" "), logLine...)
|
||
|
}
|
||
|
if msg.Source == "stdout" && config.ShowStdout {
|
||
|
outStream.Write(logLine)
|
||
|
}
|
||
|
if msg.Source == "stderr" && config.ShowStderr {
|
||
|
errStream.Write(logLine)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type byKey []string
|
||
|
|
||
|
func (s byKey) Len() int { return len(s) }
|
||
|
func (s byKey) Less(i, j int) bool {
|
||
|
keyI := strings.Split(s[i], "=")
|
||
|
keyJ := strings.Split(s[j], "=")
|
||
|
return keyI[0] < keyJ[0]
|
||
|
}
|
||
|
func (s byKey) Swap(i, j int) {
|
||
|
s[i], s[j] = s[j], s[i]
|
||
|
}
|
||
|
|
||
|
func stringAttrs(a backend.LogAttributes) string {
|
||
|
var ss byKey
|
||
|
for k, v := range a {
|
||
|
ss = append(ss, k+"="+v)
|
||
|
}
|
||
|
sort.Sort(ss)
|
||
|
return strings.Join(ss, ",")
|
||
|
}
|