Merge pull request #10996 from cdoern/untilLog

Implemented --until flag for Libpod's Container Logs
This commit is contained in:
OpenShift Merge Robot
2021-07-24 05:56:18 -04:00
committed by GitHub
8 changed files with 129 additions and 17 deletions

View File

@ -19,6 +19,8 @@ type logsOptionsWrapper struct {
entities.ContainerLogsOptions
SinceRaw string
UntilRaw string
}
var (
@ -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)
@ -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)

View File

@ -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,
@ -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
@ -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)

View File

@ -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 {
@ -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
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 beforeTimeStamp {
entryTime := time.Unix(0, int64(entry.RealtimeTimestamp)*int64(time.Microsecond))
if entryTime.Before(options.Until) || !options.Until.IsZero() {
continue
}
beforeTimeStamp = false
}
// If we're reading an event and the container exited/died,
// then we're done and can return.
event, ok := entry.Fields["PODMAN_EVENT"]

View File

@ -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.

View File

@ -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,

View File

@ -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

View File

@ -5,6 +5,7 @@ import (
"os"
"os/exec"
"strings"
"time"
. "github.com/containers/podman/v3/test/utils"
. "github.com/onsi/ginkgo"
@ -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()

View File

@ -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
}
@ -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