package statemdl import ( "net/http" "sync" "time" "github.com/gin-gonic/gin" ) // Statistic - for app application type Statistic struct { ServiceName string `json:"serviceName"` TotalHits int `json:"totalHits"` MaxTime time.Duration `json:"maxTime"` MinTime time.Duration `json:"minTime"` TotalTime time.Duration `json:"totalTime"` ErrorCount int `json:"errorCount"` ErrorTime *time.Time `json:"errorTime"` LastError string `json:"lastError"` Description string `json:"description"` IsRestricted bool `json:"isRestricted"` IsRoleBased bool `json:"isRoleBased"` } type groupResponse struct { GroupTime string `json:"name"` Hits int64 `json:"hits"` } type clientResponse struct { ServicesState map[string]Statistic `json:"servicesState"` TotalHits int64 `json:"totalHits"` CacheHits int64 `json:"cacheHits"` CacheMiss int64 `json:"cacheMiss"` StartTime time.Time `json:"startTime"` GroupReport []groupResponse `json:"groupReport"` } type cacheStates struct { totalHits int64 cacheHits int64 cacheMiss int64 cacheHitsMutex *sync.Mutex } var stateCache map[string]Statistic var stateMutex = &sync.Mutex{} var cacheStatistic *cacheStates var groupName []int64 var groupHits []int64 var groupMutex = &sync.Mutex{} var currentGroup int64 var nextGroup int64 var nextTime = time.Second * 60 // serverStartTime - server start time var serverStartTime time.Time func init() { cacheStatistic = &cacheStates{ cacheHitsMutex: &sync.Mutex{}, } serverStartTime = time.Now() stateCache = make(map[string]Statistic) current := time.Now() groupName = append(groupName, current.Unix()) groupHits = append(groupHits, 0) currentGroup = current.Unix() nextGroup = current.Add(nextTime).Unix() } func updateGlobalHit() { cacheStatistic.cacheHitsMutex.Lock() updateGroupCache(cacheStatistic.totalHits) cacheStatistic.totalHits++ cacheStatistic.cacheHitsMutex.Unlock() } func updateGroupCache(hitCount int64) { groupMutex.Lock() current := time.Now() if current.Unix() < nextGroup { for i := 0; i < len(groupName); i++ { if groupName[i] == currentGroup { groupHits[i]++ } } } else { groupName = append(groupName, nextGroup) groupHits = append(groupHits, 1) currentGroup = nextGroup nextGroup = current.Add(nextTime).Unix() } groupMutex.Unlock() } // UpdateServiceState - update entry of service in state map func UpdateServiceState(serviceName string, servingTime time.Duration, serviceError error, isRestricted, isRoleBased bool) { stateMutex.Lock() serviceState, ok := stateCache[serviceName] if !ok { serviceState = Statistic{ ServiceName: serviceName, IsRestricted: isRestricted, IsRoleBased: isRoleBased, } } serviceState.TotalHits++ if serviceError != nil { serviceState.ErrorCount++ serviceState.LastError = serviceError.Error() ct := time.Now() serviceState.ErrorTime = &ct } else { serviceState.TotalTime += servingTime if servingTime > serviceState.MaxTime { serviceState.MaxTime = servingTime } if servingTime < serviceState.MinTime || serviceState.MinTime == 0 { serviceState.MinTime = servingTime } } stateCache[serviceName] = serviceState stateMutex.Unlock() updateGlobalHit() } // UpdateGlobalServiceCacheState - update only cache hits and miss count for all services func UpdateGlobalServiceCacheState(cacheHit bool) { cacheStatistic.cacheHitsMutex.Lock() defer cacheStatistic.cacheHitsMutex.Unlock() if cacheHit { cacheStatistic.cacheHits++ } else { cacheStatistic.cacheMiss++ } } // StateHandler handler function for sta func StateHandler(c *gin.Context) { c.Header("Access-Control-Allow-Origin", "*") clientResponseData := &clientResponse{} clientResponseData.StartTime = serverStartTime cacheStatistic.cacheHitsMutex.Lock() clientResponseData.TotalHits = cacheStatistic.totalHits clientResponseData.CacheHits = cacheStatistic.cacheHits clientResponseData.CacheMiss = cacheStatistic.cacheMiss cacheStatistic.cacheHitsMutex.Unlock() groupMutex.Lock() current := time.Now() if current.Unix() > nextGroup { tmp := time.Unix(currentGroup, 0) for { tmp = tmp.Add(nextTime) if tmp.Unix() >= current.Unix() { break } groupName = append(groupName, tmp.Unix()) groupHits = append(groupHits, 0) currentGroup = tmp.Unix() nextGroup = tmp.Add(nextTime).Unix() } } for i, name := range groupName { gr := groupResponse{} // gr.GroupTime = int64(time.Unix(name, 0).Second()) gr.GroupTime = time.Unix(name, 0).String() gr.Hits = groupHits[i] clientResponseData.GroupReport = append(clientResponseData.GroupReport, gr) } if len(clientResponseData.GroupReport) > 10 { clientResponseData.GroupReport = clientResponseData.GroupReport[len(clientResponseData.GroupReport)-10:] } groupMutex.Unlock() clientResponseData.ServicesState = stateCache c.JSON(http.StatusOK, clientResponseData) }