Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: add request handling statistics for pouch daemon #2037

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions apis/server/response_stats.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package server

import "sync"

// RequestStats is the request dealing result,
// including all handled request number, 2xx3xx number, 4xx number and 5xx number
type RequestStats struct {
sync.Mutex
// req5xxCount is the count number of failed request which returns a status code of 5xx.
req5xxCount uint64
// req4xxCount is the count number of failed request which returns a status code of 5xx.
req4xxCount uint64
// req2xxCount is the count number of requests which returns a status code of 2xx and 3xx.
req2xx3xxCount uint64
// reqCount is the count number of all request.
reqCount uint64
}

func (rs *RequestStats) getAllCount() uint64 {
rs.Lock()
defer rs.Unlock()
return rs.reqCount
}

func (rs *RequestStats) get2xx3xxCount() uint64 {
rs.Lock()
defer rs.Unlock()
return rs.req2xx3xxCount
}

func (rs *RequestStats) get4xxCount() uint64 {
rs.Lock()
defer rs.Unlock()
return rs.req4xxCount
}

func (rs *RequestStats) get5xxCount() uint64 {
rs.Lock()
defer rs.Unlock()
return rs.req5xxCount
}

func (rs *RequestStats) increaseReqCount() {
rs.Lock()
rs.reqCount++
rs.Unlock()
}

func (rs *RequestStats) increase2xx3xxCount() {
rs.Lock()
rs.req2xx3xxCount++
rs.Unlock()
}

func (rs *RequestStats) increase4xxCount() {
rs.Lock()
rs.req4xxCount++
rs.Unlock()
}

func (rs *RequestStats) increase5xxCount() {
rs.Lock()
rs.req5xxCount++
rs.Unlock()
}
27 changes: 27 additions & 0 deletions apis/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,24 @@ import (
// versionMatcher defines to parse version url path.
const versionMatcher = "/v{version:[0-9.]+}"

// reqStats is used to calculate the request dealing status.
var reqStats = &RequestStats{}

func initRoute(s *Server) http.Handler {
r := mux.NewRouter()

// system
s.addRoute(r, http.MethodGet, "/_ping", s.ping)
s.addRoute(r, http.MethodGet, "/info", s.info)
s.addRoute(r, http.MethodGet, "/version", s.version)
s.addRoute(r, http.MethodGet, "/stats", func(context context.Context, rw http.ResponseWriter, req *http.Request) (err error) {
return EncodeResponse(rw, http.StatusOK, types.ResponseStats{
AllRequests: reqStats.getAllCount(),
Req2xx3xxCount: reqStats.get2xx3xxCount(),
Req4xxCount: reqStats.get4xxCount(),
Req5xxCount: reqStats.get5xxCount(),
})
})
s.addRoute(r, http.MethodPost, "/auth", s.auth)
s.addRoute(r, http.MethodGet, "/events", withCancelHandler(s.events))

Expand Down Expand Up @@ -205,9 +216,13 @@ func filter(handler handler, s *Server) http.HandlerFunc {
logrus.Debugf("Calling %s %s, client %s", req.Method, req.URL.RequestURI(), clientInfo)
}

// increase the request number by 1.
reqStats.increaseReqCount()

// Start to handle request.
err := handler(ctx, w, req)
if err == nil {
reqStats.increase2xx3xxCount()
return
}
// Handle error if request handling fails.
Expand Down Expand Up @@ -247,6 +262,8 @@ func HandleErrorResponse(w http.ResponseWriter, err error) {
code = http.StatusNotModified
}

calReqStatictics(code)

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
enc := json.NewEncoder(w)
Expand All @@ -257,3 +274,13 @@ func HandleErrorResponse(w http.ResponseWriter, err error) {
}
enc.Encode(resp)
}

// calReqStatictics will increase the 4xx count and 5xx count.
func calReqStatictics(code int) {
if code >= http.StatusInternalServerError {
reqStats.increase5xxCount()
}
if code >= http.StatusBadRequest && code < http.StatusInternalServerError {
reqStats.increase4xxCount()
}
}
35 changes: 35 additions & 0 deletions apis/swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,20 @@ paths:
schema:
$ref: "#/definitions/AuthConfig"

/stats:
get:
summary: "Get daemon's request dealing result, including all handled request number, 2xx3xx number, 4xx number and 5xx number"
description: "Get daemon's request dealing result, including all handled request number, 2xx3xx number, 4xx number and 5xx number"
consumes:
- "application/json"
produces:
- "application/json"
responses:
200:
description: "The request handling stats have returned"
schema:
$ref: "#/definitions/ResponseStats"

/daemon/update:
post:
summary: "Update daemon's labels and image proxy"
Expand Down Expand Up @@ -1805,6 +1819,27 @@ definitions:
example:
- ["unix:///var/run/pouchd.sock", "tcp://0.0.0.0:4243"]

ResponseStats:
type: "object"
description: ResponseStats contains all request handling result in daemon including 2xx3xx response number, 4xx and 5xx number.
properties:
AllRequests:
description: all requests number handled by daemon no matter success or failure.
type: "integer"
format: "uint64"
req2xx3xxCount:
description: all response number returned by daemon which is 2xx or 3xx status code.
type: "integer"
format: "uint64"
Req4xxCount:
description: all response number returned by daemon which is 4xx status code.
type: "integer"
format: "uint64"
Req5xxCount:
description: all response number returned by daemon which is 5xx status code.
type: "integer"
format: "uint64"

DaemonUpdateConfig:
type: "object"
properties:
Expand Down
67 changes: 67 additions & 0 deletions apis/types/response_stats.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions test/api_system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,24 @@ func (suite *APISystemSuite) TestRegistryLogin(c *check.C) {
request.DecodeBody(authResp, resp.Body)
c.Assert(util.PartialEqual(authResp.Status, "Login Succeeded"), check.IsNil)
}

// TestStats tests /stats API.
func (suite *APISystemSuite) TestStats(c *check.C) {
resp, err := request.Get("/stats")
c.Assert(err, check.IsNil)
defer resp.Body.Close()

CheckRespStatus(c, resp, 200)

got := types.ResponseStats{}
err = json.NewDecoder(resp.Body).Decode(&got)
c.Assert(err, check.IsNil)

if got.AllRequests <= 1 {
c.Fatalf("daemon handling request should be more than 1, actual: %d", got.AllRequests)
}

if got.Req2xx3xxCount <= 1 {
c.Fatalf("daemon handling request should be more than 0, actual: %d", got.Req2xx3xxCount)
}
}