github.com/oam-dev/kubevela@v1.9.11/references/cli/logs.go (about) 1 /* 2 Copyright 2021 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cli 18 19 import ( 20 "context" 21 "fmt" 22 "regexp" 23 "strings" 24 25 "github.com/fatih/color" 26 "github.com/spf13/cobra" 27 28 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 29 "github.com/oam-dev/kubevela/apis/types" 30 "github.com/oam-dev/kubevela/pkg/multicluster" 31 "github.com/oam-dev/kubevela/pkg/utils" 32 "github.com/oam-dev/kubevela/pkg/utils/common" 33 "github.com/oam-dev/kubevela/pkg/utils/util" 34 querytypes "github.com/oam-dev/kubevela/pkg/velaql/providers/query/types" 35 "github.com/oam-dev/kubevela/references/appfile" 36 ) 37 38 var re = regexp.MustCompile(`"((?:[^"\\]|\\.)*)"`) 39 40 // NewLogsCommand creates `logs` command to tail logs of application 41 func NewLogsCommand(c common.Args, order string, ioStreams util.IOStreams) *cobra.Command { 42 largs := &Args{Args: c} 43 cmd := &cobra.Command{ 44 Use: "logs", 45 Short: "Tail logs for application.", 46 Long: "Tail logs for vela application.", 47 Args: cobra.ExactArgs(1), 48 RunE: func(cmd *cobra.Command, args []string) error { 49 var err error 50 largs.Namespace, err = GetFlagNamespaceOrEnv(cmd, c) 51 if err != nil { 52 return err 53 } 54 largs.Name = args[0] 55 ctx := context.Background() 56 app, err := appfile.LoadApplication(largs.Namespace, args[0], c) 57 if err != nil { 58 return err 59 } 60 largs.App = app 61 if err := largs.Run(ctx, ioStreams); err != nil { 62 return err 63 } 64 return nil 65 }, 66 Annotations: map[string]string{ 67 types.TagCommandOrder: order, 68 types.TagCommandType: types.TypeApp, 69 }, 70 } 71 72 cmd.Flags().StringVarP(&largs.Output, "output", "o", "default", "output format for logs, support: [default, raw, json]") 73 cmd.Flags().StringVarP(&largs.ComponentName, "component", "c", "", "filter the pod by the component name") 74 cmd.Flags().StringVarP(&largs.ClusterName, "cluster", "", "", "filter the pod by the cluster name") 75 cmd.Flags().StringVarP(&largs.PodName, "pod", "p", "", "specify the pod name") 76 cmd.Flags().StringVarP(&largs.ContainerName, "container", "", "", "specify the container name") 77 addNamespaceAndEnvArg(cmd) 78 return cmd 79 } 80 81 // Args creates arguments for `logs` command 82 type Args struct { 83 Output string 84 Args common.Args 85 Name string 86 CtxName string 87 Namespace string 88 ContainerName string 89 PodName string 90 ClusterName string 91 ComponentName string 92 StepName string 93 App *v1beta1.Application 94 } 95 96 func (l *Args) printPodLogs(ctx context.Context, ioStreams util.IOStreams, selectPod *querytypes.PodBase, filters []string) error { 97 config, err := l.Args.GetConfig() 98 if err != nil { 99 return err 100 } 101 logC := make(chan string, 1024) 102 103 var t string 104 switch l.Output { 105 case "default": 106 if color.NoColor { 107 t = "{{.ContainerName}} {{.Message}}" 108 } else { 109 t = "{{color .ContainerColor .ContainerName}} {{.Message}}" 110 } 111 case "raw": 112 t = "{{.Message}}" 113 case "json": 114 t = "{{json .}}\n" 115 } 116 go func() { 117 for { 118 select { 119 case str := <-logC: 120 show := true 121 for _, filter := range filters { 122 if !strings.Contains(str, filter) { 123 show = false 124 break 125 } 126 } 127 if show { 128 match := re.FindStringSubmatch(str) 129 if len(match) > 1 { 130 str = strings.ReplaceAll(match[1], "\\n", "\n") 131 } 132 ioStreams.Infonln(str) 133 } 134 case <-ctx.Done(): 135 return 136 } 137 } 138 }() 139 140 err = utils.GetPodsLogs(ctx, config, l.ContainerName, []*querytypes.PodBase{selectPod}, t, logC, nil) 141 if err != nil { 142 return err 143 } 144 145 return nil 146 } 147 148 // Run refer to the implementation at https://github.com/oam-dev/stern/blob/master/stern/main.go 149 func (l *Args) Run(ctx context.Context, ioStreams util.IOStreams) error { 150 pods, err := GetApplicationPods(ctx, l.App.Name, l.App.Namespace, l.Args, Filter{ 151 Component: l.ComponentName, 152 Cluster: l.ClusterName, 153 }) 154 if err != nil { 155 return err 156 } 157 var selectPod *querytypes.PodBase 158 if l.PodName != "" { 159 for i, pod := range pods { 160 if pod.Metadata.Name == l.PodName { 161 selectPod = &pods[i] 162 break 163 } 164 } 165 if selectPod == nil { 166 fmt.Println("The Pod you specified does not exist, please select it from the list.") 167 } 168 } 169 if selectPod == nil { 170 selectPod, err = AskToChooseOnePod(pods) 171 if err != nil { 172 return err 173 } 174 } 175 176 if selectPod == nil { 177 return nil 178 } 179 180 if selectPod.Cluster != "" { 181 ctx = multicluster.ContextWithClusterName(ctx, selectPod.Cluster) 182 } 183 return l.printPodLogs(ctx, ioStreams, selectPod, nil) 184 }