From f673a269ad6aa2fa0a22bd41a815a20bf04905f0 Mon Sep 17 00:00:00 2001 From: Lorenzo Fontana Date: Sat, 29 Dec 2018 17:06:50 +0100 Subject: [PATCH] feat(cmd/log): log follow Signed-off-by: Lorenzo Fontana --- pkg/cmd/log.go | 38 ++++++++++++++++++++++---------------- pkg/logs/logs.go | 21 ++++----------------- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/pkg/cmd/log.go b/pkg/cmd/log.go index f964c9a9..e4b121f9 100644 --- a/pkg/cmd/log.go +++ b/pkg/cmd/log.go @@ -1,13 +1,11 @@ package cmd import ( - "context" "fmt" "github.com/fntlnz/kubectl-trace/pkg/factory" "github.com/fntlnz/kubectl-trace/pkg/logs" "github.com/fntlnz/kubectl-trace/pkg/meta" - "github.com/fntlnz/kubectl-trace/pkg/signals" "github.com/fntlnz/kubectl-trace/pkg/tracejob" "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/types" @@ -18,17 +16,21 @@ import ( ) var ( - logShort = `` // Wrap with i18n.T() - logLong = logShort + ` + logShort = `Print the logs for a specific trace execution` // Wrap with i18n.T() + logLong = logShort + logExamples = ` + # Logs from a trace using its name + %[1]s trace logs kubectl-trace-d5842929-0b78-11e9-a9fa-40a3cc632df1 -...` + # Logs from a trace using its id + %[1]s trace log 5594d7e1-0b78-11e9-b7f1-40a3cc632df1 - logExamples = ` - # ... - %[1]s trace log -h + # Follow logs + %[1]s trace logs kubectl-trace-d5842929-0b78-11e9-a9fa-40a3cc632df1 -f - # ... - %[1]s trace log` + # Add timestamp to logs + %[1]s trace logs kubectl-trace-d5842929-0b78-11e9-a9fa-40a3cc632df1 --timestamp +` ) // LogOptions ... @@ -38,12 +40,16 @@ type LogOptions struct { traceName *string namespace string clientConfig *rest.Config + follow bool + timestamps bool } // NewLogOptions provides an instance of LogOptions with default values. func NewLogOptions(streams genericclioptions.IOStreams) *LogOptions { return &LogOptions{ - IOStreams: streams, + IOStreams: streams, + follow: false, + timestamps: false, } } @@ -52,8 +58,9 @@ func NewLogCommand(factory factory.Factory, streams genericclioptions.IOStreams) o := NewLogOptions(streams) cmd := &cobra.Command{ - Use: "log (TRACE_ID | TRACE_NAME)", + Use: "logs (TRACE_ID | TRACE_NAME) [-f]", DisableFlagsInUseLine: true, + Aliases: []string{"log"}, Short: logShort, Long: logLong, // Wrap with templates.LongDesc() Example: fmt.Sprintf(logExamples, "kubectl"), // Wrap with templates.Examples() @@ -73,6 +80,8 @@ func NewLogCommand(factory factory.Factory, streams genericclioptions.IOStreams) }, } + cmd.Flags().BoolVarP(&o.follow, "follow", "f", o.follow, "Specify if the logs should be streamed") + cmd.Flags().BoolVar(&o.timestamps, "timestamps", o.timestamps, "Include timestamps on each line in the log output") return cmd } @@ -136,10 +145,7 @@ func (o *LogOptions) Run() error { job := jobs[0] - ctx := context.Background() - ctx = signals.WithStandardSignals(ctx) nl := logs.NewLogs(client, o.IOStreams) - nl.WithContext(ctx) - nl.Run(job.ID, job.Namespace) + nl.Run(job.ID, job.Namespace, o.follow, o.timestamps) return nil } diff --git a/pkg/logs/logs.go b/pkg/logs/logs.go index ba2989aa..c1dcdf61 100644 --- a/pkg/logs/logs.go +++ b/pkg/logs/logs.go @@ -12,22 +12,18 @@ import ( "fmt" "io" - "context" - "k8s.io/cli-runtime/pkg/genericclioptions" ) type Logs struct { genericclioptions.IOStreams coreV1Client tcorev1.CoreV1Interface - ctx context.Context } func NewLogs(client tcorev1.CoreV1Interface, streams genericclioptions.IOStreams) *Logs { return &Logs{ coreV1Client: client, IOStreams: streams, - ctx: context.TODO(), } } @@ -37,11 +33,7 @@ const ( invalidPodContainersSizeError = "unexpected number of containers in trace job pod" ) -func (l *Logs) WithContext(c context.Context) { - l.ctx = c -} - -func (l *Logs) Run(jobID types.UID, namespace string) error { +func (l *Logs) Run(jobID types.UID, namespace string, follow bool, timestamps bool) error { pl, err := l.coreV1Client.Pods(namespace).List(metav1.ListOptions{ LabelSelector: fmt.Sprintf("%s=%s", meta.TraceIDLabelKey, jobID), }) @@ -65,20 +57,16 @@ func (l *Logs) Run(jobID types.UID, namespace string) error { containerName := pod.Spec.Containers[0].Name - // TODO(fntlnz): let the user choose to follow or not logOptions := &corev1.PodLogOptions{ Container: containerName, - Follow: true, + Follow: follow, Previous: false, - Timestamps: false, + Timestamps: timestamps, } logsRequest := l.coreV1Client.Pods(namespace).GetLogs(pod.Name, logOptions) - go consumeRequest(logsRequest, l.IOStreams.Out) - <-l.ctx.Done() - - return nil + return consumeRequest(logsRequest, l.IOStreams.Out) } func consumeRequest(request *rest.Request, out io.Writer) error { @@ -91,4 +79,3 @@ func consumeRequest(request *rest.Request, out io.Writer) error { _, err = io.Copy(out, readCloser) return err } -