...
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
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
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