aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/kpod/logs.go105
-rw-r--r--libkpod/logs.go80
-rw-r--r--test/kpod_logs.bats51
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
}