mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-19 12:36:34 +00:00
Feat: add request logging for the apiserver (#3012)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
This commit is contained in:
@@ -37,6 +37,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/datastore/mongodb"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/log"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/usecase"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/webservice"
|
||||
)
|
||||
|
||||
@@ -190,6 +191,9 @@ func (s *restServer) RegisterServices() restfulspec.Config {
|
||||
// Add container filter to respond to OPTIONS
|
||||
s.webContainer.Filter(s.webContainer.OPTIONSFilter)
|
||||
|
||||
// Add request log
|
||||
s.webContainer.Filter(s.requestLog)
|
||||
|
||||
// Regist all custom webservice
|
||||
for _, handler := range webservice.GetRegisteredWebService() {
|
||||
s.webContainer.Add(handler.GetWebService())
|
||||
@@ -203,6 +207,22 @@ func (s *restServer) RegisterServices() restfulspec.Config {
|
||||
return config
|
||||
}
|
||||
|
||||
func (s *restServer) requestLog(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
|
||||
start := time.Now()
|
||||
c := utils.NewResponseCapture(resp.ResponseWriter)
|
||||
resp.ResponseWriter = c
|
||||
chain.ProcessFilter(req, resp)
|
||||
takeTime := time.Since(start)
|
||||
log.Logger.With(
|
||||
"clientIP", utils.ClientIP(req.Request),
|
||||
"path", req.Request.URL.Path,
|
||||
"method", req.Request.Method,
|
||||
"status", c.StatusCode(),
|
||||
"time", takeTime.String(),
|
||||
"responseSize", len(c.Bytes()),
|
||||
).Infof("request log")
|
||||
}
|
||||
|
||||
func enrichSwaggerObject(swo *spec.Swagger) {
|
||||
swo.Info = &spec.Info{
|
||||
InfoProps: spec.InfoProps{
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Copyright 2021 The KubeVela 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 utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ClientIP get client ip
|
||||
func ClientIP(r *http.Request) string {
|
||||
xForwardedFor := r.Header.Get("X-Forwarded-For")
|
||||
ip := strings.TrimSpace(strings.Split(xForwardedFor, ",")[0])
|
||||
if ip != "" {
|
||||
return ip
|
||||
}
|
||||
|
||||
ip = strings.TrimSpace(r.Header.Get("X-Real-Ip"))
|
||||
if ip != "" {
|
||||
return ip
|
||||
}
|
||||
|
||||
if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil {
|
||||
return ip
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// ResponseCapture capture response and get response info
|
||||
type ResponseCapture struct {
|
||||
http.ResponseWriter
|
||||
wroteHeader bool
|
||||
status int
|
||||
body *bytes.Buffer
|
||||
}
|
||||
|
||||
// NewResponseCapture new response capture
|
||||
func NewResponseCapture(w http.ResponseWriter) *ResponseCapture {
|
||||
return &ResponseCapture{
|
||||
ResponseWriter: w,
|
||||
wroteHeader: false,
|
||||
body: new(bytes.Buffer),
|
||||
}
|
||||
}
|
||||
|
||||
// Header return response writer header
|
||||
func (c ResponseCapture) Header() http.Header {
|
||||
return c.ResponseWriter.Header()
|
||||
}
|
||||
|
||||
// Write write data to response writer and body
|
||||
func (c ResponseCapture) Write(data []byte) (int, error) {
|
||||
if !c.wroteHeader {
|
||||
c.WriteHeader(http.StatusOK)
|
||||
}
|
||||
c.body.Write(data)
|
||||
return c.ResponseWriter.Write(data)
|
||||
}
|
||||
|
||||
// WriteHeader write header to response writer
|
||||
func (c *ResponseCapture) WriteHeader(statusCode int) {
|
||||
c.status = statusCode
|
||||
c.wroteHeader = true
|
||||
c.ResponseWriter.WriteHeader(statusCode)
|
||||
}
|
||||
|
||||
// Bytes return response body bytes
|
||||
func (c ResponseCapture) Bytes() []byte {
|
||||
return c.body.Bytes()
|
||||
}
|
||||
|
||||
// StatusCode return status code
|
||||
func (c ResponseCapture) StatusCode() int {
|
||||
return c.status
|
||||
}
|
||||
Reference in New Issue
Block a user