mirror of
https://github.com/kemko/nomad.git
synced 2026-01-07 10:55:42 +03:00
Showing detailed resource usage stats in alloc-stats
This commit is contained in:
@@ -205,7 +205,7 @@ func (c *NodeStatusCommand) Run(args []string) int {
|
||||
}
|
||||
|
||||
if hostStats, err = client.Nodes().Stats(node.ID, nil); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("error fetching node resource utilization stats: %#v", err))
|
||||
c.Ui.Error(fmt.Sprintf("error fetching node resource utilization stats: %v", err))
|
||||
}
|
||||
|
||||
// Format the output
|
||||
@@ -401,12 +401,14 @@ func getActualResources(hostStats *api.HostStats, node *api.Node) ([]string, err
|
||||
}
|
||||
var resources []string
|
||||
|
||||
// Calculate cpu usage
|
||||
usedCPUPercent := 0.0
|
||||
for _, cpu := range hostStats.CPU {
|
||||
usedCPUPercent += (cpu.User + cpu.System)
|
||||
}
|
||||
usedCPUTicks := (usedCPUPercent / 100) * float64(node.Resources.CPU)
|
||||
|
||||
// calculate disk usage
|
||||
storageDevice := node.Attributes["unique.storage.volume"]
|
||||
var diskUsed, diskSize uint64
|
||||
for _, disk := range hostStats.DiskStats {
|
||||
|
||||
168
command/stats.go
168
command/stats.go
@@ -1,168 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
|
||||
"github.com/hashicorp/nomad/api"
|
||||
)
|
||||
|
||||
type StatsCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (f *StatsCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: nomad stats [options] <alloc-id>
|
||||
|
||||
Displays statistics related to resource usage of tasks in an allocation. Use
|
||||
the -task flag to query statistics of an individual task running in an
|
||||
allocation.
|
||||
|
||||
General Options:
|
||||
|
||||
` + generalOptionsUsage() + `
|
||||
|
||||
Node Stats Options:
|
||||
|
||||
-task
|
||||
Display statistics for a specific task in an allocation.
|
||||
`
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (f *StatsCommand) Synopsis() string {
|
||||
return "Dispalys resource usage stats of an allocation or a task running on a nomad client"
|
||||
}
|
||||
|
||||
func (f *StatsCommand) Run(args []string) int {
|
||||
var verbose bool
|
||||
var task string
|
||||
flags := f.Meta.FlagSet("stats", FlagSetClient)
|
||||
flags.BoolVar(&verbose, "verbose", false, "")
|
||||
flags.StringVar(&task, "task", "", "")
|
||||
flags.Usage = func() { f.Ui.Output(f.Help()) }
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
args = flags.Args()
|
||||
if len(args) < 1 {
|
||||
f.Ui.Error("allocation id is a required parameter")
|
||||
return 1
|
||||
}
|
||||
client, err := f.Meta.Client()
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error initializing client: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
var allocID string
|
||||
allocID = strings.TrimSpace(args[0])
|
||||
|
||||
// Truncate the id unless full length is requested
|
||||
length := shortId
|
||||
if verbose {
|
||||
length = fullId
|
||||
}
|
||||
|
||||
// Query the allocation info
|
||||
if len(allocID) == 1 {
|
||||
f.Ui.Error(fmt.Sprintf("Alloc ID must contain at least two characters."))
|
||||
return 1
|
||||
}
|
||||
if len(allocID)%2 == 1 {
|
||||
// Identifiers must be of even length, so we strip off the last byte
|
||||
// to provide a consistent user experience.
|
||||
allocID = allocID[:len(allocID)-1]
|
||||
}
|
||||
|
||||
allocs, _, err := client.Allocations().PrefixList(allocID)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error querying allocation: %v", err))
|
||||
return 1
|
||||
}
|
||||
if len(allocs) == 0 {
|
||||
f.Ui.Error(fmt.Sprintf("No allocation(s) with prefix or id %q found", allocID))
|
||||
return 1
|
||||
}
|
||||
if len(allocs) > 1 {
|
||||
// Format the allocs
|
||||
out := make([]string, len(allocs)+1)
|
||||
out[0] = "ID|Eval ID|Job ID|Task Group|Desired Status|Client Status"
|
||||
for i, alloc := range allocs {
|
||||
out[i+1] = fmt.Sprintf("%s|%s|%s|%s|%s|%s",
|
||||
limit(alloc.ID, length),
|
||||
limit(alloc.EvalID, length),
|
||||
alloc.JobID,
|
||||
alloc.TaskGroup,
|
||||
alloc.DesiredStatus,
|
||||
alloc.ClientStatus,
|
||||
)
|
||||
}
|
||||
f.Ui.Output(fmt.Sprintf("Prefix matched multiple allocations\n\n%s", formatList(out)))
|
||||
return 0
|
||||
}
|
||||
// Prefix lookup matched a single allocation
|
||||
alloc, _, err := client.Allocations().Info(allocs[0].ID, nil)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error querying allocation: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
stats, err := client.Allocations().Stats(alloc, nil)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("unable to get stats: %v", err))
|
||||
return 1
|
||||
}
|
||||
if task == "" {
|
||||
f.printAllocResourceUsage(alloc, stats)
|
||||
} else {
|
||||
f.printTaskResourceUsage(task, stats)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (f *StatsCommand) printTaskResourceUsage(task string, resourceUsage map[string]*api.TaskResourceUsage) {
|
||||
tu, ok := resourceUsage[task]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
memoryStats := tu.ResourceUsage.MemoryStats
|
||||
cpuStats := tu.ResourceUsage.CpuStats
|
||||
f.Ui.Output(fmt.Sprintf("===> Task: %q", task))
|
||||
f.Ui.Output("Memory Stats")
|
||||
out := make([]string, 2)
|
||||
out[0] = "RSS|Cache|Swap|Max Usage|Kernel Usage|KernelMaxUsage"
|
||||
out[1] = fmt.Sprintf("%v|%v|%v|%v|%v|%v",
|
||||
humanize.Bytes(memoryStats.RSS),
|
||||
humanize.Bytes(memoryStats.Cache),
|
||||
humanize.Bytes(memoryStats.Swap),
|
||||
humanize.Bytes(memoryStats.MaxUsage),
|
||||
humanize.Bytes(memoryStats.KernelUsage),
|
||||
humanize.Bytes(memoryStats.KernelMaxUsage),
|
||||
)
|
||||
f.Ui.Output(formatList(out))
|
||||
|
||||
f.Ui.Output("")
|
||||
|
||||
f.Ui.Output("CPU Stats")
|
||||
out = make([]string, 2)
|
||||
out[0] = "Percent|Throttled Periods|Throttled Time"
|
||||
percent := strconv.FormatFloat(cpuStats.Percent, 'f', 2, 64)
|
||||
out[1] = fmt.Sprintf("%v|%v|%v", percent,
|
||||
cpuStats.ThrottledPeriods, cpuStats.ThrottledTime)
|
||||
f.Ui.Output(formatList(out))
|
||||
}
|
||||
|
||||
func (f *StatsCommand) printAllocResourceUsage(alloc *api.Allocation, resourceUsage map[string]*api.TaskResourceUsage) {
|
||||
f.Ui.Output(fmt.Sprintf("Resource Usage of Tasks running in Allocation %q", alloc.ID))
|
||||
for task, _ := range alloc.TaskStates {
|
||||
f.printTaskResourceUsage(task, resourceUsage)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user