1
0
mirror of https://github.com/divan/expvarmon.git synced 2025-04-25 13:48:54 +08:00
expvarmon/service.go

152 lines
3.0 KiB
Go
Raw Normal View History

2015-04-21 12:51:01 +03:00
package main
import (
2015-04-25 15:54:17 +03:00
"fmt"
2015-05-01 19:26:28 +03:00
"net"
"strconv"
2015-04-25 15:54:17 +03:00
"strings"
2015-05-01 20:12:23 +03:00
"sync"
2015-05-02 10:12:38 +03:00
"time"
2015-05-02 01:21:52 +03:00
"github.com/antonholmquist/jason"
2015-05-02 10:12:38 +03:00
"github.com/pyk/byten"
2015-04-21 12:51:01 +03:00
)
// Service represents constantly updating info about single service.
type Service struct {
2015-04-30 23:54:54 +03:00
Port string
Name string
Cmdline string
2015-04-25 15:54:17 +03:00
2015-05-02 10:22:49 +03:00
stacks map[VarName]*Stack
2015-04-21 12:51:01 +03:00
Err error
}
// NewService returns new Service object.
2015-05-01 18:48:34 +03:00
func NewService(port string, vars []VarName) *Service {
values := make(map[VarName]*Stack)
2015-05-01 16:49:19 +03:00
for _, name := range vars {
2015-05-01 18:48:34 +03:00
values[VarName(name)] = NewStack()
2015-05-01 16:49:19 +03:00
}
2015-05-02 10:22:49 +03:00
2015-04-21 12:51:01 +03:00
return &Service{
Name: port, // we have only port on start, so use it as name until resolved
Port: port,
2015-04-25 16:29:19 +03:00
2015-05-02 10:22:49 +03:00
stacks: values,
2015-04-21 12:51:01 +03:00
}
2015-04-29 00:07:46 +03:00
}
// Update updates Service info from Expvar variable.
2015-05-01 20:12:23 +03:00
func (s *Service) Update(wg *sync.WaitGroup) {
defer wg.Done()
2015-04-30 23:54:54 +03:00
expvar, err := FetchExpvar(s.Addr())
2015-05-01 13:20:06 +03:00
s.Err = err
2015-04-21 12:51:01 +03:00
2015-05-01 19:26:28 +03:00
// Update Cmdline & Name only once
if len(s.Cmdline) == 0 {
cmdline, err := expvar.GetStringArray("cmdline")
if err != nil {
s.Err = err
} else {
s.Cmdline = strings.Join(cmdline, " ")
s.Name = BaseCommand(cmdline)
}
2015-05-01 00:47:11 +03:00
}
2015-04-25 15:54:17 +03:00
2015-05-01 19:26:28 +03:00
// For all vars, fetch desired value from Json and push to it's own stack.
2015-05-02 10:22:49 +03:00
for name, stack := range s.stacks {
2015-05-02 01:21:52 +03:00
value, err := expvar.GetValue(name.ToSlice()...)
2015-05-01 16:49:19 +03:00
if err != nil {
continue
}
2015-05-02 01:21:52 +03:00
v := guessValue(value)
if v != nil {
stack.Push(v)
}
2015-05-01 00:47:11 +03:00
}
2015-04-30 23:54:54 +03:00
}
2015-05-02 10:22:49 +03:00
// guessValue attemtps to bruteforce all supported types.
2015-05-02 01:21:52 +03:00
func guessValue(value *jason.Value) interface{} {
if v, err := value.Int64(); err == nil {
return v
} else if v, err := value.Float64(); err == nil {
return v
} else if v, err := value.Boolean(); err == nil {
return v
} else if v, err := value.String(); err == nil {
return v
}
return nil
}
2015-04-25 15:54:17 +03:00
// Addr returns fully qualified host:port pair for service.
//
// If host is not specified, 'localhost' is used.
func (s Service) Addr() string {
2015-05-01 19:26:28 +03:00
// Try as port only
_, err := strconv.Atoi(s.Port)
if err == nil {
return fmt.Sprintf("http://localhost:%s%s", s.Port, ExpvarsURL)
}
host, port, err := net.SplitHostPort(s.Port)
if err == nil {
return fmt.Sprintf("http://%s:%s%s", host, port, ExpvarsURL)
}
return ""
2015-04-21 12:51:01 +03:00
}
2015-04-25 22:46:16 +03:00
2015-05-01 19:13:23 +03:00
// Value returns current value for the given var of this service.
2015-05-02 10:12:38 +03:00
//
// It also formats value, if kind is specified.
2015-05-01 18:48:34 +03:00
func (s Service) Value(name VarName) string {
2015-04-30 23:54:54 +03:00
if s.Err != nil {
2015-04-25 22:46:16 +03:00
return "N/A"
}
2015-05-02 10:22:49 +03:00
val, ok := s.stacks[name]
2015-04-30 23:54:54 +03:00
if !ok {
return "N/A"
}
2015-05-02 10:12:38 +03:00
v := val.Front()
if v == nil {
2015-04-30 23:54:54 +03:00
return "N/A"
}
2015-05-02 10:12:38 +03:00
switch name.Kind() {
case KindMemory:
2015-05-02 10:22:49 +03:00
if _, ok := v.(int64); !ok {
break
}
2015-05-02 10:12:38 +03:00
return fmt.Sprintf("%s", byten.Size(v.(int64)))
case KindDuration:
2015-05-02 10:22:49 +03:00
if _, ok := v.(int64); !ok {
break
}
return fmt.Sprintf("%s", time.Duration(v.(int64)))
2015-05-02 10:12:38 +03:00
default:
return fmt.Sprintf("%v", v)
}
2015-05-02 10:22:49 +03:00
return fmt.Sprintf("%v", v)
2015-04-30 23:54:54 +03:00
}
2015-05-02 01:21:52 +03:00
// Values returns slice of ints with recent
// values of the given var, to be used with sparkline.
2015-05-01 18:48:34 +03:00
func (s Service) Values(name VarName) []int {
2015-04-30 23:54:54 +03:00
if s.Err != nil {
return nil
}
2015-05-02 10:22:49 +03:00
stack, ok := s.stacks[name]
2015-04-30 23:54:54 +03:00
if !ok {
return nil
}
2015-04-25 22:46:16 +03:00
2015-05-02 01:21:52 +03:00
return stack.IntValues()
2015-04-25 22:46:16 +03:00
}