You've already forked openaccounting-server
mirror of
https://github.com/openaccounting/oa-server.git
synced 2025-12-09 09:00:42 +13:00
130 lines
3.6 KiB
Go
130 lines
3.6 KiB
Go
package rest
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// StatusMiddleware keeps track of various stats about the processed requests.
|
|
// It depends on request.Env["STATUS_CODE"] and request.Env["ELAPSED_TIME"],
|
|
// recorderMiddleware and timerMiddleware must be in the wrapped middlewares.
|
|
type StatusMiddleware struct {
|
|
lock sync.RWMutex
|
|
start time.Time
|
|
pid int
|
|
responseCounts map[string]int
|
|
totalResponseTime time.Time
|
|
}
|
|
|
|
// MiddlewareFunc makes StatusMiddleware implement the Middleware interface.
|
|
func (mw *StatusMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc {
|
|
|
|
mw.start = time.Now()
|
|
mw.pid = os.Getpid()
|
|
mw.responseCounts = map[string]int{}
|
|
mw.totalResponseTime = time.Time{}
|
|
|
|
return func(w ResponseWriter, r *Request) {
|
|
|
|
// call the handler
|
|
h(w, r)
|
|
|
|
if r.Env["STATUS_CODE"] == nil {
|
|
log.Fatal("StatusMiddleware: Env[\"STATUS_CODE\"] is nil, " +
|
|
"RecorderMiddleware may not be in the wrapped Middlewares.")
|
|
}
|
|
statusCode := r.Env["STATUS_CODE"].(int)
|
|
|
|
if r.Env["ELAPSED_TIME"] == nil {
|
|
log.Fatal("StatusMiddleware: Env[\"ELAPSED_TIME\"] is nil, " +
|
|
"TimerMiddleware may not be in the wrapped Middlewares.")
|
|
}
|
|
responseTime := r.Env["ELAPSED_TIME"].(*time.Duration)
|
|
|
|
mw.lock.Lock()
|
|
mw.responseCounts[fmt.Sprintf("%d", statusCode)]++
|
|
mw.totalResponseTime = mw.totalResponseTime.Add(*responseTime)
|
|
mw.lock.Unlock()
|
|
}
|
|
}
|
|
|
|
// Status contains stats and status information. It is returned by GetStatus.
|
|
// These information can be made available as an API endpoint, see the "status"
|
|
// example to install the following status route.
|
|
// GET /.status returns something like:
|
|
//
|
|
// {
|
|
// "Pid": 21732,
|
|
// "UpTime": "1m15.926272s",
|
|
// "UpTimeSec": 75.926272,
|
|
// "Time": "2013-03-04 08:00:27.152986 +0000 UTC",
|
|
// "TimeUnix": 1362384027,
|
|
// "StatusCodeCount": {
|
|
// "200": 53,
|
|
// "404": 11
|
|
// },
|
|
// "TotalCount": 64,
|
|
// "TotalResponseTime": "16.777ms",
|
|
// "TotalResponseTimeSec": 0.016777,
|
|
// "AverageResponseTime": "262.14us",
|
|
// "AverageResponseTimeSec": 0.00026214
|
|
// }
|
|
type Status struct {
|
|
Pid int
|
|
UpTime string
|
|
UpTimeSec float64
|
|
Time string
|
|
TimeUnix int64
|
|
StatusCodeCount map[string]int
|
|
TotalCount int
|
|
TotalResponseTime string
|
|
TotalResponseTimeSec float64
|
|
AverageResponseTime string
|
|
AverageResponseTimeSec float64
|
|
}
|
|
|
|
// GetStatus computes and returns a Status object based on the request informations accumulated
|
|
// since the start of the process.
|
|
func (mw *StatusMiddleware) GetStatus() *Status {
|
|
|
|
mw.lock.RLock()
|
|
|
|
now := time.Now()
|
|
|
|
uptime := now.Sub(mw.start)
|
|
|
|
totalCount := 0
|
|
for _, count := range mw.responseCounts {
|
|
totalCount += count
|
|
}
|
|
|
|
totalResponseTime := mw.totalResponseTime.Sub(time.Time{})
|
|
|
|
averageResponseTime := time.Duration(0)
|
|
if totalCount > 0 {
|
|
avgNs := int64(totalResponseTime) / int64(totalCount)
|
|
averageResponseTime = time.Duration(avgNs)
|
|
}
|
|
|
|
status := &Status{
|
|
Pid: mw.pid,
|
|
UpTime: uptime.String(),
|
|
UpTimeSec: uptime.Seconds(),
|
|
Time: now.String(),
|
|
TimeUnix: now.Unix(),
|
|
StatusCodeCount: mw.responseCounts,
|
|
TotalCount: totalCount,
|
|
TotalResponseTime: totalResponseTime.String(),
|
|
TotalResponseTimeSec: totalResponseTime.Seconds(),
|
|
AverageResponseTime: averageResponseTime.String(),
|
|
AverageResponseTimeSec: averageResponseTime.Seconds(),
|
|
}
|
|
|
|
mw.lock.RUnlock()
|
|
|
|
return status
|
|
}
|