Implement docker logs with standalone client lib.
Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
parent
b36531db60
commit
0876742646
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"io"
|
||||||
"time"
|
|
||||||
|
|
||||||
"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{}
|
options := lib.ContainerLogsOptions{
|
||||||
v.Set("stdout", "1")
|
ContainerID: name,
|
||||||
v.Set("stderr", "1")
|
ShowStdout: true,
|
||||||
|
ShowStderr: true,
|
||||||
if *since != "" {
|
Since: *since,
|
||||||
ts, err := timeutils.GetTimestamp(*since, time.Now())
|
Timestamps: *times,
|
||||||
|
Follow: *follow,
|
||||||
|
Tail: *tail,
|
||||||
|
}
|
||||||
|
responseBody, err := cli.client.ContainerLogs(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
v.Set("since", ts)
|
defer responseBody.Close()
|
||||||
}
|
|
||||||
|
|
||||||
if *times {
|
if c.Config.Tty {
|
||||||
v.Set("timestamps", "1")
|
_, err = io.Copy(cli.out, responseBody)
|
||||||
|
} else {
|
||||||
|
_, err = stdcopy.StdCopy(cli.out, cli.err, responseBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *follow {
|
|
||||||
v.Set("follow", "1")
|
|
||||||
}
|
|
||||||
v.Set("tail", *tail)
|
|
||||||
|
|
||||||
sopts := &streamOpts{
|
|
||||||
rawTerminal: c.Config.Tty,
|
|
||||||
out: cli.out,
|
|
||||||
err: cli.err,
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = cli.stream("GET", "/containers/"+name+"/logs?"+v.Encode(), sopts)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
message := fmt.Sprintf("Error: No such container: %s\n", name)
|
||||||
c.Assert(out, checker.Matches, message)
|
c.Assert(out, checker.Equals, message)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue