2015-04-21 17:51:01 +08:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2015-04-25 20:54:17 +08:00
|
|
|
"fmt"
|
2015-05-02 00:26:28 +08:00
|
|
|
"net"
|
|
|
|
"strconv"
|
2015-04-25 20:54:17 +08:00
|
|
|
"strings"
|
2015-05-02 01:12:23 +08:00
|
|
|
"sync"
|
2015-04-21 17:51:01 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// Service represents constantly updating info about single service.
|
|
|
|
type Service struct {
|
2015-05-01 04:54:54 +08:00
|
|
|
Port string
|
|
|
|
Name string
|
|
|
|
Cmdline string
|
2015-04-25 20:54:17 +08:00
|
|
|
|
2015-05-01 23:48:34 +08:00
|
|
|
values map[VarName]*Stack
|
2015-04-21 17:51:01 +08:00
|
|
|
|
|
|
|
Err error
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewService returns new Service object.
|
2015-05-01 23:48:34 +08:00
|
|
|
func NewService(port string, vars []VarName) *Service {
|
|
|
|
values := make(map[VarName]*Stack)
|
2015-05-01 21:49:19 +08:00
|
|
|
for _, name := range vars {
|
2015-05-01 23:48:34 +08:00
|
|
|
values[VarName(name)] = NewStack()
|
2015-05-01 21:49:19 +08:00
|
|
|
}
|
2015-04-21 17:51:01 +08:00
|
|
|
return &Service{
|
|
|
|
Name: port, // we have only port on start, so use it as name until resolved
|
|
|
|
Port: port,
|
2015-04-25 21:29:19 +08:00
|
|
|
|
2015-05-01 21:49:19 +08:00
|
|
|
values: values,
|
2015-04-21 17:51:01 +08:00
|
|
|
}
|
2015-04-29 05:07:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update updates Service info from Expvar variable.
|
2015-05-02 01:12:23 +08:00
|
|
|
func (s *Service) Update(wg *sync.WaitGroup) {
|
|
|
|
defer wg.Done()
|
2015-05-01 04:54:54 +08:00
|
|
|
expvar, err := FetchExpvar(s.Addr())
|
2015-05-01 18:20:06 +08:00
|
|
|
s.Err = err
|
2015-04-21 17:51:01 +08:00
|
|
|
|
2015-05-02 00:26:28 +08: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 05:47:11 +08:00
|
|
|
}
|
2015-04-25 20:54:17 +08:00
|
|
|
|
2015-05-02 00:26:28 +08:00
|
|
|
// For all vars, fetch desired value from Json and push to it's own stack.
|
2015-05-01 21:49:19 +08:00
|
|
|
for name, stack := range s.values {
|
2015-05-01 23:48:34 +08:00
|
|
|
value, err := expvar.GetInt64(name.ToSlice()...)
|
2015-05-01 21:49:19 +08:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
stack.Push(int(value))
|
2015-05-01 05:47:11 +08:00
|
|
|
}
|
2015-05-01 04:54:54 +08:00
|
|
|
}
|
|
|
|
|
2015-04-25 20:54:17 +08: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-02 00:26:28 +08: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 17:51:01 +08:00
|
|
|
}
|
2015-04-26 03:46:16 +08:00
|
|
|
|
|
|
|
// StatusLine returns status line for services with it's name and status.
|
|
|
|
func (s Service) StatusLine() string {
|
|
|
|
if s.Err != nil {
|
|
|
|
return fmt.Sprintf("[ERR] %s failed", s.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("[R] %s", s.Name)
|
|
|
|
}
|
|
|
|
|
2015-05-02 00:13:23 +08:00
|
|
|
// Value returns current value for the given var of this service.
|
2015-05-01 23:48:34 +08:00
|
|
|
func (s Service) Value(name VarName) string {
|
2015-05-01 04:54:54 +08:00
|
|
|
if s.Err != nil {
|
2015-04-26 03:46:16 +08:00
|
|
|
return "N/A"
|
|
|
|
}
|
2015-05-01 23:48:34 +08:00
|
|
|
val, ok := s.values[name]
|
2015-05-01 04:54:54 +08:00
|
|
|
if !ok {
|
|
|
|
return "N/A"
|
|
|
|
}
|
|
|
|
if val.Front() == 0 {
|
|
|
|
return "N/A"
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("%d", val.Front())
|
|
|
|
}
|
|
|
|
|
2015-05-02 00:13:23 +08:00
|
|
|
// Values returns slice of ints with recent values of the given var,
|
|
|
|
// to be used with sparkline.
|
2015-05-01 23:48:34 +08:00
|
|
|
func (s Service) Values(name VarName) []int {
|
2015-05-01 04:54:54 +08:00
|
|
|
if s.Err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
2015-05-01 23:48:34 +08:00
|
|
|
val, ok := s.values[name]
|
2015-05-01 04:54:54 +08:00
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
2015-04-26 03:46:16 +08:00
|
|
|
|
2015-05-01 04:54:54 +08:00
|
|
|
return val.Values
|
2015-04-26 03:46:16 +08:00
|
|
|
}
|