You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2022/08/30 15:24:36 UTC

[camel-k] 01/01: feat(cli): Add tail and tail-lines flags to the log command

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 <nf...@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 {