package main import ( "flag" "fmt" "io" "log" "os" "path/filepath" "sync" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" corev1 "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/homedir" ) var ( home = homedir.HomeDir() kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file") namespace = flag.String("namespace", "apps", "namespace for the pods") stream = flag.Bool("stream", false, "if set, livestream logs") ) func main() { flag.Parse() config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) if err != nil { panic(err) } clientset, err := kubernetes.NewForConfig(config) if err != nil { panic(err) } podsClient := clientset.CoreV1().Pods(*namespace) pods, err := podsClient.List(metav1.ListOptions{}) if err != nil { panic(err) } var wg sync.WaitGroup wg.Add(len(pods.Items)) for _, pod := range pods.Items { if len(pod.Spec.Containers) != 1 { wg.Add(len(pod.Spec.Containers) - 1) } for _, ctr := range pod.Spec.Containers { go dumpLogs(podsClient, &wg, pod.Name, ctr.Name) } } wg.Wait() } func dumpLogs(podsClient corev1.PodExpansion, wg *sync.WaitGroup, podName, ctrName string) { defer wg.Done() w := lineSplittingWriter{ writer: prefixWriter(fmt.Sprintf("%25s | ", ctrName), os.Stdout), } req := podsClient.GetLogs(podName, &v1.PodLogOptions{ Container: ctrName, Follow: *stream, }) st, err := req.Stream() if err != nil { log.Printf("can't get logs for pod %s container %s: %v", podName, ctrName, err) return } defer st.Close() io.Copy(w, st) }