diff options
author | Urvashi Mohnani <umohnani@redhat.com> | 2017-11-21 12:18:25 -0500 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2017-11-22 19:33:13 +0000 |
commit | ee4051db61ad8ce6f385ce5be45dcc4b0a29945d (patch) | |
tree | 68672ed0247fd43c31447b4d80920b442e0fecc3 | |
parent | 40dce698d3359a6bf89ed954a483454daf2e9fb2 (diff) | |
download | podman-ee4051db61ad8ce6f385ce5be45dcc4b0a29945d.tar.gz podman-ee4051db61ad8ce6f385ce5be45dcc4b0a29945d.tar.bz2 podman-ee4051db61ad8ce6f385ce5be45dcc4b0a29945d.zip |
Update kpod logs to use the new container state and runtime
Signed-off-by: Urvashi Mohnani <umohnani@redhat.com>
Closes: #62
Approved by: rhatdan
-rw-r--r-- | cmd/kpod/logs.go | 105 | ||||
-rw-r--r-- | libkpod/logs.go | 80 | ||||
-rw-r--r-- | test/kpod_logs.bats | 51 |
3 files changed, 94 insertions, 142 deletions
diff --git a/cmd/kpod/logs.go b/cmd/kpod/logs.go index 1d0cea996..726ba4a65 100644 --- a/cmd/kpod/logs.go +++ b/cmd/kpod/logs.go @@ -2,13 +2,22 @@ package main import ( "fmt" + "strings" "time" + "github.com/hpcloud/tail" "github.com/pkg/errors" - "github.com/projectatomic/libpod/libkpod" + "github.com/projectatomic/libpod/libpod" "github.com/urfave/cli" ) +type logOptions struct { + details bool + follow bool + sinceTime time.Time + tail uint64 +} + var ( logsFlags = []cli.Flag{ cli.BoolFlag{ @@ -42,51 +51,103 @@ var ( ) func logsCmd(c *cli.Context) error { + if err := validateFlags(c, logsFlags); err != nil { + return err + } + + runtime, err := getRuntime(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + args := c.Args() if len(args) != 1 { return errors.Errorf("'kpod logs' requires exactly one container name/ID") } - if err := validateFlags(c, logsFlags); err != nil { - return err - } - container := c.Args().First() - var opts libkpod.LogOptions - opts.Details = c.Bool("details") - opts.Follow = c.Bool("follow") - opts.SinceTime = time.Time{} + + sinceTime := time.Time{} if c.IsSet("since") { // parse time, error out if something is wrong since, err := time.Parse("2006-01-02T15:04:05.999999999-07:00", c.String("since")) if err != nil { return errors.Wrapf(err, "could not parse time: %q", c.String("since")) } - opts.SinceTime = since + sinceTime = since } - opts.Tail = c.Uint64("tail") - config, err := getConfig(c) - if err != nil { - return errors.Wrapf(err, "could not get config") + opts := logOptions{ + details: c.Bool("details"), + follow: c.Bool("follow"), + sinceTime: sinceTime, + tail: c.Uint64("tail"), } - server, err := libkpod.New(config) - if err != nil { - return errors.Wrapf(err, "could not create container server") - } - defer server.Shutdown() - err = server.Update() + + ctr, err := runtime.LookupContainer(args[0]) if err != nil { - return errors.Wrapf(err, "could not update list of containers") + return err } + logs := make(chan string) go func() { - err = server.GetLogs(container, logs, opts) + err = getLogs(ctr, logs, opts) }() printLogs(logs) return err } +// getLogs returns the logs of a container from the log file +// log file is created when the container is started/ran +func getLogs(container *libpod.Container, logChan chan string, opts logOptions) error { + defer close(logChan) + + seekInfo := &tail.SeekInfo{Offset: 0, Whence: 0} + if opts.tail > 0 { + // seek to correct position in log files + seekInfo.Offset = int64(opts.tail) + seekInfo.Whence = 2 + } + + t, err := tail.TailFile(container.LogPath(), tail.Config{Follow: opts.follow, ReOpen: false, Location: seekInfo}) + for line := range t.Lines { + if since, err := logSinceTime(opts.sinceTime, line.Text); err != nil || !since { + continue + } + logMessage := line.Text[secondSpaceIndex(line.Text):] + logChan <- logMessage + } + return err +} + func printLogs(logs chan string) { for line := range logs { fmt.Println(line) } } + +// returns true if the time stamps of the logs are equal to or after the +// timestamp comparing to +func logSinceTime(sinceTime time.Time, logStr string) (bool, error) { + timestamp := strings.Split(logStr, " ")[0] + logTime, err := time.Parse("2006-01-02T15:04:05.999999999-07:00", timestamp) + if err != nil { + return false, err + } + return logTime.After(sinceTime) || logTime.Equal(sinceTime), nil +} + +// secondSpaceIndex returns the index of the second space in a string +// In a line of the logs, the first two tokens are a timestamp and stdout/stderr, +// followed by the message itself. This allows us to get the index of the message +// and avoid sending the other information back to the caller of GetLogs() +func secondSpaceIndex(line string) int { + index := strings.Index(line, " ") + if index == -1 { + return 0 + } + index = strings.Index(line[index:], " ") + if index == -1 { + return 0 + } + return index +} diff --git a/libkpod/logs.go b/libkpod/logs.go deleted file mode 100644 index 00b0f0167..000000000 --- a/libkpod/logs.go +++ /dev/null @@ -1,80 +0,0 @@ -package libkpod - -import ( - "path" - "strings" - "time" - - "github.com/hpcloud/tail" -) - -// LogOptions contains all of the options for displaying logs in kpod -type LogOptions struct { - Details bool - Follow bool - SinceTime time.Time - Tail uint64 -} - -// GetLogs gets each line of a log file and, if it matches the criteria in logOptions, sends it down logChan -func (c *ContainerServer) GetLogs(container string, logChan chan string, opts LogOptions) error { - defer close(logChan) - // Get the full ID of the container - ctr, err := c.LookupContainer(container) - if err != nil { - return err - } - - containerID := ctr.ID() - sandbox := ctr.Sandbox() - if sandbox == "" { - sandbox = containerID - } - // Read the log line by line and pass it into the pipe - logsFile := path.Join(c.config.LogDir, sandbox, containerID+".log") - - seekInfo := &tail.SeekInfo{Offset: 0, Whence: 0} - if opts.Tail > 0 { - // seek to correct position in logs files - seekInfo.Offset = int64(opts.Tail) - seekInfo.Whence = 2 - } - - t, err := tail.TailFile(logsFile, tail.Config{Follow: false, ReOpen: false, Location: seekInfo}) - for line := range t.Lines { - if since, err := logSinceTime(opts.SinceTime, line.Text); err != nil || !since { - continue - } - logMessage := line.Text[secondSpaceIndex(line.Text):] - if opts.Details { - // add additional information to line - } - logChan <- logMessage - } - return err -} - -func logSinceTime(sinceTime time.Time, logStr string) (bool, error) { - timestamp := strings.Split(logStr, " ")[0] - logTime, err := time.Parse("2006-01-02T15:04:05.999999999-07:00", timestamp) - if err != nil { - return false, err - } - return logTime.After(sinceTime) || logTime.Equal(sinceTime), nil -} - -// secondSpaceIndex returns the index of the second space in a string -// In a line of the logs, the first two tokens are a timestamp and stdout/stderr, -// followed by the message itself. This allows us to get the index of the message -// and avoid sending the other information back to the caller of GetLogs() -func secondSpaceIndex(line string) int { - index := strings.Index(line, " ") - if index == -1 { - return 0 - } - index = strings.Index(line[index:], " ") - if index == -1 { - return 0 - } - return index -} diff --git a/test/kpod_logs.bats b/test/kpod_logs.bats index 54b1d15c1..d5dc8622e 100644 --- a/test/kpod_logs.bats +++ b/test/kpod_logs.bats @@ -2,8 +2,6 @@ load helpers -IMAGE="alpine:latest" - function teardown() { cleanup_test } @@ -13,69 +11,42 @@ function setup() { } @test "display logs for container" { - skip "Test needs to be converted to kpod run" - start_crio - run crioctl pod run --config "$TESTDATA"/sandbox_config.json - echo "$output" - [ "$status" -eq 0 ] - pod_id="$output" - run crioctl ctr create --config "$TESTDATA"/container_config.json --pod "$pod_id" + run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} run -d $BB ls" echo "$output" [ "$status" -eq 0 ] ctr_id="$output" - run crioctl ctr start --id "$ctr_id" + run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} logs $ctr_id" echo "$output" [ "$status" -eq 0 ] - run bash -c ${KPOD_BINARY} $KPOD_OPTIONS logs "$ctr_id" + run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} rm $ctr_id" echo "$output" [ "$status" -eq 0 ] - cleanup_ctrs - cleanup_pods - stop_crio } @test "tail three lines of logs for container" { - skip "Test needs to be converted to kpod run" - start_crio - run crioctl pod run --config "$TESTDATA"/sandbox_config.json - echo "$output" - [ "$status" -eq 0 ] - pod_id="$output" - run crioctl ctr create --config "$TESTDATA"/container_config.json --pod "$pod_id" + run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} run -d $BB ls" echo "$output" [ "$status" -eq 0 ] ctr_id="$output" - run crioctl ctr start --id "$ctr_id" - echo "$output" - [ "$status" -eq 0 ] - run bash -c ${KPOD_BINARY} $KPOD_OPTIONS logs --tail 3 $ctr_id + run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} logs --tail 3 $ctr_id" echo "$output" lines=$(echo "$output" | wc -l) [ "$status" -eq 0 ] [[ $(wc -l < "$output" ) -le 3 ]] - cleanup_ctrs - cleanup_pods - stop_crio + run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} rm $ctr_id" + echo "$output" + [ "$status" -eq 0 ] } @test "display logs for container since a given time" { - skip "Test needs to be converted to kpod run" - start_crio - run crioctl pod run --config "$TESTDATA"/sandbox_config.json - echo "$output" - [ "$status" -eq 0 ] - pod_id="$output" - run crioctl ctr create --config "$TESTDATA"/container_config.json --pod "$pod_id" + run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} run -d $BB ls" echo "$output" [ "$status" -eq 0 ] ctr_id="$output" - run crioctl ctr start --id "$ctr_id" + run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} logs --since 2017-08-07T10:10:09.056611202-04:00 $ctr_id" echo "$output" [ "$status" -eq 0 ] - run bash -c ${KPOD_BINARY} $KPOD_OPTIONS logs --since 2017-08-07T10:10:09.056611202-04:00 $ctr_id + run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} rm $ctr_id" echo "$output" [ "$status" -eq 0 ] - cleanup_ctrs - cleanup_pods - stop_crio } |