...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/cmd/logs.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/cmd

     1  // Copyright 2021 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  
    16  package cmd
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"strings"
    22  
    23  	"github.com/hasura/go-graphql-client"
    24  	"github.com/pkg/errors"
    25  	"github.com/spf13/cobra"
    26  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/client-go/kubernetes"
    28  
    29  	cm "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common"
    30  )
    31  
    32  type logsOptions struct {
    33  	tail int64
    34  	node string
    35  }
    36  
    37  type Component string
    38  
    39  const (
    40  	Manager   Component = "MANAGER"
    41  	Daemon    Component = "DAEMON"
    42  	Dashboard Component = "DASHBOARD"
    43  	DnsServer Component = "DNSSERVER"
    44  )
    45  
    46  func NewLogsCmd() (*cobra.Command, error) {
    47  	o := &logsOptions{}
    48  
    49  	logsCmd := &cobra.Command{
    50  		Use:   `logs [-t LINE]`,
    51  		Short: `Print logs of controller-manager, chaos-daemon and chaos-dashboard`,
    52  		Long: `Print logs of controller-manager, chaos-daemon and chaos-dashboard, to provide debug information.
    53  
    54  Examples:
    55    # Default print all log of all chaosmesh components
    56    chaosctl logs
    57  
    58    # Print 100 log lines for chaosmesh components in node NODENAME
    59    chaosctl logs -t 100 -n NODENAME`,
    60  		RunE: func(cmd *cobra.Command, args []string) error {
    61  			return o.Run(args)
    62  		},
    63  		SilenceErrors:     true,
    64  		SilenceUsage:      true,
    65  		ValidArgsFunction: noCompletions,
    66  	}
    67  
    68  	logsCmd.Flags().Int64VarP(&o.tail, "tail", "t", -1, "number of lines of recent log")
    69  	logsCmd.Flags().StringVarP(&o.node, "node", "n", "", "the node of target pods")
    70  	err := logsCmd.RegisterFlagCompletionFunc("node", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
    71  		clientset, err := cm.InitClientSet()
    72  		if err != nil {
    73  			return nil, cobra.ShellCompDirectiveDefault
    74  		}
    75  		return listNodes(toComplete, clientset.KubeCli)
    76  	})
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	return logsCmd, nil
    81  }
    82  
    83  // Run logs
    84  func (o *logsOptions) Run(args []string) error {
    85  	client, cancel, err := cm.CreateClient(context.TODO(), managerNamespace, managerSvc)
    86  	if err != nil {
    87  		return errors.Wrap(err, "failed to initialize clientset")
    88  	}
    89  	defer cancel()
    90  
    91  	componentsNeeded := []Component{Manager, Daemon, Dashboard, DnsServer}
    92  	for _, name := range componentsNeeded {
    93  		var query struct {
    94  			Namespace []struct {
    95  				Component []struct {
    96  					Name string
    97  					Spec struct {
    98  						NodeName string
    99  					}
   100  					Logs string
   101  				} `graphql:"component(component: $component)"`
   102  			} `graphql:"namespace(ns: $namespace)"`
   103  		}
   104  
   105  		variables := map[string]interface{}{
   106  			"namespace": graphql.String(managerNamespace),
   107  			"component": name,
   108  		}
   109  
   110  		err := client.QueryClient.Query(context.TODO(), &query, variables)
   111  		if err != nil {
   112  			return err
   113  		}
   114  
   115  		if len(query.Namespace) == 0 {
   116  			return fmt.Errorf("no namespace %s found", managerNamespace)
   117  		}
   118  
   119  		for _, component := range query.Namespace[0].Component {
   120  			if o.node != "" && component.Spec.NodeName != o.node {
   121  				// ignore component on this node
   122  				continue
   123  			}
   124  
   125  			logLines := strings.Split(component.Logs, "\n")
   126  			if o.tail > 0 {
   127  				if len(logLines) > int(o.tail) {
   128  					logLines = logLines[len(logLines)-int(o.tail)-1:]
   129  				}
   130  			}
   131  
   132  			cm.PrettyPrint(fmt.Sprintf("[%s]", component.Name), 0, cm.Cyan)
   133  			cm.PrettyPrint(strings.Join(logLines, "\n"), 1, cm.NoColor)
   134  		}
   135  	}
   136  	return nil
   137  }
   138  
   139  func listNodes(toComplete string, c *kubernetes.Clientset) ([]string, cobra.ShellCompDirective) {
   140  	// FIXME: get context from parameter
   141  	nodes, err := c.CoreV1().Nodes().List(context.TODO(), v1.ListOptions{})
   142  	if err != nil {
   143  		return nil, cobra.ShellCompDirectiveDefault
   144  	}
   145  	var ret []string
   146  	for _, ns := range nodes.Items {
   147  		if strings.HasPrefix(ns.Name, toComplete) {
   148  			ret = append(ret, ns.Name)
   149  		}
   150  	}
   151  	return ret, cobra.ShellCompDirectiveNoFileComp
   152  }
   153