github.com/sams1990/dockerrepo@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  }