mirror of https://github.com/divan/expvarmon.git
175 lines
3.5 KiB
Go
175 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/pyk/byten"
|
|
)
|
|
|
|
// VarName represents variable name.
|
|
//
|
|
// It has dot-separated format, like "memstats.Alloc",
|
|
// but can be used in different forms, hence it's own type.
|
|
//
|
|
// It also can have optional "kind:" modifier, like "mem:" or "duration:"
|
|
type VarName string
|
|
|
|
// VarKind specifies special kinds of values, affects formatting.
|
|
type VarKind int
|
|
|
|
// VarValue represents arbitrary value for variable.
|
|
type VarValue interface{}
|
|
|
|
const (
|
|
KindDefault VarKind = iota
|
|
KindMemory
|
|
KindDuration
|
|
KindString
|
|
)
|
|
|
|
// ToSlice converts "dot-separated" notation into the "slice of strings".
|
|
//
|
|
// "dot-separated" notation is a human-readable format, passed via args.
|
|
// "slice of strings" is used by Jason library.
|
|
//
|
|
// Example: "memstats.Alloc" => []string{"memstats", "Alloc"}
|
|
// Example: "mem:memstats.Alloc" => []string{"memstats", "Alloc"}
|
|
func (v VarName) ToSlice() []string {
|
|
start := strings.IndexRune(string(v), ':') + 1
|
|
slice := DottedFieldsToSliceEscaped(string(v)[start:])
|
|
return slice
|
|
}
|
|
|
|
// Short returns short name, which is typically is the last word in the long names.
|
|
func (v VarName) Short() string {
|
|
if v == "" {
|
|
return ""
|
|
}
|
|
|
|
slice := v.ToSlice()
|
|
return slice[len(slice)-1]
|
|
}
|
|
|
|
// Long returns long name, without kind: modifier.
|
|
func (v VarName) Long() string {
|
|
if v == "" {
|
|
return ""
|
|
}
|
|
|
|
start := strings.IndexRune(string(v), ':') + 1
|
|
return string(v)[start:]
|
|
}
|
|
|
|
// Kind returns kind of variable, based on it's name modifiers ("mem:")
|
|
func (v VarName) Kind() VarKind {
|
|
start := strings.IndexRune(string(v), ':')
|
|
if start == -1 {
|
|
return KindDefault
|
|
}
|
|
|
|
switch string(v)[:start] {
|
|
case "mem":
|
|
return KindMemory
|
|
case "duration":
|
|
return KindDuration
|
|
case "str":
|
|
return KindString
|
|
}
|
|
return KindDefault
|
|
}
|
|
|
|
// Format returns human-readable var value representation.
|
|
func Format(v VarValue, kind VarKind) string {
|
|
switch kind {
|
|
case KindMemory:
|
|
if _, ok := v.(int64); !ok {
|
|
break
|
|
}
|
|
return fmt.Sprintf("%s", byten.Size(v.(int64)))
|
|
case KindDuration:
|
|
if _, ok := v.(int64); !ok {
|
|
break
|
|
}
|
|
return fmt.Sprintf("%s", roundDuration(time.Duration(v.(int64))))
|
|
}
|
|
|
|
if f, ok := v.(float64); ok {
|
|
return fmt.Sprintf("%.2f", f)
|
|
}
|
|
|
|
return fmt.Sprintf("%v", v)
|
|
}
|
|
|
|
// roundDuration removes unneeded precision from the String() output for time.Duration.
|
|
func roundDuration(d time.Duration) time.Duration {
|
|
r := time.Second
|
|
if d < time.Second {
|
|
r = time.Millisecond
|
|
}
|
|
if d < time.Millisecond {
|
|
r = time.Microsecond
|
|
}
|
|
if r <= 0 {
|
|
return d
|
|
}
|
|
neg := d < 0
|
|
if neg {
|
|
d = -d
|
|
}
|
|
if m := d % r; m+m < r {
|
|
d = d - m
|
|
} else {
|
|
d = d + r - m
|
|
}
|
|
if neg {
|
|
return -d
|
|
}
|
|
return d
|
|
}
|
|
|
|
func DottedFieldsToSliceEscaped(s string) []string {
|
|
rv := make([]string, 0)
|
|
lastSlash := false
|
|
curr := ""
|
|
for _, r := range s {
|
|
// base case, dot not after slash
|
|
if !lastSlash && r == '.' {
|
|
if len(curr) > 0 {
|
|
rv = append(rv, curr)
|
|
curr = ""
|
|
}
|
|
continue
|
|
} else if !lastSlash {
|
|
// any character not after slash
|
|
curr += string(r)
|
|
if r == '\\' {
|
|
lastSlash = true
|
|
} else {
|
|
lastSlash = false
|
|
}
|
|
continue
|
|
} else if r == '\\' {
|
|
// last was slash, and so is this
|
|
lastSlash = false // 2 slashes = 0
|
|
// we already appended a single slash on first
|
|
continue
|
|
} else if r == '.' {
|
|
// we see \. but already appended \ last time
|
|
// replace it with .
|
|
curr = curr[:len(curr)-1] + "."
|
|
lastSlash = false
|
|
} else {
|
|
// \ and any other character, ignore
|
|
curr += string(r)
|
|
lastSlash = false
|
|
continue
|
|
}
|
|
}
|
|
if len(curr) > 0 {
|
|
rv = append(rv, curr)
|
|
}
|
|
return rv
|
|
}
|