summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/podman/pods/logs.go140
1 files changed, 140 insertions, 0 deletions
diff --git a/cmd/podman/pods/logs.go b/cmd/podman/pods/logs.go
new file mode 100644
index 000000000..fe5205669
--- /dev/null
+++ b/cmd/podman/pods/logs.go
@@ -0,0 +1,140 @@
+package pods
+
+import (
+ "os"
+
+ "github.com/containers/common/pkg/completion"
+ "github.com/containers/podman/v3/cmd/podman/common"
+ "github.com/containers/podman/v3/cmd/podman/registry"
+ "github.com/containers/podman/v3/cmd/podman/validate"
+ "github.com/containers/podman/v3/libpod/define"
+ "github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/util"
+ "github.com/pkg/errors"
+ "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.`
+ logsPodCommand = &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 togather
+ 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`,
+ }
+
+ containerLogsCommand = &cobra.Command{
+ Use: logsPodCommand.Use,
+ Short: logsPodCommand.Short,
+ Long: logsPodCommand.Long,
+ Args: logsPodCommand.Args,
+ RunE: logsPodCommand.RunE,
+ ValidArgsFunction: logsPodCommand.ValidArgsFunction,
+ 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`,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: logsPodCommand,
+ })
+ logsFlags(logsPodCommand)
+ validate.AddLatestFlag(logsPodCommand, &logsPodOptions.Latest)
+
+ // container logs
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: containerLogsCommand,
+ Parent: podCmd,
+ })
+ logsFlags(containerLogsCommand)
+ validate.AddLatestFlag(containerLogsCommand, &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.Timestamps, "timestamps", "t", false, "Output the timestamps 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 errors.Wrapf(err, "error parsing --since %q", logsPodOptions.SinceRaw)
+ }
+ 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 errors.Wrapf(err, "error parsing --until %q", logsPodOptions.UntilRaw)
+ }
+ logsPodOptions.Until = until
+ }
+
+ // Remote can only process one container at a time
+ if registry.IsRemote() && logsPodOptions.ContainerName == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "-c or --container cannot be empty")
+ }
+
+ logsPodOptions.StdoutWriter = os.Stdout
+ logsPodOptions.StderrWriter = os.Stderr
+ return registry.ContainerEngine().PodLogs(registry.GetContext(), args[0], logsPodOptions.PodLogsOptions)
+}