You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by to...@apache.org on 2020/12/11 01:49:35 UTC
[apisix-dashboard] branch master updated: feat: add access log for
Manager API (#994)
This is an automated email from the ASF dual-hosted git repository.
tokers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git
The following commit(s) were added to refs/heads/master by this push:
new 64cd555 feat: add access log for Manager API (#994)
64cd555 is described below
commit 64cd555d8acdcc111a65ef1a00f1f20980a9f259
Author: nic-chen <33...@users.noreply.github.com>
AuthorDate: Fri Dec 11 09:49:07 2020 +0800
feat: add access log for Manager API (#994)
* feat: access log
* feat: access log
* chore: access log format
* chore: access log format
* test: add test case for access log
* chore: add access log example
* fix: according to review
* test: add unit test for `logging` middleware
* fix: license checker CI failed
---
api/conf/conf.go | 21 ++++++++++--
api/conf/conf.yaml | 5 +++
api/filter/logging.go | 51 +++++++++++++++++++++++++++++-
api/filter/{logging.go => logging_test.go} | 29 ++++++++++++++++-
api/internal/route.go | 4 ++-
api/log/log.go | 7 ++++
api/log/zap.go | 33 ++++++++++++++-----
api/main.go | 2 +-
api/test/shell/cli_test.sh | 18 +++++++++--
9 files changed, 154 insertions(+), 16 deletions(-)
diff --git a/api/conf/conf.go b/api/conf/conf.go
index 578fcbd..b34c339 100644
--- a/api/conf/conf.go
+++ b/api/conf/conf.go
@@ -48,6 +48,7 @@ var (
ETCDConfig *Etcd
ErrorLogLevel = "warn"
ErrorLogPath = "logs/error.log"
+ AccessLogPath = "logs/access.log"
UserList = make(map[string]User, 2)
AuthConf Authentication
SSLDefaultStatus = 1 //enable ssl by default
@@ -69,8 +70,13 @@ type ErrorLog struct {
FilePath string `yaml:"file_path"`
}
+type AccessLog struct {
+ FilePath string `yaml:"file_path"`
+}
+
type Log struct {
- ErrorLog ErrorLog `yaml:"error_log"`
+ ErrorLog ErrorLog `yaml:"error_log"`
+ AccessLog AccessLog `yaml:"access_log"`
}
type Conf struct {
@@ -143,7 +149,18 @@ func setConf() {
ErrorLogPath = config.Conf.Log.ErrorLog.FilePath
}
if !filepath.IsAbs(ErrorLogPath) {
- ErrorLogPath, err = filepath.Abs(WorkDir + "/" + ErrorLogPath)
+ ErrorLogPath, err = filepath.Abs(filepath.Join(WorkDir, ErrorLogPath))
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ // access log
+ if config.Conf.Log.AccessLog.FilePath != "" {
+ AccessLogPath = config.Conf.Log.AccessLog.FilePath
+ }
+ if !filepath.IsAbs(AccessLogPath) {
+ AccessLogPath, err = filepath.Abs(filepath.Join(WorkDir, AccessLogPath))
if err != nil {
panic(err)
}
diff --git a/api/conf/conf.yaml b/api/conf/conf.yaml
index 7f147cb..802b11d 100644
--- a/api/conf/conf.yaml
+++ b/api/conf/conf.yaml
@@ -32,6 +32,11 @@ conf:
file_path:
logs/error.log # supports relative path, absolute path, standard output
# such as: logs/error.log, /tmp/logs/error.log, /dev/stdout, /dev/stderr
+ access_log:
+ file_path:
+ logs/access.log # supports relative path, absolute path, standard output
+ # such as: logs/access.log, /tmp/logs/access.log, /dev/stdout, /dev/stderr
+ # log example: 2020-12-09T16:38:09.039+0800 INFO filter/logging.go:46 /apisix/admin/routes/r1 {"status": 401, "host": "127.0.0.1:9000", "query": "asdfsafd=adf&a=a", "requestId": "3d50ecb8-758c-46d1-af5b-cd9d1c820156", "latency": 0, "remoteIP": "127.0.0.1", "method": "PUT", "errs": []}
authentication:
secret:
secret # secret for jwt token generation.
diff --git a/api/filter/logging.go b/api/filter/logging.go
index 328ac4d..0a01f6a 100644
--- a/api/filter/logging.go
+++ b/api/filter/logging.go
@@ -16,4 +16,53 @@
*/
package filter
-//for logging access log, will refactor it in a new pr.
+import (
+ "bytes"
+ "time"
+
+ "github.com/gin-gonic/gin"
+ "go.uber.org/zap"
+)
+
+func RequestLogHandler(logger *zap.SugaredLogger) gin.HandlerFunc {
+ return func(c *gin.Context) {
+ start, host, remoteIP, path, method := time.Now(), c.Request.Host, c.ClientIP(), c.Request.URL.Path, c.Request.Method
+ query := c.Request.URL.RawQuery
+ requestId := c.Writer.Header().Get("X-Request-Id")
+
+ blw := &bodyLogWriter{body: bytes.NewBuffer(nil), ResponseWriter: c.Writer}
+ c.Writer = blw
+ c.Next()
+ latency := time.Since(start) / 1000000
+ statusCode := c.Writer.Status()
+ //respBody := blw.body.String()
+
+ var errs []string
+ for _, err := range c.Errors {
+ errs = append(errs, err.Error())
+ }
+
+ logger.Desugar().Info(path,
+ //zap.String("path", path),
+ zap.Int("status", statusCode),
+ zap.String("host", host),
+ zap.String("query", query),
+ zap.String("requestId", requestId),
+ zap.Duration("latency", latency),
+ zap.String("remoteIP", remoteIP),
+ zap.String("method", method),
+ //zap.String("respBody", respBody),
+ zap.Strings("errs", errs),
+ )
+ }
+}
+
+type bodyLogWriter struct {
+ gin.ResponseWriter
+ body *bytes.Buffer
+}
+
+func (w bodyLogWriter) Write(b []byte) (int, error) {
+ w.body.Write(b)
+ return w.ResponseWriter.Write(b)
+}
diff --git a/api/filter/logging.go b/api/filter/logging_test.go
similarity index 53%
copy from api/filter/logging.go
copy to api/filter/logging_test.go
index 328ac4d..087d8b0 100644
--- a/api/filter/logging.go
+++ b/api/filter/logging_test.go
@@ -16,4 +16,31 @@
*/
package filter
-//for logging access log, will refactor it in a new pr.
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/gin-gonic/gin"
+ "github.com/stretchr/testify/assert"
+
+ "github.com/apisix/manager-api/log"
+)
+
+func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
+ req := httptest.NewRequest(method, path, nil)
+ w := httptest.NewRecorder()
+ r.ServeHTTP(w, req)
+ return w
+}
+
+func TestRequestLogHandler(t *testing.T) {
+ r := gin.New()
+ logger := log.GetLogger(log.AccessLog)
+ r.Use(RequestLogHandler(logger))
+ r.GET("/", func(c *gin.Context) {
+ })
+
+ w := performRequest(r, "GET", "/")
+ assert.Equal(t, 200, w.Code)
+}
diff --git a/api/internal/route.go b/api/internal/route.go
index 04a721f..83a3e72 100644
--- a/api/internal/route.go
+++ b/api/internal/route.go
@@ -35,6 +35,7 @@ import (
"github.com/apisix/manager-api/internal/handler/service"
"github.com/apisix/manager-api/internal/handler/ssl"
"github.com/apisix/manager-api/internal/handler/upstream"
+ "github.com/apisix/manager-api/log"
)
func SetUpRouter() *gin.Engine {
@@ -44,9 +45,10 @@ func SetUpRouter() *gin.Engine {
gin.SetMode(gin.ReleaseMode)
}
r := gin.New()
+ logger := log.GetLogger(log.AccessLog)
store := cookie.NewStore([]byte("secret"))
r.Use(sessions.Sessions("session", store))
- r.Use(filter.CORS(), filter.Authentication(), filter.RequestId(), filter.RecoverHandler())
+ r.Use(filter.CORS(), filter.RequestId(), filter.RequestLogHandler(logger), filter.Authentication(), filter.RecoverHandler())
r.Use(static.Serve("/", static.LocalFile(conf.WebDir, false)))
r.NoRoute(func(c *gin.Context) {
c.File(fmt.Sprintf("%s/index.html", conf.WebDir))
diff --git a/api/log/log.go b/api/log/log.go
index 3c53a96..43bb609 100644
--- a/api/log/log.go
+++ b/api/log/log.go
@@ -20,6 +20,13 @@ var (
DefLogger Interface = emptyLog{}
)
+type Type int8
+
+const (
+ AccessLog Type = iota - 1
+ ErrorLog
+)
+
type emptyLog struct {
}
diff --git a/api/log/zap.go b/api/log/zap.go
index 5319072..66379d8 100644
--- a/api/log/zap.go
+++ b/api/log/zap.go
@@ -28,14 +28,22 @@ import (
var logger *zap.SugaredLogger
func init() {
- writeSyncer := fileWriter()
- encoder := getEncoder()
+ logger = GetLogger(ErrorLog)
+}
+
+func GetLogger(logType Type) *zap.SugaredLogger {
+ writeSyncer := fileWriter(logType)
+ encoder := getEncoder(logType)
logLevel := getLogLevel()
+ if logType == AccessLog {
+ logLevel = zapcore.InfoLevel
+ }
+
core := zapcore.NewCore(encoder, writeSyncer, logLevel)
zapLogger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(2))
- logger = zapLogger.Sugar()
+ return zapLogger.Sugar()
}
func getLogLevel() zapcore.LevelEnabler {
@@ -57,23 +65,32 @@ func getLogLevel() zapcore.LevelEnabler {
return level
}
-func getEncoder() zapcore.Encoder {
+func getEncoder(logType Type) zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
+
+ if logType == AccessLog {
+ encoderConfig.LevelKey = zapcore.OmitKey
+ }
+
return zapcore.NewConsoleEncoder(encoderConfig)
}
-func fileWriter() zapcore.WriteSyncer {
+func fileWriter(logType Type) zapcore.WriteSyncer {
+ logPath := conf.ErrorLogPath
+ if logType == AccessLog {
+ logPath = conf.AccessLogPath
+ }
//standard output
- if conf.ErrorLogPath == "/dev/stdout" {
+ if logPath == "/dev/stdout" {
return zapcore.Lock(os.Stdout)
}
- if conf.ErrorLogPath == "/dev/stderr" {
+ if logPath == "/dev/stderr" {
return zapcore.Lock(os.Stderr)
}
- writer, _, err := zap.Open(conf.ErrorLogPath)
+ writer, _, err := zap.Open(logPath)
if err != nil {
panic(err)
}
diff --git a/api/main.go b/api/main.go
index ac42689..48fb6a8 100644
--- a/api/main.go
+++ b/api/main.go
@@ -25,13 +25,13 @@ import (
"syscall"
"time"
- "github.com/apisix/manager-api/internal/handler"
"github.com/shiningrush/droplet"
"github.com/apisix/manager-api/conf"
"github.com/apisix/manager-api/internal"
"github.com/apisix/manager-api/internal/core/storage"
"github.com/apisix/manager-api/internal/core/store"
+ "github.com/apisix/manager-api/internal/handler"
"github.com/apisix/manager-api/internal/utils"
"github.com/apisix/manager-api/log"
)
diff --git a/api/test/shell/cli_test.sh b/api/test/shell/cli_test.sh
index dabcd65..76d313d 100755
--- a/api/test/shell/cli_test.sh
+++ b/api/test/shell/cli_test.sh
@@ -41,7 +41,7 @@ trap clean_up EXIT
export GO111MODULE=on
go build -o ./manager-api .
-#default level: warn, path: logs/error.log
+# default level: warn, path: logs/error.log
./manager-api &
sleep 3
@@ -79,7 +79,7 @@ fi
clean_logfile
-#change path
+# change path
sed -i 's/logs\/error.log/.\/error.log/' conf/conf.yaml
@@ -113,6 +113,20 @@ fi
# clean config
clean_up
+# access log test
+./manager-api &
+sleep 3
+
+curl http://127.0.0.1:9000/apisix/admin/user/login -d '{"username":"admin", "password": "admin"}'
+
+pkill -f manager-api
+
+if [[ `grep -c "/apisix/admin/user/login" ./logs/access.log` -eq '0' ]]; then
+ echo "failed: failed to write access log"
+ exit 1
+fi
+
+
# etcd basic auth
# add root user
curl -L http://localhost:2379/v3/auth/user/add -d '{"name": "root", "password": "root"}'