2015-04-21 12:51:01 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2015-04-29 00:07:46 +03:00
|
|
|
"errors"
|
2015-04-25 15:54:17 +03:00
|
|
|
"fmt"
|
|
|
|
"net/http"
|
2015-04-21 12:51:01 +03:00
|
|
|
"runtime"
|
2015-04-25 15:54:17 +03:00
|
|
|
"strings"
|
2015-04-29 00:07:46 +03:00
|
|
|
|
|
|
|
"github.com/pyk/byten"
|
2015-04-21 12:51:01 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type Services []*Service
|
|
|
|
|
|
|
|
// Service represents constantly updating info about single service.
|
|
|
|
type Service struct {
|
2015-04-25 15:54:17 +03:00
|
|
|
Port string
|
|
|
|
Name string
|
|
|
|
|
|
|
|
Cmdline string
|
2015-04-25 16:29:19 +03:00
|
|
|
MemStats *runtime.MemStats
|
|
|
|
|
|
|
|
Values map[string]*Stack
|
2015-04-21 12:51:01 +03:00
|
|
|
|
|
|
|
Err error
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewService returns new Service object.
|
|
|
|
func NewService(port string) *Service {
|
|
|
|
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
|
|
|
|
|
|
|
Values: make(map[string]*Stack),
|
2015-04-21 12:51:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-29 00:07:46 +03:00
|
|
|
func GetExpvar(addr string) (*Expvar, error) {
|
|
|
|
var e Expvar
|
|
|
|
resp, err := http.Get(addr)
|
2015-04-25 15:54:17 +03:00
|
|
|
if err != nil {
|
2015-04-29 00:07:46 +03:00
|
|
|
return &e, err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode == http.StatusNotFound {
|
|
|
|
return &e, errors.New("Vars not found. Did you import expvars?")
|
2015-04-25 15:54:17 +03:00
|
|
|
} else {
|
2015-04-29 00:07:46 +03:00
|
|
|
expvar, err := ParseExpvar(resp.Body)
|
|
|
|
e = *expvar
|
2015-04-25 15:54:17 +03:00
|
|
|
if err != nil {
|
2015-04-29 00:07:46 +03:00
|
|
|
return &e, err
|
2015-04-21 12:51:01 +03:00
|
|
|
}
|
|
|
|
}
|
2015-04-29 00:07:46 +03:00
|
|
|
return &e, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update updates Service info from Expvar variable.
|
|
|
|
func (s *Service) Update() {
|
|
|
|
expvar, err := GetExpvar(s.Addr())
|
|
|
|
if err != nil {
|
|
|
|
expvar.Err = err
|
|
|
|
}
|
2015-04-21 12:51:01 +03:00
|
|
|
|
2015-04-25 15:54:17 +03:00
|
|
|
s.Err = expvar.Err
|
2015-04-25 16:29:19 +03:00
|
|
|
s.MemStats = expvar.MemStats
|
2015-04-25 15:54:17 +03:00
|
|
|
|
|
|
|
// Update name and cmdline only if empty
|
|
|
|
if len(s.Cmdline) == 0 {
|
|
|
|
s.Cmdline = strings.Join(expvar.Cmdline, " ")
|
|
|
|
s.Name = BaseCommand(expvar.Cmdline)
|
|
|
|
}
|
2015-04-25 16:29:19 +03:00
|
|
|
|
|
|
|
// Put metrics data
|
|
|
|
mem, ok := s.Values["memory"]
|
|
|
|
if !ok {
|
2015-04-25 22:46:16 +03:00
|
|
|
s.Values["memory"] = NewStack(1200)
|
2015-04-25 16:29:19 +03:00
|
|
|
mem = s.Values["memory"]
|
|
|
|
}
|
2015-04-29 00:07:46 +03:00
|
|
|
if s.MemStats != nil {
|
|
|
|
mem.Push(int(s.MemStats.Alloc) / 1024)
|
|
|
|
}
|
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 {
|
|
|
|
return fmt.Sprintf("http://localhost:%s%s", s.Port, ExpvarsUrl)
|
2015-04-21 12:51:01 +03:00
|
|
|
}
|
2015-04-25 22:46:16 +03: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)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Meminfo returns memory info string for the given service.
|
|
|
|
func (s Service) Meminfo() string {
|
|
|
|
if s.Err != nil || s.MemStats == nil {
|
|
|
|
return "N/A"
|
|
|
|
}
|
|
|
|
|
|
|
|
allocated := byten.Size(int64(s.MemStats.Alloc))
|
|
|
|
sys := byten.Size(int64(s.MemStats.Sys))
|
|
|
|
return fmt.Sprintf("Alloc/Sys: %s / %s", allocated, sys)
|
|
|
|
}
|