|
- // Copyright 2013 Beego Authors
- // Copyright 2014 The Macaron Authors
- //
- // Licensed under the Apache License, Version 2.0 (the "License"): you may
- // not use this file except in compliance with the License. You may obtain
- // a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- // License for the specific language governing permissions and limitations
- // under the License.
-
- package toolbox
-
- import (
- "encoding/json"
- "fmt"
- "io"
- "strings"
- "sync"
- "time"
- )
-
- // Statistics struct
- type Statistics struct {
- RequestUrl string
- RequestNum int64
- MinTime time.Duration
- MaxTime time.Duration
- TotalTime time.Duration
- }
-
- // UrlMap contains several statistics struct to log different data
- type UrlMap struct {
- lock sync.RWMutex
- LengthLimit int // limit the urlmap's length if it's equal to 0 there's no limit
- urlmap map[string]map[string]*Statistics
- }
-
- // add statistics task.
- // it needs request method, request url and statistics time duration
- func (m *UrlMap) AddStatistics(requestMethod, requestUrl string, requesttime time.Duration) {
- m.lock.Lock()
- defer m.lock.Unlock()
-
- if method, ok := m.urlmap[requestUrl]; ok {
- if s, ok := method[requestMethod]; ok {
- s.RequestNum += 1
- if s.MaxTime < requesttime {
- s.MaxTime = requesttime
- }
- if s.MinTime > requesttime {
- s.MinTime = requesttime
- }
- s.TotalTime += requesttime
- } else {
- nb := &Statistics{
- RequestUrl: requestUrl,
- RequestNum: 1,
- MinTime: requesttime,
- MaxTime: requesttime,
- TotalTime: requesttime,
- }
- m.urlmap[requestUrl][requestMethod] = nb
- }
-
- } else {
- if m.LengthLimit > 0 && m.LengthLimit <= len(m.urlmap) {
- return
- }
- methodmap := make(map[string]*Statistics)
- nb := &Statistics{
- RequestUrl: requestUrl,
- RequestNum: 1,
- MinTime: requesttime,
- MaxTime: requesttime,
- TotalTime: requesttime,
- }
- methodmap[requestMethod] = nb
- m.urlmap[requestUrl] = methodmap
- }
- }
-
- // put url statistics result in io.Writer
- func (m *UrlMap) GetMap(w io.Writer) {
- m.lock.RLock()
- defer m.lock.RUnlock()
-
- sep := fmt.Sprintf("+%s+%s+%s+%s+%s+%s+%s+\n", strings.Repeat("-", 51), strings.Repeat("-", 12),
- strings.Repeat("-", 18), strings.Repeat("-", 18), strings.Repeat("-", 18), strings.Repeat("-", 18), strings.Repeat("-", 18))
- fmt.Fprintf(w, sep)
- fmt.Fprintf(w, "| % -50s| % -10s | % -16s | % -16s | % -16s | % -16s | % -16s |\n", "Request URL", "Method", "Times", "Total Used(s)", "Max Used(μs)", "Min Used(μs)", "Avg Used(μs)")
- fmt.Fprintf(w, sep)
-
- for k, v := range m.urlmap {
- for kk, vv := range v {
- fmt.Fprintf(w, "| % -50s| % -10s | % 16d | % 16f | % 16.6f | % 16.6f | % 16.6f |\n", k,
- kk, vv.RequestNum, vv.TotalTime.Seconds(), float64(vv.MaxTime.Nanoseconds())/1000,
- float64(vv.MinTime.Nanoseconds())/1000, float64(time.Duration(int64(vv.TotalTime)/vv.RequestNum).Nanoseconds())/1000,
- )
- }
- }
- fmt.Fprintf(w, sep)
- }
-
- type URLMapInfo struct {
- URL string `json:"url"`
- Method string `json:"method"`
- Times int64 `json:"times"`
- TotalUsed float64 `json:"total_used"`
- MaxUsed float64 `json:"max_used"`
- MinUsed float64 `json:"min_used"`
- AvgUsed float64 `json:"avg_used"`
- }
-
- func (m *UrlMap) JSON(w io.Writer) {
- infos := make([]*URLMapInfo, 0, len(m.urlmap))
- for k, v := range m.urlmap {
- for kk, vv := range v {
- infos = append(infos, &URLMapInfo{
- URL: k,
- Method: kk,
- Times: vv.RequestNum,
- TotalUsed: vv.TotalTime.Seconds(),
- MaxUsed: float64(vv.MaxTime.Nanoseconds()) / 1000,
- MinUsed: float64(vv.MinTime.Nanoseconds()) / 1000,
- AvgUsed: float64(time.Duration(int64(vv.TotalTime)/vv.RequestNum).Nanoseconds()) / 1000,
- })
- }
- }
-
- if err := json.NewEncoder(w).Encode(infos); err != nil {
- panic("URLMap.JSON: " + err.Error())
- }
- }
|