mirror of
https://github.com/containers/podman.git
synced 2025-08-06 03:19:52 +08:00
Merge pull request #10996 from cdoern/untilLog
Implemented --until flag for Libpod's Container Logs
This commit is contained in:
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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"]
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user