Browse Source

Implement docker logs with standalone client lib.

Signed-off-by: David Calavera <david.calavera@gmail.com>
David Calavera 9 years ago
parent
commit
0876742646

+ 20 - 0
api/client/lib/container_inspect.go

@@ -0,0 +1,20 @@
+package lib
+
+import (
+	"encoding/json"
+
+	"github.com/docker/docker/api/types"
+)
+
+// ContainerInspect returns the all the container information.
+func (cli *Client) ContainerInspect(containerID string) (types.ContainerJSON, error) {
+	serverResp, err := cli.GET("/containers/"+containerID+"/json", nil, nil)
+	if err != nil {
+		return types.ContainerJSON{}, err
+	}
+	defer serverResp.body.Close()
+
+	var response types.ContainerJSON
+	json.NewDecoder(serverResp.body).Decode(&response)
+	return response, err
+}

+ 56 - 0
api/client/lib/logs.go

@@ -0,0 +1,56 @@
+package lib
+
+import (
+	"io"
+	"net/url"
+	"time"
+
+	"github.com/docker/docker/pkg/timeutils"
+)
+
+// ContainerLogsOptions holds parameters to filter logs with.
+type ContainerLogsOptions struct {
+	ContainerID string
+	ShowStdout  bool
+	ShowStderr  bool
+	Since       string
+	Timestamps  bool
+	Follow      bool
+	Tail        string
+}
+
+// ContainerLogs returns the logs generated by a container in an io.ReadCloser.
+// It's up to the caller to close the stream.
+func (cli *Client) ContainerLogs(options ContainerLogsOptions) (io.ReadCloser, error) {
+	var query url.Values
+	if options.ShowStdout {
+		query.Set("stdout", "1")
+	}
+
+	if options.ShowStderr {
+		query.Set("stderr", "1")
+	}
+
+	if options.Since != "" {
+		ts, err := timeutils.GetTimestamp(options.Since, time.Now())
+		if err != nil {
+			return nil, err
+		}
+		query.Set("since", ts)
+	}
+
+	if options.Timestamps {
+		query.Set("timestamps", "1")
+	}
+
+	if options.Follow {
+		query.Set("follow", "1")
+	}
+	query.Set("tail", options.Tail)
+
+	resp, err := cli.GET("/containers/"+options.ContainerID+"/logs", query, nil)
+	if err != nil {
+		return nil, err
+	}
+	return resp.body, nil
+}

+ 20 - 35
api/client/logs.go

@@ -1,15 +1,13 @@
 package client
 package client
 
 
 import (
 import (
-	"encoding/json"
 	"fmt"
 	"fmt"
-	"net/url"
-	"time"
+	"io"
 
 
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/client/lib"
 	Cli "github.com/docker/docker/cli"
 	Cli "github.com/docker/docker/cli"
 	flag "github.com/docker/docker/pkg/mflag"
 	flag "github.com/docker/docker/pkg/mflag"
-	"github.com/docker/docker/pkg/timeutils"
+	"github.com/docker/docker/pkg/stdcopy"
 )
 )
 
 
 var validDrivers = map[string]bool{
 var validDrivers = map[string]bool{
@@ -32,47 +30,34 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
 
 
 	name := cmd.Arg(0)
 	name := cmd.Arg(0)
 
 
-	serverResp, err := cli.call("GET", "/containers/"+name+"/json", nil, nil)
+	c, err := cli.client.ContainerInspect(name)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	var c types.ContainerJSON
-	if err := json.NewDecoder(serverResp.body).Decode(&c); err != nil {
-		return err
-	}
-
 	if !validDrivers[c.HostConfig.LogConfig.Type] {
 	if !validDrivers[c.HostConfig.LogConfig.Type] {
 		return fmt.Errorf("\"logs\" command is supported only for \"json-file\" and \"journald\" logging drivers (got: %s)", c.HostConfig.LogConfig.Type)
 		return fmt.Errorf("\"logs\" command is supported only for \"json-file\" and \"journald\" logging drivers (got: %s)", c.HostConfig.LogConfig.Type)
 	}
 	}
 
 
-	v := url.Values{}
-	v.Set("stdout", "1")
-	v.Set("stderr", "1")
-
-	if *since != "" {
-		ts, err := timeutils.GetTimestamp(*since, time.Now())
-		if err != nil {
-			return err
-		}
-		v.Set("since", ts)
-	}
-
-	if *times {
-		v.Set("timestamps", "1")
+	options := lib.ContainerLogsOptions{
+		ContainerID: name,
+		ShowStdout:  true,
+		ShowStderr:  true,
+		Since:       *since,
+		Timestamps:  *times,
+		Follow:      *follow,
+		Tail:        *tail,
 	}
 	}
-
-	if *follow {
-		v.Set("follow", "1")
+	responseBody, err := cli.client.ContainerLogs(options)
+	if err != nil {
+		return err
 	}
 	}
-	v.Set("tail", *tail)
+	defer responseBody.Close()
 
 
-	sopts := &streamOpts{
-		rawTerminal: c.Config.Tty,
-		out:         cli.out,
-		err:         cli.err,
+	if c.Config.Tty {
+		_, err = io.Copy(cli.out, responseBody)
+	} else {
+		_, err = stdcopy.StdCopy(cli.out, cli.err, responseBody)
 	}
 	}
-
-	_, err = cli.stream("GET", "/containers/"+name+"/logs?"+v.Encode(), sopts)
 	return err
 	return err
 }
 }

+ 2 - 2
integration-cli/docker_cli_logs_test.go

@@ -349,6 +349,6 @@ func (s *DockerSuite) TestLogsFollowGoroutinesNoOutput(c *check.C) {
 func (s *DockerSuite) TestLogsCLIContainerNotFound(c *check.C) {
 func (s *DockerSuite) TestLogsCLIContainerNotFound(c *check.C) {
 	name := "testlogsnocontainer"
 	name := "testlogsnocontainer"
 	out, _, _ := dockerCmdWithError("logs", name)
 	out, _, _ := dockerCmdWithError("logs", name)
-	message := fmt.Sprintf(".*No such container: %s.*\n", name)
-	c.Assert(out, checker.Matches, message)
+	message := fmt.Sprintf("Error: No such container: %s\n", name)
+	c.Assert(out, checker.Equals, message)
 }
 }