1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
package pods
import (
"errors"
"fmt"
"os"
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/validate"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/util"
"github.com/spf13/cobra"
)
// logsOptionsWrapper wraps entities.LogsOptions and prevents leaking
// CLI-only fields into the API types.
type logsOptionsWrapper struct {
entities.PodLogsOptions
SinceRaw string
UntilRaw string
}
var (
logsPodOptions logsOptionsWrapper
logsPodDescription = `Displays logs for pod with one or more containers.`
podLogsCommand = &cobra.Command{
Use: "logs [options] POD",
Short: "Fetch logs for pod with one or more containers",
Long: logsPodDescription,
// We dont want users to invoke latest and pod together
Args: func(cmd *cobra.Command, args []string) error {
switch {
case registry.IsRemote() && logsPodOptions.Latest:
return errors.New(cmd.Name() + " does not support 'latest' when run remotely")
case len(args) > 1:
return errors.New("requires exactly 1 arg")
case logsPodOptions.Latest && len(args) > 0:
return errors.New("--latest and pods cannot be used together")
case !logsPodOptions.Latest && len(args) < 1:
return errors.New("specify at least one pod name or ID to log")
}
return nil
},
RunE: logs,
ValidArgsFunction: common.AutocompletePods,
Example: `podman pod logs podID
podman pod logs -c ctrname podName
podman pod logs --tail 2 mywebserver
podman pod logs --follow=true --since 10m podID
podman pod logs mywebserver`,
}
)
func init() {
// pod logs
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: podLogsCommand,
Parent: podCmd,
})
logsFlags(podLogsCommand)
validate.AddLatestFlag(podLogsCommand, &logsPodOptions.Latest)
}
func logsFlags(cmd *cobra.Command) {
flags := cmd.Flags()
flags.BoolVar(&logsPodOptions.Details, "details", false, "Show extra details provided to the logs")
flags.BoolVarP(&logsPodOptions.Follow, "follow", "f", false, "Follow log output.")
containerNameFlag := "container"
flags.StringVarP(&logsPodOptions.ContainerName, containerNameFlag, "c", "", "Filter logs by container name or id which belongs to pod")
_ = cmd.RegisterFlagCompletionFunc(containerNameFlag, common.AutocompleteContainers)
sinceFlagName := "since"
flags.StringVar(&logsPodOptions.SinceRaw, sinceFlagName, "", "Show logs since TIMESTAMP")
_ = cmd.RegisterFlagCompletionFunc(sinceFlagName, completion.AutocompleteNone)
untilFlagName := "until"
flags.StringVar(&logsPodOptions.UntilRaw, untilFlagName, "", "Show logs until TIMESTAMP")
_ = cmd.RegisterFlagCompletionFunc(untilFlagName, completion.AutocompleteNone)
tailFlagName := "tail"
flags.Int64Var(&logsPodOptions.Tail, tailFlagName, -1, "Output the specified number of LINES at the end of the logs.")
_ = cmd.RegisterFlagCompletionFunc(tailFlagName, completion.AutocompleteNone)
flags.BoolVarP(&logsPodOptions.Names, "names", "n", false, "Output container names instead of container IDs in the log")
flags.BoolVarP(&logsPodOptions.Timestamps, "timestamps", "t", false, "Output the timestamps in the log")
flags.BoolVarP(&logsPodOptions.Colors, "color", "", false, "Output the containers within a pod with different colors in the log")
flags.SetInterspersed(false)
_ = flags.MarkHidden("details")
}
func logs(_ *cobra.Command, args []string) error {
if logsPodOptions.SinceRaw != "" {
// parse time, error out if something is wrong
since, err := util.ParseInputTime(logsPodOptions.SinceRaw, true)
if err != nil {
return fmt.Errorf("parsing --since %q: %w", logsPodOptions.SinceRaw, err)
}
logsPodOptions.Since = since
}
if logsPodOptions.UntilRaw != "" {
// parse time, error out if something is wrong
until, err := util.ParseInputTime(logsPodOptions.UntilRaw, false)
if err != nil {
return fmt.Errorf("parsing --until %q: %w", logsPodOptions.UntilRaw, err)
}
logsPodOptions.Until = until
}
// Remote can only process one container at a time
if registry.IsRemote() && logsPodOptions.ContainerName == "" {
return fmt.Errorf("-c or --container cannot be empty: %w", define.ErrInvalidArg)
}
logsPodOptions.StdoutWriter = os.Stdout
logsPodOptions.StderrWriter = os.Stderr
podName := ""
if len(args) > 0 {
podName = args[0]
}
return registry.ContainerEngine().PodLogs(registry.GetContext(), podName, logsPodOptions.PodLogsOptions)
}
|