11package core
22
33import (
4+ "github.com/devfeel/dotweb/framework/json"
5+ "strconv"
6+ "strings"
7+ "sync"
48 "sync/atomic"
59 "time"
610)
711
812var GlobalState * ServerStateInfo
913
14+ const (
15+ minuteTimeLayout = "200601021504"
16+ dateTimeLayout = "2006-01-02 15:04:05"
17+ defaultReserveMinutes = 60
18+ defaultCheckTimeMinutes = 10
19+ )
20+
1021func init () {
1122 GlobalState = & ServerStateInfo {
12- ServerStartTime : time .Now (),
13- TotalRequestCount : 0 ,
14- TotalErrorCount : 0 ,
23+ ServerStartTime : time .Now (),
24+ TotalRequestCount : 0 ,
25+ TotalErrorCount : 0 ,
26+ IntervalRequestData : NewItemContext (),
27+ DetailRequestPageData : NewItemContext (),
28+ IntervalErrorData : NewItemContext (),
29+ DetailErrorPageData : NewItemContext (),
30+ DetailErrorData : NewItemContext (),
31+ DetailHTTPCodeData : NewItemContext (),
32+ dataChan_Request : make (chan * RequestInfo , 1000 ),
33+ dataChan_Error : make (chan * ErrorInfo , 1000 ),
34+ dataChan_HttpCode : make (chan * HttpCodeInfo , 1000 ),
35+ infoPool : & pool {
36+ requestInfo : sync.Pool {
37+ New : func () interface {} {
38+ return & RequestInfo {}
39+ },
40+ },
41+ errorInfo : sync.Pool {
42+ New : func () interface {} {
43+ return & ErrorInfo {}
44+ },
45+ },
46+ httpCodeInfo : sync.Pool {
47+ New : func () interface {} {
48+ return & HttpCodeInfo {}
49+ },
50+ },
51+ },
1552 }
53+ go GlobalState .handleInfo ()
54+ go time .AfterFunc (time .Duration (defaultCheckTimeMinutes )* time .Minute , GlobalState .checkAndRemoveIntervalData )
55+ }
56+
57+ //pool定义
58+ type pool struct {
59+ requestInfo sync.Pool
60+ errorInfo sync.Pool
61+ httpCodeInfo sync.Pool
62+ }
63+
64+ //http request count info
65+ type RequestInfo struct {
66+ Url string
67+ Num uint64
68+ }
69+
70+ //error count info
71+ type ErrorInfo struct {
72+ Url string
73+ ErrMsg string
74+ Num uint64
75+ }
76+
77+ //httpcode count info
78+ type HttpCodeInfo struct {
79+ Url string
80+ Code int
81+ Num uint64
1682}
1783
1884//服务器状态信息
@@ -21,18 +87,219 @@ type ServerStateInfo struct {
2187 ServerStartTime time.Time
2288 //该运行期间总访问次数
2389 TotalRequestCount uint64
24- //该运行期间错误次数
90+ //单位时间内请求数据 - 按分钟为单位
91+ IntervalRequestData * ItemContext
92+ //明细请求页面数据 - 以不带参数的访问url为key
93+ DetailRequestPageData * ItemContext
94+ //该运行期间异常次数
2595 TotalErrorCount uint64
96+ //单位时间内异常次数 - 按分钟为单位
97+ IntervalErrorData * ItemContext
98+ //明细异常页面数据 - 以不带参数的访问url为key
99+ DetailErrorPageData * ItemContext
100+ //明细异常数据 - 以不带参数的访问url为key
101+ DetailErrorData * ItemContext
102+ //明细Http状态码数据 - 以HttpCode为key,例如200、500等
103+ DetailHTTPCodeData * ItemContext
104+
105+ dataChan_Request chan * RequestInfo
106+ dataChan_Error chan * ErrorInfo
107+ dataChan_HttpCode chan * HttpCodeInfo
108+ //对象池
109+ infoPool * pool
26110}
27111
28- //增加请求数
29- func (state * ServerStateInfo ) AddRequestCount (num uint64 ) uint64 {
30- atomic .AddUint64 (& state .TotalRequestCount , num )
112+ //ShowHtmlData show server state data html-string format
113+ func (state * ServerStateInfo ) ShowHtmlData () string {
114+ data := "<html><body><div>"
115+ data += "ServerStartTime : " + state .ServerStartTime .Format (dateTimeLayout )
116+ data += "<br>"
117+ data += "TotalRequestCount : " + strconv .FormatUint (state .TotalRequestCount , 10 )
118+ data += "<br>"
119+ data += "TotalErrorCount : " + strconv .FormatUint (state .TotalErrorCount , 10 )
120+ data += "<br>"
121+ state .IntervalRequestData .RLock ()
122+ data += "IntervalRequestData : " + jsonutil .GetJsonString (state .IntervalRequestData .GetCurrentMap ())
123+ state .IntervalRequestData .RUnlock ()
124+ data += "<br>"
125+ state .DetailRequestPageData .RLock ()
126+ data += "DetailRequestPageData : " + jsonutil .GetJsonString (state .DetailRequestPageData .GetCurrentMap ())
127+ state .DetailRequestPageData .RUnlock ()
128+ data += "<br>"
129+ state .IntervalErrorData .RLock ()
130+ data += "IntervalErrorData : " + jsonutil .GetJsonString (state .IntervalErrorData .GetCurrentMap ())
131+ state .IntervalErrorData .RUnlock ()
132+ data += "<br>"
133+ state .DetailErrorPageData .RLock ()
134+ data += "DetailErrorPageData : " + jsonutil .GetJsonString (state .DetailErrorPageData .GetCurrentMap ())
135+ state .DetailErrorPageData .RUnlock ()
136+ data += "<br>"
137+ state .DetailErrorData .RLock ()
138+ data += "DetailErrorData : " + jsonutil .GetJsonString (state .DetailErrorData .GetCurrentMap ())
139+ state .DetailErrorData .RUnlock ()
140+ data += "<br>"
141+ state .DetailHTTPCodeData .RLock ()
142+ data += "DetailHttpCodeData : " + jsonutil .GetJsonString (state .DetailHTTPCodeData .GetCurrentMap ())
143+ state .DetailHTTPCodeData .RUnlock ()
144+ data += "</div></body></html>"
145+ return data
146+ }
147+
148+ //QueryIntervalRequestData query request count by query time
149+ func (state * ServerStateInfo ) QueryIntervalRequestData (queryKey string ) uint64 {
150+ return state .IntervalRequestData .GetUInt64 (queryKey )
151+ }
152+
153+ //QueryIntervalErrorData query error count by query time
154+ func (state * ServerStateInfo ) QueryIntervalErrorData (queryKey string ) uint64 {
155+ return state .IntervalErrorData .GetUInt64 (queryKey )
156+ }
157+
158+ //AddRequestCount 增加请求数
159+ func (state * ServerStateInfo ) AddRequestCount (page string , num uint64 ) uint64 {
160+ if strings .Index (page , "/dotweb/" ) != 0 {
161+ atomic .AddUint64 (& state .TotalRequestCount , num )
162+ state .addRequestData (page , num )
163+ }
31164 return state .TotalRequestCount
32165}
33166
34- //增加错误数
35- func (state * ServerStateInfo ) AddErrorCount (num uint64 ) uint64 {
167+ //AddHttpCodeCount 增加Http状态码数据
168+ func (state * ServerStateInfo ) AddTTPCodeCount (page string , code int , num uint64 ) uint64 {
169+ if strings .Index (page , "/dotweb/" ) != 0 {
170+ state .addHTTPCodeData (page , code , num )
171+ }
172+ return state .TotalErrorCount
173+ }
174+
175+ //AddErrorCount 增加错误数
176+ func (state * ServerStateInfo ) AddErrorCount (page string , err error , num uint64 ) uint64 {
36177 atomic .AddUint64 (& state .TotalErrorCount , num )
178+ state .addErrorData (page , err , num )
37179 return state .TotalErrorCount
38180}
181+
182+ func (state * ServerStateInfo ) addRequestData (page string , num uint64 ) {
183+ //get from pool
184+ info := state .infoPool .requestInfo .Get ().(* RequestInfo )
185+ info .Url = page
186+ info .Num = num
187+ state .dataChan_Request <- info
188+ }
189+
190+ func (state * ServerStateInfo ) addErrorData (page string , err error , num uint64 ) {
191+ //get from pool
192+ info := state .infoPool .errorInfo .Get ().(* ErrorInfo )
193+ info .Url = page
194+ info .ErrMsg = err .Error ()
195+ info .Num = num
196+ state .dataChan_Error <- info
197+ }
198+
199+ func (state * ServerStateInfo ) addHTTPCodeData (page string , code int , num uint64 ) {
200+ //get from pool
201+ info := state .infoPool .httpCodeInfo .Get ().(* HttpCodeInfo )
202+ info .Url = page
203+ info .Code = code
204+ info .Num = num
205+ state .dataChan_HttpCode <- info
206+ }
207+
208+ //处理日志内部函数
209+ func (state * ServerStateInfo ) handleInfo () {
210+ for {
211+ select {
212+ case info := <- state .dataChan_Request :
213+ {
214+ //set detail page data
215+ key := strings .ToLower (info .Url )
216+ val := state .DetailRequestPageData .GetUInt64 (key )
217+ state .DetailRequestPageData .Set (key , val + info .Num )
218+
219+ //set interval data
220+ key = time .Now ().Format (minuteTimeLayout )
221+ val = state .IntervalRequestData .GetUInt64 (key )
222+ state .IntervalRequestData .Set (key , val + info .Num )
223+
224+ //put info obj
225+ state .infoPool .requestInfo .Put (info )
226+ }
227+ case info := <- state .dataChan_Error :
228+ {
229+ //set detail error page data
230+ key := strings .ToLower (info .Url )
231+ val := state .DetailErrorPageData .GetUInt64 (key )
232+ state .DetailErrorPageData .Set (key , val + info .Num )
233+
234+ //set detail error data
235+ key = info .ErrMsg
236+ val = state .DetailErrorData .GetUInt64 (key )
237+ state .DetailErrorData .Set (key , val + info .Num )
238+
239+ //set interval data
240+ key = time .Now ().Format (minuteTimeLayout )
241+ val = state .IntervalErrorData .GetUInt64 (key )
242+ state .IntervalErrorData .Set (key , val + info .Num )
243+
244+ //put info obj
245+ state .infoPool .errorInfo .Put (info )
246+ }
247+ case info := <- state .dataChan_HttpCode :
248+ {
249+ //set detail error page data
250+ key := strconv .Itoa (info .Code )
251+ val := state .DetailHTTPCodeData .GetUInt64 (key )
252+ state .DetailHTTPCodeData .Set (key , val + info .Num )
253+
254+ //put info obj
255+ state .infoPool .httpCodeInfo .Put (info )
256+ }
257+ }
258+ }
259+ }
260+
261+ //check and remove need to remove interval data with request and error
262+ func (state * ServerStateInfo ) checkAndRemoveIntervalData () {
263+ var needRemoveKey []string
264+ now , _ := time .Parse (minuteTimeLayout , time .Now ().Format (minuteTimeLayout ))
265+
266+ //check IntervalRequestData
267+ state .IntervalRequestData .RLock ()
268+ if state .IntervalRequestData .Len () > defaultReserveMinutes {
269+ for k := range state .IntervalRequestData .GetCurrentMap () {
270+ if t , err := time .Parse (minuteTimeLayout , k ); err != nil {
271+ needRemoveKey = append (needRemoveKey , k )
272+ } else {
273+ if now .Sub (t ) > (defaultReserveMinutes * time .Minute ) {
274+ needRemoveKey = append (needRemoveKey , k )
275+ }
276+ }
277+ }
278+ }
279+ state .IntervalRequestData .RUnlock ()
280+ //remove keys
281+ for _ , v := range needRemoveKey {
282+ state .IntervalRequestData .Remove (v )
283+ }
284+
285+ //check IntervalErrorData
286+ needRemoveKey = []string {}
287+ state .IntervalErrorData .RLock ()
288+ if state .IntervalErrorData .Len () > defaultReserveMinutes {
289+ for k := range state .IntervalErrorData .GetCurrentMap () {
290+ if t , err := time .Parse (minuteTimeLayout , k ); err != nil {
291+ needRemoveKey = append (needRemoveKey , k )
292+ } else {
293+ if now .Sub (t ) > (defaultReserveMinutes * time .Minute ) {
294+ needRemoveKey = append (needRemoveKey , k )
295+ }
296+ }
297+ }
298+ }
299+ state .IntervalErrorData .RUnlock ()
300+ //remove keys
301+ for _ , v := range needRemoveKey {
302+ state .IntervalErrorData .Remove (v )
303+ }
304+ time .AfterFunc (time .Duration (defaultCheckTimeMinutes )* time .Minute , state .checkAndRemoveIntervalData )
305+ }
0 commit comments