mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
1044093bb0
Refactor container logs system to make communicating log messages internally much simpler. Move responsibility for marshalling log messages into the REST server. Support TTY logs. Pave the way for fixing the ambiguous bytestream format. Pave the way for fixing details. Signed-off-by: Drew Erny <drew.erny@docker.com>
92 lines
2.5 KiB
Go
92 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, ",")
|
|
}
|