github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/kubernetes/logger/formatter.go (about) 1 /* 2 Copyright 2021 The Skaffold 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 logger 18 19 import ( 20 "fmt" 21 "io" 22 "sync" 23 24 v1 "k8s.io/api/core/v1" 25 26 eventV2 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/event/v2" 27 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/log" 28 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/output" 29 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" 30 tagutil "github.com/GoogleContainerTools/skaffold/pkg/skaffold/tag/util" 31 ) 32 33 type Formatter func(pod v1.Pod, containerStatus v1.ContainerStatus, isMuted func() bool) log.Formatter 34 35 type kubernetesLogFormatter struct { 36 colorPicker output.ColorPicker 37 prefix string 38 JSONParseConfig latest.JSONParseConfig 39 40 pod *v1.Pod 41 container v1.ContainerStatus 42 43 lock sync.Mutex 44 isMuted func() bool 45 } 46 47 func newKubernetesLogFormatter(config Config, colorPicker output.ColorPicker, isMuted func() bool, pod *v1.Pod, container v1.ContainerStatus) *kubernetesLogFormatter { 48 return &kubernetesLogFormatter{ 49 colorPicker: colorPicker, 50 prefix: prefix(config, pod, container), 51 JSONParseConfig: config.JSONParseConfig(), 52 pod: pod, 53 container: container, 54 isMuted: isMuted, 55 } 56 } 57 58 func (k *kubernetesLogFormatter) Name() string { return k.prefix } 59 60 func (k *kubernetesLogFormatter) PrintLine(out io.Writer, line string) { 61 if k.isMuted() { 62 return 63 } 64 formattedPrefix := k.prefix 65 if output.IsColorable(out) { 66 formattedPrefix = k.color().Sprintf("%s", k.prefix) 67 // if our original prefix was empty, don't prepend a space to the line, 68 // but keep the color prefix we just added. 69 if k.prefix != "" { 70 formattedPrefix = fmt.Sprintf("%s ", formattedPrefix) 71 } 72 } 73 74 line = log.ParseJSON(k.JSONParseConfig, line) 75 formattedLine := fmt.Sprintf("%s%s", formattedPrefix, line) 76 eventV2.ApplicationLog(k.pod.Name, k.container.Name, formattedPrefix, line, formattedLine) 77 78 k.lock.Lock() 79 defer k.lock.Unlock() 80 fmt.Fprint(out, formattedLine) 81 } 82 83 func (k *kubernetesLogFormatter) color() output.Color { 84 for _, container := range k.pod.Spec.Containers { 85 if c := k.colorPicker.Pick(container.Image); c != output.None { 86 return c 87 } 88 } 89 90 // If no mapping is found, don't add any color formatting 91 return output.None 92 } 93 94 func prefix(config Config, pod *v1.Pod, container v1.ContainerStatus) string { 95 var c latest.Pipeline 96 var present bool 97 for _, container := range pod.Spec.Containers { 98 if c, present = config.PipelineForImage(tagutil.StripTag(container.Image, false)); present { 99 break 100 } 101 } 102 if !present { 103 c = config.DefaultPipeline() 104 } 105 switch c.Deploy.Logs.Prefix { 106 case "auto": 107 if pod.Name != container.Name { 108 return podAndContainerPrefix(pod, container) 109 } 110 return autoPrefix(pod, container) 111 case "container": 112 return containerPrefix(container) 113 case "podAndContainer": 114 return podAndContainerPrefix(pod, container) 115 case "none": 116 return "" 117 default: 118 panic("unsupported prefix: " + c.Deploy.Logs.Prefix) 119 } 120 } 121 122 func autoPrefix(pod *v1.Pod, container v1.ContainerStatus) string { 123 if pod.Name != container.Name { 124 return fmt.Sprintf("[%s %s]", pod.Name, container.Name) 125 } 126 return fmt.Sprintf("[%s]", container.Name) 127 } 128 129 func containerPrefix(container v1.ContainerStatus) string { 130 return fmt.Sprintf("[%s]", container.Name) 131 } 132 133 func podAndContainerPrefix(pod *v1.Pod, container v1.ContainerStatus) string { 134 return fmt.Sprintf("[%s %s]", pod.Name, container.Name) 135 }