
This is done by moving the following types to api/types/config.go: - ContainersConfig - ContainerAttachWithLogsConfig - ContainerWsAttachWithLogsConfig - ContainerLogsConfig - ContainerStatsConfig Remove dependency on "version" package from types.ContainerStatsConfig. Decouple the "container" router from the "daemon/exec" implementation. * This is done by making daemon.ContainerExecInspect() return an interface{} value. The same trick is already used by daemon.ContainerInspect(). Improve documentation for router packages. Extract localRoute and router into separate files. Move local.router to image.imageRouter. Changes: - Move local/image.go to image/image_routes.go. - Move local/local.go to image/image.go - Rename router to imageRouter. - Simplify imports for image/image.go (remove alias for router package). Merge router/local package into router package. Decouple the "image" router from the actual daemon implementation. Add Daemon.GetNetworkByID and Daemon.GetNetworkByName. Decouple the "network" router from the actual daemon implementation. This is done by replacing the daemon.NetworkByName constant with an explicit GetNetworkByName method. Remove the unused Daemon.GetNetwork method and the associated constants NetworkByID and NetworkByName. Signed-off-by: Lukas Waslowski <cr7pt0gr4ph7@gmail.com> Signed-off-by: David Calavera <david.calavera@gmail.com>
123 lines
3.2 KiB
Go
123 lines
3.2 KiB
Go
package daemon
|
|
|
|
import (
|
|
"io"
|
|
"strconv"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/docker/docker/container"
|
|
"github.com/docker/docker/daemon/logger"
|
|
"github.com/docker/docker/daemon/logger/jsonfilelog"
|
|
derr "github.com/docker/docker/errors"
|
|
"github.com/docker/docker/pkg/stdcopy"
|
|
"github.com/docker/engine-api/types/backend"
|
|
)
|
|
|
|
// ContainerLogs hooks up a container's stdout and stderr streams
|
|
// configured with the given struct.
|
|
func (daemon *Daemon) ContainerLogs(containerName string, config *backend.ContainerLogsConfig) error {
|
|
container, err := daemon.GetContainer(containerName)
|
|
if err != nil {
|
|
return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
|
|
}
|
|
|
|
if !(config.UseStdout || config.UseStderr) {
|
|
return derr.ErrorCodeNeedStream
|
|
}
|
|
|
|
outStream := config.OutStream
|
|
errStream := outStream
|
|
if !container.Config.Tty {
|
|
errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
|
|
outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
|
|
}
|
|
config.OutStream = outStream
|
|
|
|
cLog, err := daemon.getLogger(container)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
logReader, ok := cLog.(logger.LogReader)
|
|
if !ok {
|
|
return logger.ErrReadLogsNotSupported
|
|
}
|
|
|
|
follow := config.Follow && container.IsRunning()
|
|
tailLines, err := strconv.Atoi(config.Tail)
|
|
if err != nil {
|
|
tailLines = -1
|
|
}
|
|
|
|
logrus.Debug("logs: begin stream")
|
|
readConfig := logger.ReadConfig{
|
|
Since: config.Since,
|
|
Tail: tailLines,
|
|
Follow: follow,
|
|
}
|
|
logs := logReader.ReadLogs(readConfig)
|
|
|
|
for {
|
|
select {
|
|
case err := <-logs.Err:
|
|
logrus.Errorf("Error streaming logs: %v", err)
|
|
return nil
|
|
case <-config.Stop:
|
|
logs.Close()
|
|
return nil
|
|
case msg, ok := <-logs.Msg:
|
|
if !ok {
|
|
logrus.Debugf("logs: end stream")
|
|
return nil
|
|
}
|
|
logLine := msg.Line
|
|
if config.Timestamps {
|
|
logLine = append([]byte(msg.Timestamp.Format(logger.TimeFormat)+" "), logLine...)
|
|
}
|
|
if msg.Source == "stdout" && config.UseStdout {
|
|
outStream.Write(logLine)
|
|
}
|
|
if msg.Source == "stderr" && config.UseStderr {
|
|
errStream.Write(logLine)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (daemon *Daemon) getLogger(container *container.Container) (logger.Logger, error) {
|
|
if container.LogDriver != nil && container.IsRunning() {
|
|
return container.LogDriver, nil
|
|
}
|
|
cfg := container.GetLogConfig(daemon.defaultLogConfig)
|
|
if err := logger.ValidateLogOpts(cfg.Type, cfg.Config); err != nil {
|
|
return nil, err
|
|
}
|
|
return container.StartLogger(cfg)
|
|
}
|
|
|
|
// StartLogging initializes and starts the container logging stream.
|
|
func (daemon *Daemon) StartLogging(container *container.Container) error {
|
|
cfg := container.GetLogConfig(daemon.defaultLogConfig)
|
|
if cfg.Type == "none" {
|
|
return nil // do not start logging routines
|
|
}
|
|
|
|
if err := logger.ValidateLogOpts(cfg.Type, cfg.Config); err != nil {
|
|
return err
|
|
}
|
|
l, err := container.StartLogger(cfg)
|
|
if err != nil {
|
|
return derr.ErrorCodeInitLogger.WithArgs(err)
|
|
}
|
|
|
|
copier := logger.NewCopier(container.ID, map[string]io.Reader{"stdout": container.StdoutPipe(), "stderr": container.StderrPipe()}, l)
|
|
container.LogCopier = copier
|
|
copier.Run()
|
|
container.LogDriver = l
|
|
|
|
// set LogPath field only for json-file logdriver
|
|
if jl, ok := l.(*jsonfilelog.JSONFileLogger); ok {
|
|
container.LogPath = jl.LogPath()
|
|
}
|
|
|
|
return nil
|
|
}
|