github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/cmd/ctr/commands/tasks/metrics.go (about) 1 // +build linux 2 3 /* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package tasks 20 21 import ( 22 "encoding/json" 23 "errors" 24 "fmt" 25 "os" 26 "text/tabwriter" 27 28 wstats "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/stats" 29 v1 "github.com/containerd/cgroups/stats/v1" 30 v2 "github.com/containerd/cgroups/v2/stats" 31 "github.com/containerd/containerd/cmd/ctr/commands" 32 "github.com/containerd/typeurl" 33 "github.com/urfave/cli" 34 ) 35 36 func init() { 37 // metricsCommand is only added on Linux as github.com/containerd/cgroups 38 // does not compile on darwin or windows 39 Command.Subcommands = append(Command.Subcommands, metricsCommand) 40 } 41 42 const ( 43 formatFlag = "format" 44 formatTable = "table" 45 formatJSON = "json" 46 ) 47 48 var metricsCommand = cli.Command{ 49 Name: "metrics", 50 Usage: "get a single data point of metrics for a task with the built-in Linux runtime", 51 ArgsUsage: "CONTAINER", 52 Aliases: []string{"metric"}, 53 Flags: []cli.Flag{ 54 cli.StringFlag{ 55 Name: formatFlag, 56 Usage: `"table" or "json"`, 57 Value: formatTable, 58 }, 59 }, 60 Action: func(context *cli.Context) error { 61 client, ctx, cancel, err := commands.NewClient(context) 62 if err != nil { 63 return err 64 } 65 defer cancel() 66 container, err := client.LoadContainer(ctx, context.Args().First()) 67 if err != nil { 68 return err 69 } 70 task, err := container.Task(ctx, nil) 71 if err != nil { 72 return err 73 } 74 metric, err := task.Metrics(ctx) 75 if err != nil { 76 return err 77 } 78 anydata, err := typeurl.UnmarshalAny(metric.Data) 79 if err != nil { 80 return err 81 } 82 var ( 83 data *v1.Metrics 84 data2 *v2.Metrics 85 windowsStats *wstats.Statistics 86 ) 87 switch v := anydata.(type) { 88 case *v1.Metrics: 89 data = v 90 case *v2.Metrics: 91 data2 = v 92 case *wstats.Statistics: 93 windowsStats = v 94 default: 95 return errors.New("cannot convert metric data to cgroups.Metrics or windows.Statistics") 96 } 97 98 switch context.String(formatFlag) { 99 case formatTable: 100 w := tabwriter.NewWriter(os.Stdout, 1, 8, 4, ' ', 0) 101 fmt.Fprintf(w, "ID\tTIMESTAMP\t\n") 102 fmt.Fprintf(w, "%s\t%s\t\n\n", metric.ID, metric.Timestamp) 103 if data != nil { 104 printCgroupMetricsTable(w, data) 105 } else if data2 != nil { 106 printCgroup2MetricsTable(w, data2) 107 } else { 108 if windowsStats.GetLinux() != nil { 109 printCgroupMetricsTable(w, windowsStats.GetLinux()) 110 } else if windowsStats.GetWindows() != nil { 111 printWindowsContainerStatistics(w, windowsStats.GetWindows()) 112 } 113 // Print VM stats if its isolated 114 if windowsStats.VM != nil { 115 printWindowsVMStatistics(w, windowsStats.VM) 116 } 117 } 118 return w.Flush() 119 case formatJSON: 120 marshaledJSON, err := json.MarshalIndent(anydata, "", " ") 121 if err != nil { 122 return err 123 } 124 fmt.Println(string(marshaledJSON)) 125 return nil 126 default: 127 return errors.New("format must be table or json") 128 } 129 }, 130 } 131 132 func printCgroupMetricsTable(w *tabwriter.Writer, data *v1.Metrics) { 133 fmt.Fprintf(w, "METRIC\tVALUE\t\n") 134 if data.Memory != nil { 135 fmt.Fprintf(w, "memory.usage_in_bytes\t%d\t\n", data.Memory.Usage.Usage) 136 fmt.Fprintf(w, "memory.limit_in_bytes\t%d\t\n", data.Memory.Usage.Limit) 137 fmt.Fprintf(w, "memory.stat.cache\t%d\t\n", data.Memory.TotalCache) 138 } 139 if data.CPU != nil { 140 fmt.Fprintf(w, "cpuacct.usage\t%d\t\n", data.CPU.Usage.Total) 141 fmt.Fprintf(w, "cpuacct.usage_percpu\t%v\t\n", data.CPU.Usage.PerCPU) 142 } 143 if data.Pids != nil { 144 fmt.Fprintf(w, "pids.current\t%v\t\n", data.Pids.Current) 145 fmt.Fprintf(w, "pids.limit\t%v\t\n", data.Pids.Limit) 146 } 147 } 148 149 func printCgroup2MetricsTable(w *tabwriter.Writer, data *v2.Metrics) { 150 fmt.Fprintf(w, "METRIC\tVALUE\t\n") 151 if data.Pids != nil { 152 fmt.Fprintf(w, "pids.current\t%v\t\n", data.Pids.Current) 153 fmt.Fprintf(w, "pids.limit\t%v\t\n", data.Pids.Limit) 154 } 155 if data.CPU != nil { 156 fmt.Fprintf(w, "cpu.usage_usec\t%v\t\n", data.CPU.UsageUsec) 157 fmt.Fprintf(w, "cpu.user_usec\t%v\t\n", data.CPU.UserUsec) 158 fmt.Fprintf(w, "cpu.system_usec\t%v\t\n", data.CPU.SystemUsec) 159 fmt.Fprintf(w, "cpu.nr_periods\t%v\t\n", data.CPU.NrPeriods) 160 fmt.Fprintf(w, "cpu.nr_throttled\t%v\t\n", data.CPU.NrThrottled) 161 fmt.Fprintf(w, "cpu.throttled_usec\t%v\t\n", data.CPU.ThrottledUsec) 162 } 163 if data.Memory != nil { 164 fmt.Fprintf(w, "memory.usage\t%v\t\n", data.Memory.Usage) 165 fmt.Fprintf(w, "memory.usage_limit\t%v\t\n", data.Memory.UsageLimit) 166 fmt.Fprintf(w, "memory.swap_usage\t%v\t\n", data.Memory.SwapUsage) 167 fmt.Fprintf(w, "memory.swap_limit\t%v\t\n", data.Memory.SwapLimit) 168 } 169 } 170 171 func printWindowsContainerStatistics(w *tabwriter.Writer, stats *wstats.WindowsContainerStatistics) { 172 fmt.Fprintf(w, "METRIC\tVALUE\t\n") 173 fmt.Fprintf(w, "timestamp\t%s\t\n", stats.Timestamp) 174 fmt.Fprintf(w, "start_time\t%s\t\n", stats.ContainerStartTime) 175 fmt.Fprintf(w, "uptime_ns\t%d\t\n", stats.UptimeNS) 176 if stats.Processor != nil { 177 fmt.Fprintf(w, "cpu.total_runtime_ns\t%d\t\n", stats.Processor.TotalRuntimeNS) 178 fmt.Fprintf(w, "cpu.runtime_user_ns\t%d\t\n", stats.Processor.RuntimeUserNS) 179 fmt.Fprintf(w, "cpu.runtime_kernel_ns\t%d\t\n", stats.Processor.RuntimeKernelNS) 180 } 181 if stats.Memory != nil { 182 fmt.Fprintf(w, "memory.commit_bytes\t%d\t\n", stats.Memory.MemoryUsageCommitBytes) 183 fmt.Fprintf(w, "memory.commit_peak_bytes\t%d\t\n", stats.Memory.MemoryUsageCommitPeakBytes) 184 fmt.Fprintf(w, "memory.private_working_set_bytes\t%d\t\n", stats.Memory.MemoryUsagePrivateWorkingSetBytes) 185 } 186 if stats.Storage != nil { 187 fmt.Fprintf(w, "storage.read_count_normalized\t%d\t\n", stats.Storage.ReadCountNormalized) 188 fmt.Fprintf(w, "storage.read_size_bytes\t%d\t\n", stats.Storage.ReadSizeBytes) 189 fmt.Fprintf(w, "storage.write_count_normalized\t%d\t\n", stats.Storage.WriteCountNormalized) 190 fmt.Fprintf(w, "storage.write_size_bytes\t%d\t\n", stats.Storage.WriteSizeBytes) 191 } 192 } 193 194 func printWindowsVMStatistics(w *tabwriter.Writer, stats *wstats.VirtualMachineStatistics) { 195 fmt.Fprintf(w, "METRIC\tVALUE\t\n") 196 if stats.Processor != nil { 197 fmt.Fprintf(w, "vm.cpu.total_runtime_ns\t%d\t\n", stats.Processor.TotalRuntimeNS) 198 } 199 if stats.Memory != nil { 200 fmt.Fprintf(w, "vm.memory.working_set_bytes\t%d\t\n", stats.Memory.WorkingSetBytes) 201 fmt.Fprintf(w, "vm.memory.virtual_node_count\t%d\t\n", stats.Memory.VirtualNodeCount) 202 fmt.Fprintf(w, "vm.memory.available\t%d\t\n", stats.Memory.VmMemory.AvailableMemory) 203 fmt.Fprintf(w, "vm.memory.available_buffer\t%d\t\n", stats.Memory.VmMemory.AvailableMemoryBuffer) 204 fmt.Fprintf(w, "vm.memory.reserved\t%d\t\n", stats.Memory.VmMemory.ReservedMemory) 205 fmt.Fprintf(w, "vm.memory.assigned\t%d\t\n", stats.Memory.VmMemory.AssignedMemory) 206 fmt.Fprintf(w, "vm.memory.slp_active\t%t\t\n", stats.Memory.VmMemory.SlpActive) 207 fmt.Fprintf(w, "vm.memory.balancing_enabled\t%t\t\n", stats.Memory.VmMemory.BalancingEnabled) 208 fmt.Fprintf(w, "vm.memory.dm_operation_in_progress\t%t\t\n", stats.Memory.VmMemory.DmOperationInProgress) 209 } 210 }