1
2
3
4
5
6
7
8
9
10
11
12
13
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
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
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
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