Example #1
0
// Logs obtains the stderr and stdout log messages from the container.
func Logs(containerID string, stream StdStream) (string, error) {
	// Create the output buffer.
	buf := bytes.NewBuffer(nil)

	// Create the logs options.
	opts := docker.LogsOptions{
		Container:    containerID,
		Follow:       false,
		OutputStream: buf,
		ErrorStream:  buf,
	}

	if stream == StdStreamCombined {
		opts.Stdout = true
		opts.Stderr = true
	} else if stream == StdStreamOutput {
		opts.Stdout = true
		opts.Stderr = false
	} else if stream == StdStreamError {
		opts.Stdout = false
		opts.Stderr = true
	} else {
		return "", fmt.Errorf("invalid stream option!")
	}

	// Obtain the logs.
	err := Client.Logs(opts)
	if err != nil {
		return "", fmt.Errorf("failed to get container '%s' logs: %v", containerID, err)
	}

	return strings.TrimSpace(buf.String()), nil
}
Example #2
0
// GetKubeletDockerContainerLogs returns logs of specific container
// By default the function will return snapshot of the container log
// Log streaming is possible if 'follow' param is set to true
// Log tailing is possible when number of tailed lines are set and only if 'follow' is false
// TODO: Make 'RawTerminal' option  flagable.
func GetKubeletDockerContainerLogs(client DockerInterface, containerID, tail string, follow bool, stdout, stderr io.Writer) (err error) {
	opts := docker.LogsOptions{
		Container:    containerID,
		Stdout:       true,
		Stderr:       true,
		OutputStream: stdout,
		ErrorStream:  stderr,
		Timestamps:   true,
		RawTerminal:  false,
		Follow:       follow,
	}

	if !follow {
		opts.Tail = tail
	}

	err = client.Logs(opts)
	return
}
Example #3
0
// dockerRun mimics the 'docker run --rm' CLI command. It uses the Docker Remote
// API to create and start a container and stream its logs. The container is
// removed after it terminates.
func dockerRun(client DockerClient, createOpts docker.CreateContainerOptions, logsOpts docker.LogsOptions) error {
	// Create a new container.
	glog.V(4).Infof("Creating container with options {Name:%q Config:%+v HostConfig:%+v} ...", createOpts.Name, createOpts.Config, createOpts.HostConfig)
	c, err := client.CreateContainer(createOpts)
	if err != nil {
		return fmt.Errorf("create container %q: %v", createOpts.Name, err)
	}

	containerName := containerNameOrID(c)

	removeContainer := func() {
		glog.V(4).Infof("Removing container %q ...", containerName)
		if err := client.RemoveContainer(docker.RemoveContainerOptions{ID: c.ID}); err != nil {
			glog.V(0).Infof("warning: Failed to remove container %q: %v", containerName, err)
		} else {
			glog.V(4).Infof("Removed container %q", containerName)
		}
	}
	startWaitContainer := func() error {
		// Start the container.
		glog.V(4).Infof("Starting container %q ...", containerName)
		if err := client.StartContainer(c.ID, nil); err != nil {
			return fmt.Errorf("start container %q: %v", containerName, err)
		}

		// Stream container logs.
		logsOpts.Container = c.ID
		glog.V(4).Infof("Streaming logs of container %q with options %+v ...", containerName, logsOpts)
		if err := client.Logs(logsOpts); err != nil {
			return fmt.Errorf("streaming logs of %q: %v", containerName, err)
		}

		// Return an error if the exit code of the container is non-zero.
		glog.V(4).Infof("Waiting for container %q to stop ...", containerName)
		exitCode, err := client.WaitContainer(c.ID)
		if err != nil {
			return fmt.Errorf("waiting for container %q to stop: %v", containerName, err)
		}
		if exitCode != 0 {
			return fmt.Errorf("container %q returned non-zero exit code: %d", containerName, exitCode)
		}
		return nil
	}
	// the interrupt handler acts as a super-defer which will guarantee removeContainer is executed
	// either when startWaitContainer finishes, or when a SIGQUIT/SIGINT/SIGTERM is received.
	return interrupt.New(nil, removeContainer).Run(startWaitContainer)
}
Example #4
0
// dockerRun mimics the 'docker run --rm' CLI command. It uses the Docker Remote
// API to create and start a container and stream its logs. The container is
// removed after it terminates.
func dockerRun(client DockerClient, createOpts docker.CreateContainerOptions, logsOpts docker.LogsOptions) error {
	// Create a new container.
	glog.V(4).Infof("Creating container with options {Name:%q Config:%+v HostConfig:%+v} ...", createOpts.Name, createOpts.Config, createOpts.HostConfig)
	c, err := client.CreateContainer(createOpts)
	if err != nil {
		return fmt.Errorf("create container %q: %v", createOpts.Name, err)
	}

	containerName := containerNameOrID(c)

	// Container was created, so we defer its removal.
	defer func() {
		glog.V(4).Infof("Removing container %q ...", containerName)
		if err := client.RemoveContainer(docker.RemoveContainerOptions{ID: c.ID}); err != nil {
			glog.Warningf("Failed to remove container %q: %v", containerName, err)
		} else {
			glog.V(4).Infof("Removed container %q", containerName)
		}
	}()

	// Start the container.
	glog.V(4).Infof("Starting container %q ...", containerName)
	if err := client.StartContainer(c.ID, nil); err != nil {
		return fmt.Errorf("start container %q: %v", containerName, err)
	}

	// Stream container logs.
	logsOpts.Container = c.ID
	glog.V(4).Infof("Streaming logs of container %q with options %+v ...", containerName, logsOpts)
	if err := client.Logs(logsOpts); err != nil {
		return fmt.Errorf("streaming logs of %q: %v", containerName, err)
	}

	// Return an error if the exit code of the container is non-zero.
	glog.V(4).Infof("Waiting for container %q to stop ...", containerName)
	exitCode, err := client.WaitContainer(c.ID)
	if err != nil {
		return fmt.Errorf("waiting for container %q to stop: %v", containerName, err)
	}
	if exitCode != 0 {
		return fmt.Errorf("container %q returned non-zero exit code: %d", containerName, exitCode)
	}

	return nil
}
Example #5
0
func (l *LogsHandler) Handle(key string, initialMessage string, incomingMessages <-chan string, response chan<- common.Message) {
	defer backend.SignalHandlerClosed(key, response)

	requestUrl, err := url.Parse(initialMessage)
	if err != nil {
		log.WithFields(log.Fields{"error": err, "url": initialMessage}).Error("Couldn't parse url.")
		return
	}
	tokenString := requestUrl.Query().Get("token")
	token, valid := auth.GetAndCheckToken(tokenString)
	if !valid {
		return
	}

	logs := token.Claims["logs"].(map[string]interface{})
	container := logs["Container"].(string)
	follow, found := logs["Follow"].(bool)

	if !found {
		follow = true
	}

	tailTemp, found := logs["Lines"].(int)
	var tail string
	if found {
		tail = strconv.Itoa(int(tailTemp))
	} else {
		tail = "100"
	}

	client, err := events.NewDockerClient()
	if err != nil {
		log.WithFields(log.Fields{"error": err}).Error("Couldn't get docker client.")
		return
	}

	reader, writer := io.Pipe()

	containerRef, err := client.InspectContainer(container)
	if err != nil {
		return
	}

	logopts := dockerClient.LogsOptions{
		Container:  container,
		Follow:     follow,
		Stdout:     true,
		Stderr:     true,
		Timestamps: true,
		Tail:       tail,
	}
	if containerRef.Config.Tty {
		logopts.OutputStream = stdbothWriter{writer}
		logopts.RawTerminal = true
	} else {
		logopts.OutputStream = stdoutWriter{writer}
		logopts.ErrorStream = stderrorWriter{writer}
		logopts.RawTerminal = false
	}

	go func(w *io.PipeWriter) {
		for {
			_, ok := <-incomingMessages
			if !ok {
				w.Close()
				return
			}
		}
	}(writer)

	go func(r *io.PipeReader) {
		scanner := bufio.NewScanner(r)
		scanner.Split(customSplit)
		for scanner.Scan() {
			text := scanner.Text()
			message := common.Message{
				Key:  key,
				Type: common.Body,
				Body: text,
			}
			response <- message
		}
		if err := scanner.Err(); err != nil {
			log.WithFields(log.Fields{"error": err}).Error("Error with the container log scanner.")
		}
	}(reader)

	// Returns an error, but ignoring it because it will always return an error when a streaming call is made.
	client.Logs(logopts)
}