Skip to content

Commit

Permalink
Merge pull request #10996 from cdoern/untilLog
Browse files Browse the repository at this point in the history
Implemented --until flag for Libpod's Container Logs
  • Loading branch information
openshift-merge-robot authored Jul 24, 2021
2 parents c44c298 + 0f708ef commit d956500
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 17 deletions.
14 changes: 14 additions & 0 deletions cmd/podman/containers/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type logsOptionsWrapper struct {
entities.ContainerLogsOptions

SinceRaw string

UntilRaw string
}

var (
Expand Down Expand Up @@ -101,6 +103,10 @@ func logsFlags(cmd *cobra.Command) {
flags.StringVar(&logsOptions.SinceRaw, sinceFlagName, "", "Show logs since TIMESTAMP")
_ = cmd.RegisterFlagCompletionFunc(sinceFlagName, completion.AutocompleteNone)

untilFlagName := "until"
flags.StringVar(&logsOptions.UntilRaw, untilFlagName, "", "Show logs until TIMESTAMP")
_ = cmd.RegisterFlagCompletionFunc(untilFlagName, completion.AutocompleteNone)

tailFlagName := "tail"
flags.Int64Var(&logsOptions.Tail, tailFlagName, -1, "Output the specified number of LINES at the end of the logs. Defaults to -1, which prints all lines")
_ = cmd.RegisterFlagCompletionFunc(tailFlagName, completion.AutocompleteNone)
Expand All @@ -120,6 +126,14 @@ func logs(_ *cobra.Command, args []string) error {
}
logsOptions.Since = since
}
if logsOptions.UntilRaw != "" {
// parse time, error out if something is wrong
until, err := util.ParseInputTime(logsOptions.UntilRaw)
if err != nil {
return errors.Wrapf(err, "error parsing --until %q", logsOptions.UntilRaw)
}
logsOptions.Until = until
}
logsOptions.StdoutWriter = os.Stdout
logsOptions.StderrWriter = os.Stderr
return registry.ContainerEngine().ContainerLogs(registry.GetContext(), args, logsOptions.ContainerLogsOptions)
Expand Down
29 changes: 29 additions & 0 deletions docs/source/markdown/podman-logs.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ strings (e.g. 10m, 1h30m) computed relative to the client machine's time. Suppor
time stamps include RFC3339Nano, RFC3339, 2006-01-02T15:04:05, 2006-01-02T15:04:05.999999999, 2006-01-02Z07:00,
and 2006-01-02.

#### **--until**=*TIMESTAMP*

Show logs until TIMESTAMP. The --until option can be Unix timestamps, date formatted timestamps, or Go duration
strings (e.g. 10m, 1h30m) computed relative to the client machine's time. Supported formats for date formatted
time stamps include RFC3339Nano, RFC3339, 2006-01-02T15:04:05, 2006-01-02T15:04:05.999999999, 2006-01-02Z07:00,
and 2006-01-02.


#### **--tail**=*LINES*

Output the specified number of LINES at the end of the logs. LINES must be an integer. Defaults to -1,
Expand Down Expand Up @@ -74,6 +82,17 @@ podman logs --tail 2 b3f2436bdb97
# Server initialized
```

To view all containers logs:
```
podman logs -t --since 0 myserver
1:M 07 Aug 14:10:09.055 # Server can't set maximum open files to 10032 because of OS error: Operation not permitted.
1:M 07 Aug 14:10:09.055 # Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'.
1:M 07 Aug 14:10:09.056 * Running mode=standalone, port=6379.
1:M 07 Aug 14:10:09.056 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1:M 07 Aug 14:10:09.056 # Server initialized
```

To view a containers logs since a certain time:
```
podman logs -t --since 2017-08-07T10:10:09.055837383-04:00 myserver
Expand All @@ -93,6 +112,16 @@ podman logs --since 10m myserver
# Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'.
```

To view a container's logs until 30 minutes ago:
```
podman logs --until 30m myserver
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.0.2.100. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.0.2.100. Set the 'ServerName' directive globally to suppress this message
[Tue Jul 20 13:18:14.223727 2021] [mpm_event:notice] [pid 1:tid 140021067187328] AH00489: Apache/2.4.48 (Unix) configured -- resuming normal operations
[Tue Jul 20 13:18:14.223819 2021] [core:notice] [pid 1:tid 140021067187328] AH00094: Command line: 'httpd -D FOREGROUND'
```

## SEE ALSO
podman(1), podman-run(1), podman-container-rm(1)

Expand Down
19 changes: 3 additions & 16 deletions libpod/container_log_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,6 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
}
}()

beforeTimeStamp := true
afterTimeStamp := false // needed for options.Since
tailQueue := []*logs.LogLine{} // needed for options.Tail
doTail := options.Tail > 0
for {
Expand Down Expand Up @@ -150,21 +148,10 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
return
}

if !afterTimeStamp {
entryTime := time.Unix(0, int64(entry.RealtimeTimestamp)*int64(time.Microsecond))
if entryTime.Before(options.Since) {
continue
}
afterTimeStamp = true
}
if beforeTimeStamp {
entryTime := time.Unix(0, int64(entry.RealtimeTimestamp)*int64(time.Microsecond))
if entryTime.Before(options.Until) || !options.Until.IsZero() {
continue
}
beforeTimeStamp = false
entryTime := time.Unix(0, int64(entry.RealtimeTimestamp)*int64(time.Microsecond))
if (entryTime.Before(options.Since) && !options.Since.IsZero()) || (entryTime.After(options.Until) && !options.Until.IsZero()) {
continue
}

// If we're reading an event and the container exited/died,
// then we're done and can return.
event, ok := entry.Fields["PODMAN_EVENT"]
Expand Down
2 changes: 2 additions & 0 deletions pkg/domain/entities/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ type ContainerLogsOptions struct {
Names bool
// Show logs since this timestamp.
Since time.Time
// Show logs until this timestamp.
Until time.Time
// Number of lines to display at the end of the output.
Tail int64
// Show timestamps in the logs.
Expand Down
1 change: 1 addition & 0 deletions pkg/domain/infra/abi/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,7 @@ func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []strin
Details: options.Details,
Follow: options.Follow,
Since: options.Since,
Until: options.Until,
Tail: options.Tail,
Timestamps: options.Timestamps,
UseName: options.Names,
Expand Down
3 changes: 2 additions & 1 deletion pkg/domain/infra/tunnel/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,10 +369,11 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG

func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIDs []string, opts entities.ContainerLogsOptions) error {
since := opts.Since.Format(time.RFC3339)
until := opts.Until.Format(time.RFC3339)
tail := strconv.FormatInt(opts.Tail, 10)
stdout := opts.StdoutWriter != nil
stderr := opts.StderrWriter != nil
options := new(containers.LogOptions).WithFollow(opts.Follow).WithSince(since).WithStderr(stderr)
options := new(containers.LogOptions).WithFollow(opts.Follow).WithSince(since).WithUntil(until).WithStderr(stderr)
options.WithStdout(stdout).WithTail(tail)

var err error
Expand Down
29 changes: 29 additions & 0 deletions test/e2e/logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"os/exec"
"strings"
"time"

. "github.com/containers/podman/v3/test/utils"
. "github.com/onsi/ginkgo"
Expand Down Expand Up @@ -135,6 +136,34 @@ var _ = Describe("Podman logs", func() {
Expect(len(results.OutputToStringArray())).To(Equal(3))
})

It("until duration 10m: "+log, func() {
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()

results := podmanTest.Podman([]string{"logs", "--until", "10m", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(len(results.OutputToStringArray())).To(Equal(0))
})

It("until time NOW: "+log, func() {

logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()

now := time.Now()
now = now.Add(time.Minute * 1)
nowS := now.Format(time.RFC3339)
results := podmanTest.Podman([]string{"logs", "--until", nowS, cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(len(results.OutputToStringArray())).To(Equal(3))
})

It("latest and container name should fail: "+log, func() {
results := podmanTest.Podman([]string{"logs", "-l", "foobar"})
results.WaitWithDefaultTimeout()
Expand Down
49 changes: 49 additions & 0 deletions test/system/035-logs.bats
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ load helpers
# test --since with Unix timestamps
run_podman logs --since 1000 $cid

# test --until with Unix timestamps
run_podman logs --until 1000 $cid

run_podman rm $cid
}

Expand Down Expand Up @@ -125,4 +128,50 @@ $s_after"
_log_test_since journald
}

function _log_test_until() {
local driver=$1

s_before="before_$(random_string)_${driver}"
s_after="after_$(random_string)_${driver}"

before=$(date --iso-8601=seconds)
sleep 5
run_podman run --log-driver=$driver -d --name test $IMAGE sh -c \
"echo $s_before; trap 'echo $s_after; exit' SIGTERM; while :; do sleep 1; done"

# sleep a second to make sure the date is after the first echo
sleep 1
run_podman stop test
# sleep for 20 seconds to get the proper after time
sleep 20

run_podman logs test
is "$output" \
"$s_before
$s_after"

run_podman logs --until $before test
is "$output" \
""

after=$(date --iso-8601=seconds)

run_podman logs --until $after test
is "$output" \
"$s_before
$s_after"
run_podman rm -f test
}

@test "podman logs - until k8s-file" {
_log_test_until k8s-file
}

@test "podman logs - until journald" {
# We can't use journald on RHEL as rootless: rhbz#1895105
skip_if_journald_unavailable

_log_test_until journald
}

# vim: filetype=sh

0 comments on commit d956500

Please sign in to comment.