123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- package health
- import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "log"
- "path"
- "strings"
- "sync"
- "time"
- )
- type StatusFile struct {
- filename string
- mu sync.RWMutex
- m StatusFileData
- }
- type StatusFileData map[string]*Service
- func NewStatusFile(filename string) *StatusFile {
- return &StatusFile{
- m: make(StatusFileData),
- filename: filename,
- }
- }
- // DirectoryReader loads (and regularly re-loads) health
- // .json files from the specified files into the default
- // health registry.
- func DirectoryReader(dir string) {
- for {
- err := reloadDirectory(dir)
- if err != nil {
- log.Printf("loading health data: %s", err)
- }
- time.Sleep(1 * time.Second)
- }
- }
- func reloadDirectory(dir string) error {
- dirlist, err := ioutil.ReadDir(dir)
- if err != nil {
- return fmt.Errorf("could not read '%s': %s", dir, err)
- }
- seen := map[string]bool{}
- var parseErr error
- for _, file := range dirlist {
- fileName := file.Name()
- if !strings.HasSuffix(strings.ToLower(fileName), ".json") ||
- strings.HasPrefix(path.Base(fileName), ".") ||
- file.IsDir() {
- continue
- }
- statusName := fileName[0:strings.LastIndex(fileName, ".")]
- registry.mu.Lock()
- s, ok := registry.m[statusName]
- registry.mu.Unlock()
- seen[statusName] = true
- if ok {
- s.Reload()
- } else {
- s := NewStatusFile(path.Join(dir, fileName))
- err := s.Reload()
- if err != nil {
- log.Printf("error loading '%s': %s", fileName, err)
- parseErr = err
- }
- registry.Add(statusName, s)
- }
- }
- registry.mu.Lock()
- for n, _ := range registry.m {
- if !seen[n] {
- registry.m[n].Close()
- delete(registry.m, n)
- }
- }
- registry.mu.Unlock()
- return parseErr
- }
- func (s *StatusFile) Reload() error {
- if len(s.filename) > 0 {
- return s.Load(s.filename)
- }
- return nil
- }
- // Load imports the data atomically into the status map. If there's
- // a JSON error the old data is preserved.
- func (s *StatusFile) Load(filename string) error {
- n := StatusFileData{}
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- return err
- }
- err = json.Unmarshal(b, &n)
- if err != nil {
- return err
- }
- s.mu.Lock()
- s.m = n
- s.mu.Unlock()
- return nil
- }
- func (s *StatusFile) Close() error {
- s.mu.Lock()
- s.m = nil
- s.mu.Unlock()
- return nil
- }
- func (s *StatusFile) GetStatus(check string) StatusType {
- s.mu.RLock()
- defer s.mu.RUnlock()
- if s.m == nil {
- return StatusUnknown
- }
- st, ok := s.m[check]
- if !ok {
- log.Printf("Not found '%s'", check)
- return StatusUnknown
- }
- return st.Status
- }
- // UnmarshalJSON implements the json.Unmarshaler interface.
- func (srv *Service) UnmarshalJSON(b []byte) error {
- var i int64
- if err := json.Unmarshal(b, &i); err != nil {
- return err
- }
- *srv = Service{Status: StatusType(i)}
- return nil
- }
- // UnmarshalJSON implements the json.Marshaler interface.
- // func (srv *Service) MarshalJSON() ([]byte, error) {
- // return
- // }
|