github.com/oam-dev/kubevela@v1.9.11/references/cli/top/model/log.go (about) 1 /* 2 Copyright 2022 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 model 18 19 import ( 20 "context" 21 "fmt" 22 "regexp" 23 "text/template" 24 "time" 25 26 "github.com/fatih/color" 27 "github.com/pkg/errors" 28 "github.com/wercker/stern/stern" 29 "k8s.io/apimachinery/pkg/labels" 30 "k8s.io/client-go/kubernetes" 31 "k8s.io/client-go/rest" 32 33 "github.com/oam-dev/kubevela/pkg/multicluster" 34 ) 35 36 // PrintLogOfPod print the log during 48h of aimed pod 37 func PrintLogOfPod(ctx context.Context, config *rest.Config, cluster, namespace, podName, containerName string) (chan string, error) { 38 if cluster != "local" { 39 ctx = multicluster.ContextWithClusterName(ctx, cluster) 40 } 41 pod, err := regexp.Compile(podName + ".*") 42 if err != nil { 43 return nil, fmt.Errorf("fail to compile '%s' for logs query", podName+".*") 44 } 45 container := regexp.MustCompile(".*") 46 if containerName != "" { 47 container = regexp.MustCompile(containerName + ".*") 48 } 49 selector := labels.NewSelector() 50 51 logC := make(chan string, 1024) 52 53 go podLog(ctx, config, namespace, pod, container, selector, logC) 54 55 return logC, nil 56 } 57 58 func podLog(ctx context.Context, config *rest.Config, namespace string, pod, container *regexp.Regexp, selector labels.Selector, logC chan string) { 59 clientSet, err := kubernetes.NewForConfig(config) 60 if err != nil { 61 logC <- err.Error() 62 return 63 } 64 65 added, removed, err := stern.Watch(ctx, 66 clientSet.CoreV1().Pods(namespace), 67 pod, 68 container, 69 nil, 70 []stern.ContainerState{stern.RUNNING, stern.TERMINATED}, 71 selector, 72 ) 73 if err != nil { 74 logC <- err.Error() 75 return 76 } 77 78 tails := make(map[string]*stern.Tail) 79 80 var t string 81 if color.NoColor { 82 t = "{{.ContainerName}} {{.Message}}" 83 } else { 84 t = "{{color .ContainerColor .ContainerName}} {{.Message}}" 85 } 86 87 funs := map[string]interface{}{ 88 "color": func(color color.Color, text string) string { 89 return color.SprintFunc()(text) 90 }, 91 } 92 template, err := template.New("log").Funcs(funs).Parse(t) 93 if err != nil { 94 if err != nil { 95 logC <- errors.Wrap(err, "unable to parse template").Error() 96 return 97 } 98 } 99 100 go func() { 101 for p := range added { 102 id := p.GetID() 103 if tails[id] != nil { 104 continue 105 } 106 // 48h 107 dur, _ := time.ParseDuration("48h") 108 tail := stern.NewTail(p.Namespace, p.Pod, p.Container, template, &stern.TailOptions{ 109 Timestamps: true, 110 SinceSeconds: int64(dur.Seconds()), 111 Exclude: nil, 112 Include: nil, 113 Namespace: false, 114 TailLines: nil, // default for all logs 115 }) 116 tails[id] = tail 117 118 tail.Start(ctx, clientSet.CoreV1().Pods(p.Namespace), logC) 119 } 120 }() 121 122 go func() { 123 for p := range removed { 124 id := p.GetID() 125 if tails[id] == nil { 126 continue 127 } 128 tails[id].Close() 129 delete(tails, id) 130 } 131 }() 132 133 <-ctx.Done() 134 }