This is an automated email from the ASF dual-hosted git repository. nfilotto pushed a commit to branch 3004/log-tail in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit 80bd2d7f664b765d1bb337820d804a6652c0410b Author: Nicolas Filotto <nfilo...@talend.com> AuthorDate: Tue Aug 30 17:24:10 2022 +0200 feat(cli): Add tail and tail-lines flags to the log command --- e2e/namespace/install/cli/log_test.go | 8 ++++++++ pkg/cmd/debug.go | 2 +- pkg/cmd/log.go | 13 ++++++++++++- pkg/cmd/run.go | 2 +- pkg/util/kubernetes/log/annotation_scraper.go | 6 ++++-- pkg/util/kubernetes/log/pod_scraper.go | 5 ++++- pkg/util/kubernetes/log/util.go | 8 ++++---- 7 files changed, 34 insertions(+), 10 deletions(-) diff --git a/e2e/namespace/install/cli/log_test.go b/e2e/namespace/install/cli/log_test.go index 5b696ac68..5b25479e7 100644 --- a/e2e/namespace/install/cli/log_test.go +++ b/e2e/namespace/install/cli/log_test.go @@ -48,6 +48,14 @@ func TestKamelCLILog(t *testing.T) { logsCLI := GetOutputStringAsync(Kamel("log", "yaml", "-n", ns)) Eventually(logsCLI).Should(ContainSubstring("Monitoring pod " + podName)) Eventually(logsCLI).Should(ContainSubstring(logs)) + + logsCLI := GetOutputStringAsync(Kamel("log", "yaml", "-n", ns, "-f")) + Eventually(logsCLI).Should(ContainSubstring("Monitoring pod " + podName)) + Eventually(logsCLI).Should(ContainSubstring(logs)) + + logsCLI := GetOutputStringAsync(Kamel("log", "yaml", "-n", ns, "-l", 5)) + Eventually(logsCLI).Should(ContainSubstring("Monitoring pod " + podName)) + Eventually(logsCLI).Should(ContainSubstring(logs)) }) }) } diff --git a/pkg/cmd/debug.go b/pkg/cmd/debug.go index 2913bacae..7d5a1de8f 100644 --- a/pkg/cmd/debug.go +++ b/pkg/cmd/debug.go @@ -123,7 +123,7 @@ func (o *debugCmdOptions) run(cmd *cobra.Command, args []string) error { selector := fmt.Sprintf("camel.apache.org/debug=true,camel.apache.org/integration=%s", name) go func() { - err = k8slog.PrintUsingSelector(o.Context, cmd, cmdClient, o.Namespace, "integration", selector, cmd.OutOrStdout()) + err = k8slog.PrintUsingSelector(o.Context, cmd, cmdClient, o.Namespace, "integration", selector, nil, cmd.OutOrStdout()) if err != nil { fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) } diff --git a/pkg/cmd/log.go b/pkg/cmd/log.go index 9a9efcbf9..b668091fa 100644 --- a/pkg/cmd/log.go +++ b/pkg/cmd/log.go @@ -46,6 +46,9 @@ func newCmdLog(rootCmdOptions *RootCmdOptions) (*cobra.Command, *logCmdOptions) RunE: options.run, } + cmd.Flags().BoolP("tail", "f", false, "To show the end of the logs") + cmd.Flags().Int64P("tail-lines", "l", 10, "The number of lines from the end of the logs to show") + // completion support configureKnownCompletions(&cmd) @@ -54,6 +57,8 @@ func newCmdLog(rootCmdOptions *RootCmdOptions) (*cobra.Command, *logCmdOptions) type logCmdOptions struct { *RootCmdOptions + Tail bool `mapstructure:"tail"` + TailLines int64 `mapstructure:"tail-lines"` } func (o *logCmdOptions) validate(_ *cobra.Command, args []string) error { @@ -129,7 +134,13 @@ func (o *logCmdOptions) run(cmd *cobra.Command, args []string) error { // Found the running integration so step over to scraping its pod log // fmt.Fprintln(cmd.OutOrStdout(), "Integration '"+integrationID+"' is now running. Showing log ...") - if err := k8slog.Print(o.Context, cmd, c, &integration, cmd.OutOrStdout()); err != nil { + var tailLines *int64 + if cmd.Flags().Lookup("tail-lines").Changed { + tailLines = &o.TailLines + } else if o.Tail { + tailLines = &[]int64{10}[0] + } + if err := k8slog.Print(o.Context, cmd, c, &integration, tailLines, cmd.OutOrStdout()); err != nil { return false, err } diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go index b1e23aa6e..ac4174ff4 100644 --- a/pkg/cmd/run.go +++ b/pkg/cmd/run.go @@ -378,7 +378,7 @@ func (o *runCmdOptions) run(cmd *cobra.Command, args []string) error { } } if o.Logs || o.Dev { - err = k8slog.Print(o.Context, cmd, c, integration, cmd.OutOrStdout()) + err = k8slog.Print(o.Context, cmd, c, integration, nil, cmd.OutOrStdout()) if err != nil { return err } diff --git a/pkg/util/kubernetes/log/annotation_scraper.go b/pkg/util/kubernetes/log/annotation_scraper.go index c3cde929d..4c687ad60 100644 --- a/pkg/util/kubernetes/log/annotation_scraper.go +++ b/pkg/util/kubernetes/log/annotation_scraper.go @@ -44,16 +44,18 @@ type SelectorScraper struct { podScrapers sync.Map counter uint64 L klog.Logger + tailLines *int64 } // NewSelectorScraper creates a new SelectorScraper. -func NewSelectorScraper(client kubernetes.Interface, namespace string, defaultContainerName string, labelSelector string) *SelectorScraper { +func NewSelectorScraper(client kubernetes.Interface, namespace string, defaultContainerName string, labelSelector string, tailLines *int64) *SelectorScraper { return &SelectorScraper{ client: client, namespace: namespace, defaultContainerName: defaultContainerName, labelSelector: labelSelector, L: klog.WithName("scraper").WithName("label").WithValues("selector", labelSelector), + tailLines: tailLines, } } @@ -130,7 +132,7 @@ func (s *SelectorScraper) synchronize(ctx context.Context, out *bufio.Writer) er } func (s *SelectorScraper) addPodScraper(ctx context.Context, podName string, out *bufio.Writer) { - podScraper := NewPodScraper(s.client, s.namespace, podName, s.defaultContainerName) + podScraper := NewPodScraper(s.client, s.namespace, podName, s.defaultContainerName, s.tailLines) podCtx, podCancel := context.WithCancel(ctx) id := atomic.AddUint64(&s.counter, 1) prefix := "[" + strconv.FormatUint(id, 10) + "] " diff --git a/pkg/util/kubernetes/log/pod_scraper.go b/pkg/util/kubernetes/log/pod_scraper.go index 494e0501f..a9fb24a89 100644 --- a/pkg/util/kubernetes/log/pod_scraper.go +++ b/pkg/util/kubernetes/log/pod_scraper.go @@ -48,16 +48,18 @@ type PodScraper struct { defaultContainerName string client kubernetes.Interface L klog.Logger + tailLines *int64 } // NewPodScraper creates a new pod scraper. -func NewPodScraper(c kubernetes.Interface, namespace string, podName string, defaultContainerName string) *PodScraper { +func NewPodScraper(c kubernetes.Interface, namespace string, podName string, defaultContainerName string, tailLines *int64) *PodScraper { return &PodScraper{ namespace: namespace, podName: podName, defaultContainerName: defaultContainerName, client: c, L: klog.WithName("scraper").WithName("pod").WithValues("name", podName), + tailLines: tailLines, } } @@ -83,6 +85,7 @@ func (s *PodScraper) doScrape(ctx context.Context, out *bufio.Writer, clientClos } logOptions := corev1.PodLogOptions{ Follow: true, + TailLines: s.tailLines, Container: containerName, } byteReader, err := s.client.CoreV1().Pods(s.namespace).GetLogs(s.podName, &logOptions).Stream(ctx) diff --git a/pkg/util/kubernetes/log/util.go b/pkg/util/kubernetes/log/util.go index 26bd2c158..8dbc08530 100644 --- a/pkg/util/kubernetes/log/util.go +++ b/pkg/util/kubernetes/log/util.go @@ -30,13 +30,13 @@ import ( ) // Print prints integrations logs to the stdout. -func Print(ctx context.Context, cmd *cobra.Command, client kubernetes.Interface, integration *v1.Integration, out io.Writer) error { - return PrintUsingSelector(ctx, cmd, client, integration.Namespace, integration.Name, v1.IntegrationLabel+"="+integration.Name, out) +func Print(ctx context.Context, cmd *cobra.Command, client kubernetes.Interface, integration *v1.Integration, tailLines *int64, out io.Writer) error { + return PrintUsingSelector(ctx, cmd, client, integration.Namespace, integration.Name, v1.IntegrationLabel+"="+integration.Name, tailLines, out) } // PrintUsingSelector prints pod logs using a selector. -func PrintUsingSelector(ctx context.Context, cmd *cobra.Command, client kubernetes.Interface, namespace, defaultContainerName, selector string, out io.Writer) error { - scraper := NewSelectorScraper(client, namespace, defaultContainerName, selector) +func PrintUsingSelector(ctx context.Context, cmd *cobra.Command, client kubernetes.Interface, namespace, defaultContainerName, selector string, tailLines *int64, out io.Writer) error { + scraper := NewSelectorScraper(client, namespace, defaultContainerName, selector, tailLines) reader := scraper.Start(ctx) if _, err := io.Copy(out, ioutil.NopCloser(reader)); err != nil {