...

Source file src/golang.conradwood.net/go-easyops/server/usage_tracker.go

Documentation: golang.conradwood.net/go-easyops/server

     1  package server
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"sync"
     7  	"time"
     8  
     9  	"golang.conradwood.net/apis/auth"
    10  )
    11  
    12  var (
    13  	usages_tracking_enabled = flag.Bool("ge_track_usage_per_calling_service", true, "if true track usage per calling service")
    14  	usages                  = &usage_info_tracker{usages: make(map[string]*usage_service)}
    15  )
    16  
    17  type usage_info_tracker struct {
    18  	sync.Mutex
    19  	usages map[string]*usage_service
    20  }
    21  
    22  type usage_service struct {
    23  	sync.Mutex
    24  	name             string
    25  	usage_method_map map[string]*usage_method
    26  }
    27  type usage_method struct {
    28  	sync.Mutex
    29  	name    string
    30  	callers []*usage_caller
    31  }
    32  type usage_caller struct {
    33  	sync.Mutex
    34  	user      *auth.User
    35  	calls     int
    36  	errors    int
    37  	last_call time.Time
    38  }
    39  
    40  func (uit *usage_info_tracker) GetServiceByName(name string) *usage_service {
    41  	uit.Lock()
    42  	defer uit.Unlock()
    43  	us := uit.usages[name]
    44  	if us == nil {
    45  		us = &usage_service{name: name, usage_method_map: make(map[string]*usage_method)}
    46  		uit.usages[name] = us
    47  	}
    48  	return us
    49  }
    50  func (uit *usage_info_tracker) Services() []*usage_service {
    51  	uit.Lock()
    52  	defer uit.Unlock()
    53  	var res []*usage_service
    54  	for _, v := range uit.usages {
    55  		res = append(res, v)
    56  	}
    57  	return res
    58  }
    59  
    60  func (us *usage_service) Methods() []*usage_method {
    61  	us.Lock()
    62  	defer us.Unlock()
    63  	var res []*usage_method
    64  	for _, v := range us.usage_method_map {
    65  		res = append(res, v)
    66  	}
    67  	return res
    68  }
    69  func (us *usage_service) MethodByName(name string) *usage_method {
    70  	us.Lock()
    71  	defer us.Unlock()
    72  	um := us.usage_method_map[name]
    73  	if um == nil {
    74  		if len(us.usage_method_map) > 100 {
    75  			return nil
    76  		}
    77  		um = &usage_method{name: name}
    78  		us.usage_method_map[name] = um
    79  	}
    80  	return um
    81  }
    82  func (us *usage_service) Name() string {
    83  	return us.name
    84  }
    85  
    86  func (um *usage_method) Callers() []*usage_caller {
    87  	um.Lock()
    88  	defer um.Unlock()
    89  	var res []*usage_caller
    90  	for _, v := range um.callers {
    91  		res = append(res, v)
    92  	}
    93  	return res
    94  }
    95  func (um *usage_method) Name() string {
    96  	return um.name
    97  }
    98  func (um *usage_method) CallerByUser(caller *auth.User) *usage_caller {
    99  	um.Lock()
   100  	defer um.Unlock()
   101  	var uc *usage_caller
   102  	for _, ucl := range um.callers {
   103  		if ucl.user.ID == caller.ID {
   104  			uc = ucl
   105  			break
   106  		}
   107  	}
   108  	if uc == nil {
   109  		if len(um.callers) > 200 {
   110  			return nil
   111  		}
   112  		uc = &usage_caller{user: caller}
   113  		um.callers = append(um.callers, uc)
   114  	}
   115  	return uc
   116  }
   117  func (uc *usage_caller) User() *auth.User {
   118  	return uc.user
   119  }
   120  
   121  // how often was it called?
   122  func (uc *usage_caller) Usages() int {
   123  	return uc.calls
   124  }
   125  func (uc *usage_caller) Errors() int {
   126  	return uc.errors
   127  }
   128  func (uc *usage_caller) ErrorRate() float64 {
   129  	if uc.errors == 0 || uc.calls == 0 {
   130  		return 0.0
   131  	}
   132  	res := float64(uc.errors) / float64(uc.calls) * 100.0
   133  	return res
   134  }
   135  
   136  // when was last time it was called?
   137  func (uc *usage_caller) LastCallTime() time.Time {
   138  	return uc.last_call
   139  }
   140  func (uc *usage_caller) String() string {
   141  	return fmt.Sprintf("%s %d %d %d (%s)", uc.user.ID, uc.calls, uc.errors, uc.last_call.Unix(), uc.user.Email)
   142  }
   143  
   144  func track_get_caller(service, method string, caller *auth.User) *usage_caller {
   145  	if !*usages_tracking_enabled {
   146  		return nil
   147  	}
   148  	if caller == nil {
   149  		return nil
   150  	}
   151  	us := usages.GetServiceByName(service)
   152  	if us == nil {
   153  		return nil
   154  	}
   155  	um := us.MethodByName(method)
   156  	if um == nil {
   157  		return nil
   158  	}
   159  	uc := um.CallerByUser(caller)
   160  	if uc == nil {
   161  		return nil
   162  	}
   163  	return uc
   164  }
   165  func track_inbound_call(service, method string, caller *auth.User) {
   166  	uc := track_get_caller(service, method, caller)
   167  	if uc == nil {
   168  		return
   169  	}
   170  	uc.Lock()
   171  	uc.calls++
   172  	uc.last_call = time.Now()
   173  	uc.Unlock()
   174  }
   175  func track_inbound_error(service, method string, caller *auth.User) {
   176  	uc := track_get_caller(service, method, caller)
   177  	if uc == nil {
   178  		return
   179  	}
   180  	uc.Lock()
   181  	uc.errors++
   182  	uc.Unlock()
   183  }
   184  
   185  func GetUsageInfo() *usage_info_tracker {
   186  	return usages
   187  }
   188  

View as plain text