131 lines
4.5 KiB
Go
131 lines
4.5 KiB
Go
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)
|
|
}
|