mirror of https://github.com/k3s-io/k3s
Allow a selector when retrieving logs
parent
23389b2dc6
commit
acb032fc72
|
@ -40,6 +40,9 @@ var (
|
||||||
# Return snapshot logs from pod nginx with only one container
|
# Return snapshot logs from pod nginx with only one container
|
||||||
kubectl logs nginx
|
kubectl logs nginx
|
||||||
|
|
||||||
|
# Return snapshot logs for the pods defined by label app=nginx
|
||||||
|
kubectl logs -lapp=nginx
|
||||||
|
|
||||||
# Return snapshot of previous terminated ruby container logs from pod web-1
|
# Return snapshot of previous terminated ruby container logs from pod web-1
|
||||||
kubectl logs -p -c ruby web-1
|
kubectl logs -p -c ruby web-1
|
||||||
|
|
||||||
|
@ -51,6 +54,8 @@ var (
|
||||||
|
|
||||||
# Show all logs from pod nginx written in the last hour
|
# Show all logs from pod nginx written in the last hour
|
||||||
kubectl logs --since=1h nginx`)
|
kubectl logs --since=1h nginx`)
|
||||||
|
|
||||||
|
selectorTail int64 = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -91,8 +96,7 @@ func NewCmdLogs(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||||
if err := o.Validate(); err != nil {
|
if err := o.Validate(); err != nil {
|
||||||
cmdutil.CheckErr(cmdutil.UsageError(cmd, err.Error()))
|
cmdutil.CheckErr(cmdutil.UsageError(cmd, err.Error()))
|
||||||
}
|
}
|
||||||
_, err := o.RunLogs()
|
cmdutil.CheckErr(o.RunLogs())
|
||||||
cmdutil.CheckErr(err)
|
|
||||||
},
|
},
|
||||||
Aliases: []string{"log"},
|
Aliases: []string{"log"},
|
||||||
}
|
}
|
||||||
|
@ -100,7 +104,7 @@ func NewCmdLogs(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||||
cmd.Flags().Bool("timestamps", false, "Include timestamps on each line in the log output")
|
cmd.Flags().Bool("timestamps", false, "Include timestamps on each line in the log output")
|
||||||
cmd.Flags().Int64("limit-bytes", 0, "Maximum bytes of logs to return. Defaults to no limit.")
|
cmd.Flags().Int64("limit-bytes", 0, "Maximum bytes of logs to return. Defaults to no limit.")
|
||||||
cmd.Flags().BoolP("previous", "p", false, "If true, print the logs for the previous instance of the container in a pod if it exists.")
|
cmd.Flags().BoolP("previous", "p", false, "If true, print the logs for the previous instance of the container in a pod if it exists.")
|
||||||
cmd.Flags().Int64("tail", -1, "Lines of recent log file to display. Defaults to -1, showing all log lines.")
|
cmd.Flags().Int64("tail", -1, "Lines of recent log file to display. Defaults to -1 with no selector, showing all log lines otherwise 10, if a selector is provided.")
|
||||||
cmd.Flags().String("since-time", "", "Only return logs after a specific date (RFC3339). Defaults to all logs. Only one of since-time / since may be used.")
|
cmd.Flags().String("since-time", "", "Only return logs after a specific date (RFC3339). Defaults to all logs. Only one of since-time / since may be used.")
|
||||||
cmd.Flags().Duration("since", 0, "Only return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs. Only one of since-time / since may be used.")
|
cmd.Flags().Duration("since", 0, "Only return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs. Only one of since-time / since may be used.")
|
||||||
cmd.Flags().StringP("container", "c", "", "Print the logs of this container")
|
cmd.Flags().StringP("container", "c", "", "Print the logs of this container")
|
||||||
|
@ -108,16 +112,23 @@ func NewCmdLogs(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||||
cmd.Flags().Bool("interactive", false, "If true, prompt the user for input when required.")
|
cmd.Flags().Bool("interactive", false, "If true, prompt the user for input when required.")
|
||||||
cmd.Flags().MarkDeprecated("interactive", "This flag is no longer respected and there is no replacement.")
|
cmd.Flags().MarkDeprecated("interactive", "This flag is no longer respected and there is no replacement.")
|
||||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||||
|
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on.")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||||
containerName := cmdutil.GetFlagString(cmd, "container")
|
containerName := cmdutil.GetFlagString(cmd, "container")
|
||||||
|
selector := cmdutil.GetFlagString(cmd, "selector")
|
||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 0:
|
case 0:
|
||||||
return cmdutil.UsageError(cmd, logsUsageStr)
|
if len(selector) == 0 {
|
||||||
|
return cmdutil.UsageError(cmd, logsUsageStr)
|
||||||
|
}
|
||||||
case 1:
|
case 1:
|
||||||
o.ResourceArg = args[0]
|
o.ResourceArg = args[0]
|
||||||
|
if len(selector) != 0 {
|
||||||
|
return cmdutil.UsageError(cmd, "only a selector (-l) or a POD name is allowed")
|
||||||
|
}
|
||||||
case 2:
|
case 2:
|
||||||
if cmd.Flag("container").Changed {
|
if cmd.Flag("container").Changed {
|
||||||
return cmdutil.UsageError(cmd, "only one of -c or an inline [CONTAINER] arg is allowed")
|
return cmdutil.UsageError(cmd, "only one of -c or an inline [CONTAINER] arg is allowed")
|
||||||
|
@ -162,18 +173,35 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Comm
|
||||||
o.ClientMapper = resource.ClientMapperFunc(f.ClientForMapping)
|
o.ClientMapper = resource.ClientMapperFunc(f.ClientForMapping)
|
||||||
o.Out = out
|
o.Out = out
|
||||||
|
|
||||||
|
if len(selector) != 0 {
|
||||||
|
if logOptions.Follow {
|
||||||
|
return cmdutil.UsageError(cmd, "only one of follow (-f) or selector (-l) is allowed")
|
||||||
|
}
|
||||||
|
if len(logOptions.Container) != 0 {
|
||||||
|
return cmdutil.UsageError(cmd, "a container cannot be specified when using a selector (-l)")
|
||||||
|
}
|
||||||
|
if logOptions.TailLines == nil {
|
||||||
|
logOptions.TailLines = &selectorTail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mapper, typer := f.Object()
|
mapper, typer := f.Object()
|
||||||
decoder := f.Decoder(true)
|
decoder := f.Decoder(true)
|
||||||
if o.Object == nil {
|
if o.Object == nil {
|
||||||
infos, err := resource.NewBuilder(mapper, typer, o.ClientMapper, decoder).
|
builder := resource.NewBuilder(mapper, typer, o.ClientMapper, decoder).
|
||||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||||
ResourceNames("pods", o.ResourceArg).
|
SingleResourceType()
|
||||||
SingleResourceType().
|
if o.ResourceArg != "" {
|
||||||
Do().Infos()
|
builder.ResourceNames("pods", o.ResourceArg)
|
||||||
|
}
|
||||||
|
if selector != "" {
|
||||||
|
builder.ResourceTypes("pods").SelectorParam(selector)
|
||||||
|
}
|
||||||
|
infos, err := builder.Do().Infos()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(infos) != 1 {
|
if selector == "" && len(infos) != 1 {
|
||||||
return errors.New("expected a resource")
|
return errors.New("expected a resource")
|
||||||
}
|
}
|
||||||
o.Object = infos[0].Object
|
o.Object = infos[0].Object
|
||||||
|
@ -183,9 +211,6 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Comm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o LogsOptions) Validate() error {
|
func (o LogsOptions) Validate() error {
|
||||||
if len(o.ResourceArg) == 0 {
|
|
||||||
return errors.New("a pod must be specified")
|
|
||||||
}
|
|
||||||
logsOptions, ok := o.Options.(*api.PodLogOptions)
|
logsOptions, ok := o.Options.(*api.PodLogOptions)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("unexpected logs options object")
|
return errors.New("unexpected logs options object")
|
||||||
|
@ -198,17 +223,32 @@ func (o LogsOptions) Validate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunLogs retrieves a pod log
|
// RunLogs retrieves a pod log
|
||||||
func (o LogsOptions) RunLogs() (int64, error) {
|
func (o LogsOptions) RunLogs() error {
|
||||||
req, err := o.LogsForObject(o.Object, o.Options)
|
switch t := o.Object.(type) {
|
||||||
|
case *api.PodList:
|
||||||
|
for _, p := range t.Items {
|
||||||
|
if err := o.getLogs(&p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return o.getLogs(o.Object)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o LogsOptions) getLogs(obj runtime.Object) error {
|
||||||
|
req, err := o.LogsForObject(obj, o.Options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
readCloser, err := req.Stream()
|
readCloser, err := req.Stream()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
defer readCloser.Close()
|
defer readCloser.Close()
|
||||||
|
|
||||||
return io.Copy(o.Out, readCloser)
|
_, err = io.Copy(o.Out, readCloser)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue