...
1 package cmd
2
3 import (
4 "bytes"
5 "fmt"
6 "time"
7
8 pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
9 "github.com/linkerd/linkerd2/pkg/k8s"
10 "github.com/spf13/cobra"
11 )
12
13 type metricsOptions struct {
14 namespace string
15 pod string
16 obfuscate bool
17 }
18
19 func newMetricsOptions() *metricsOptions {
20 return &metricsOptions{
21 pod: "",
22 obfuscate: false,
23 }
24 }
25
26 func newCmdMetrics() *cobra.Command {
27 options := newMetricsOptions()
28
29 cmd := &cobra.Command{
30 Use: "proxy-metrics [flags] (RESOURCE)",
31 Short: "Fetch metrics directly from Linkerd proxies",
32 Long: `Fetch metrics directly from Linkerd proxies.
33
34 This command initiates a port-forward to a given pod or set of pods, and
35 queries the /metrics endpoint on the Linkerd proxies.
36
37 The RESOURCE argument specifies the target resource to query metrics for:
38 (TYPE/NAME)
39
40 Examples:
41 * cronjob/my-cronjob
42 * deploy/my-deploy
43 * ds/my-daemonset
44 * job/my-job
45 * po/mypod1
46 * rc/my-replication-controller
47 * sts/my-statefulset
48
49 Valid resource types include:
50 * cronjobs
51 * daemonsets
52 * deployments
53 * jobs
54 * pods
55 * replicasets
56 * replicationcontrollers
57 * statefulsets`,
58 Example: ` # Get metrics from pod-foo-bar in the default namespace.
59 linkerd diagnostics proxy-metrics po/pod-foo-bar
60
61 # Get metrics from the web deployment in the emojivoto namespace.
62 linkerd diagnostics proxy-metrics -n emojivoto deploy/web
63
64 # Get metrics from the linkerd-destination pod in the linkerd namespace.
65 linkerd diagnostics proxy-metrics -n linkerd $(
66 kubectl --namespace linkerd get pod \
67 --selector linkerd.io/control-plane-component=destination \
68 --output name
69 )`,
70 Args: cobra.ExactArgs(1),
71 RunE: func(cmd *cobra.Command, args []string) error {
72 if options.namespace == "" {
73 options.namespace = pkgcmd.GetDefaultNamespace(kubeconfigPath, kubeContext)
74 }
75 k8sAPI, err := k8s.NewAPI(kubeconfigPath, kubeContext, impersonate, impersonateGroup, 0)
76 if err != nil {
77 return err
78 }
79
80 pods, err := k8s.GetPodsFor(cmd.Context(), k8sAPI, options.namespace, args[0])
81 if err != nil {
82 return err
83 }
84
85 results := getMetrics(k8sAPI, pods, k8s.ProxyAdminPortName, 30*time.Second, verbose)
86
87 var buf bytes.Buffer
88 for i, result := range results {
89 content := fmt.Sprintf("#\n# POD %s (%d of %d)\n#\n", result.pod, i+1, len(results))
90 switch {
91 case result.err != nil:
92 content += fmt.Sprintf("# ERROR: %s\n", result.err)
93 case options.obfuscate:
94 obfuscatedMetrics, err := obfuscateMetrics(result.metrics)
95 if err != nil {
96 content += fmt.Sprintf("# ERROR %s\n", err)
97 } else {
98 content += string(obfuscatedMetrics)
99 }
100 default:
101 content += string(result.metrics)
102 }
103
104 buf.WriteString(content)
105 }
106 fmt.Printf("%s", buf.String())
107
108 return nil
109 },
110 }
111
112 cmd.PersistentFlags().StringVarP(&options.namespace, "namespace", "n", options.namespace, "Namespace of resource")
113 cmd.PersistentFlags().BoolVar(&options.obfuscate, "obfuscate", options.obfuscate, "Obfuscate sensitive information")
114
115 pkgcmd.ConfigureNamespaceFlagCompletion(cmd, []string{"namespace"},
116 kubeconfigPath, impersonate, impersonateGroup, kubeContext)
117
118 return cmd
119 }
120
View as plain text