improve logger feautre, add unit testing cases for ghttp.Server; add SetDefaultLogger function for glog

This commit is contained in:
John
2020-01-21 15:42:08 +08:00
parent 2ba0913bea
commit 202419202f
12 changed files with 107 additions and 41 deletions

View File

@ -434,13 +434,13 @@ func (s *Server) GetRouterArray() []RouterItem {
// Run starts server listening in blocking way.
func (s *Server) Run() {
if err := s.Start(); err != nil {
glog.Fatal(err)
s.Logger().Fatal(err)
}
// Blocking using channel.
<-s.closeChan
glog.Printf("[ghttp] %d: all servers shutdown", gproc.Pid())
s.Logger().Printf("[ghttp] %d: all servers shutdown", gproc.Pid())
}
// Wait blocks to wait for all servers done.
@ -542,7 +542,7 @@ func (s *Server) startServer(fdMap listenerFdMap) {
}
// 如果非关闭错误,那么提示报错,否则认为是正常的服务关闭操作
if err != nil && !strings.EqualFold(http.ErrServerClosed.Error(), err.Error()) {
glog.Fatal(err)
s.Logger().Fatal(err)
}
// 如果所有异步的http.Server都已经停止那么WebServer就可以退出了
if s.serverCount.Add(-1) < 1 {

View File

@ -206,7 +206,7 @@ func (s *Server) EnableHTTPS(certFile, keyFile string, tlsConfig ...*tls.Config)
}
}
if certFileRealPath == "" {
glog.Fatal(fmt.Sprintf(`[ghttp] EnableHTTPS failed: certFile "%s" does not exist`, certFile))
s.Logger().Fatal(fmt.Sprintf(`[ghttp] EnableHTTPS failed: certFile "%s" does not exist`, certFile))
}
keyFileRealPath := gfile.RealPath(keyFile)
if keyFileRealPath == "" {
@ -216,7 +216,7 @@ func (s *Server) EnableHTTPS(certFile, keyFile string, tlsConfig ...*tls.Config)
}
}
if keyFileRealPath == "" {
glog.Fatal(fmt.Sprintf(`[ghttp] EnableHTTPS failed: keyFile "%s" does not exist`, keyFile))
s.Logger().Fatal(fmt.Sprintf(`[ghttp] EnableHTTPS failed: keyFile "%s" does not exist`, keyFile))
}
s.config.HTTPSCertPath = certFileRealPath
s.config.HTTPSKeyPath = keyFileRealPath

View File

@ -16,7 +16,6 @@ import (
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/os/glog"
"github.com/gogf/gf/util/gconv"
)
@ -54,12 +53,12 @@ func (s *Server) SetServerRoot(root string) {
realPath := root
if !gres.Contains(realPath) {
if p, err := gfile.Search(root); err != nil {
glog.Fatal(fmt.Sprintf(`[ghttp] SetServerRoot failed: %v`, err))
s.Logger().Fatal(fmt.Sprintf(`[ghttp] SetServerRoot failed: %v`, err))
} else {
realPath = p
}
}
glog.Debug("[ghttp] SetServerRoot path:", realPath)
s.Logger().Debug("[ghttp] SetServerRoot path:", realPath)
s.config.SearchPaths = []string{strings.TrimRight(realPath, gfile.Separator)}
s.config.FileServerEnabled = true
}
@ -69,7 +68,7 @@ func (s *Server) AddSearchPath(path string) {
realPath := path
if !gres.Contains(realPath) {
if p, err := gfile.Search(path); err != nil {
glog.Fatal(fmt.Sprintf(`[ghttp] AddSearchPath failed: %v`, err))
s.Logger().Fatal(fmt.Sprintf(`[ghttp] AddSearchPath failed: %v`, err))
} else {
realPath = p
}
@ -83,7 +82,7 @@ func (s *Server) AddStaticPath(prefix string, path string) {
realPath := path
if !gres.Contains(realPath) {
if p, err := gfile.Search(path); err != nil {
glog.Fatal(fmt.Sprintf(`[ghttp] AddStaticPath failed: %v`, err))
s.Logger().Fatal(fmt.Sprintf(`[ghttp] AddStaticPath failed: %v`, err))
} else {
realPath = p
}

View File

@ -11,7 +11,6 @@ import (
"crypto/tls"
"errors"
"fmt"
"github.com/gogf/gf/os/glog"
"github.com/gogf/gf/os/gproc"
"log"
"net"
@ -21,6 +20,7 @@ import (
// 优雅的Web Server对象封装
type gracefulServer struct {
server *Server // Belonged server.
fd uintptr // 热重启时传递的socket监听文件句柄
itemFunc string // 监听地址信息
httpServer *http.Server // 底层http.Server
@ -33,6 +33,7 @@ type gracefulServer struct {
// 创建一个优雅的Http Server
func (s *Server) newGracefulServer(itemFunc string, fd ...int) *gracefulServer {
gs := &gracefulServer{
server: s,
itemFunc: itemFunc,
httpServer: s.newHttpServer(itemFunc),
}
@ -133,7 +134,7 @@ func (s *gracefulServer) doServe() error {
if s.fd != 0 {
action = "reloaded"
}
glog.Printf("%d: %s server %s listening on [%s]", gproc.Pid(), s.getProto(), action, s.itemFunc)
s.server.Logger().Printf("%d: %s server %s listening on [%s]", gproc.Pid(), s.getProto(), action, s.itemFunc)
s.status = SERVER_STATUS_RUNNING
err := s.httpServer.Serve(s.listener)
s.status = SERVER_STATUS_STOPPED
@ -166,7 +167,7 @@ func (s *gracefulServer) shutdown() {
return
}
if err := s.httpServer.Shutdown(context.Background()); err != nil {
glog.Errorf("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.itemFunc, err)
s.server.Logger().Errorf("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.itemFunc, err)
}
}
@ -176,6 +177,6 @@ func (s *gracefulServer) close() {
return
}
if err := s.httpServer.Close(); err != nil {
glog.Errorf("%d: %s server [%s] closed error: %v", gproc.Pid(), s.getProto(), s.itemFunc, err)
s.server.Logger().Errorf("%d: %s server [%s] closed error: %v", gproc.Pid(), s.getProto(), s.itemFunc, err)
}
}

View File

@ -9,12 +9,18 @@ package ghttp
import (
"fmt"
"github.com/gogf/gf/errors/gerror"
"github.com/gogf/gf/os/glog"
)
const (
gPATH_FILTER_KEY = "github.com/gogf/gf/"
)
// Logger returns the logger of the server.
func (s *Server) Logger() *glog.Logger {
return s.config.Logger
}
// 处理服务错误信息主要是panichttp请求的status由access log进行管理
func (s *Server) handleAccessLog(r *Request) {
if !s.IsAccessLogEnabled() {
@ -24,7 +30,7 @@ func (s *Server) handleAccessLog(r *Request) {
if r.TLS != nil {
scheme = "https"
}
s.config.Logger.File(s.config.AccessLogPattern).
s.Logger().File(s.config.AccessLogPattern).
Stdout(s.config.LogStdout).
Printf(
`%d "%s %s %s %s %s" %.3f, %s, "%s", "%s"`,
@ -60,7 +66,7 @@ func (s *Server) handleErrorLog(err error, r *Request) {
Error(content)
return
}
s.config.Logger.File(s.config.AccessLogPattern).
s.Logger().File(s.config.AccessLogPattern).
Stack(s.config.ErrorStack).
StackWithFilter(gPATH_FILTER_KEY).
Stdout(s.config.LogStdout).

View File

@ -6,8 +6,6 @@
package ghttp
import "github.com/gogf/gf/os/glog"
// Plugin is the interface for server plugin.
type Plugin interface {
Install(s *Server) error
@ -18,7 +16,7 @@ type Plugin interface {
func (s *Server) Plugin(plugin ...Plugin) {
for _, p := range plugin {
if err := p.Install(s); err != nil {
glog.Fatal(err)
s.Logger().Fatal(err)
}
}
}

View File

@ -15,7 +15,6 @@ import (
"github.com/gogf/gf/debug/gdebug"
"github.com/gogf/gf/container/glist"
"github.com/gogf/gf/os/glog"
"github.com/gogf/gf/text/gregex"
"github.com/gogf/gf/text/gstr"
)
@ -63,11 +62,11 @@ func (s *Server) setHandler(pattern string, handler *handlerItem) {
handler.itemId = handlerIdGenerator.Add(1)
domain, method, uri, err := s.parsePattern(pattern)
if err != nil {
glog.Fatal("invalid pattern:", pattern, err)
s.Logger().Fatal("invalid pattern:", pattern, err)
return
}
if len(uri) == 0 || uri[0] != '/' {
glog.Fatal("invalid pattern:", pattern, "URI should lead with '/'")
s.Logger().Fatal("invalid pattern:", pattern, "URI should lead with '/'")
return
}
// 注册地址记录及重复注册判断
@ -76,7 +75,7 @@ func (s *Server) setHandler(pattern string, handler *handlerItem) {
switch handler.itemType {
case gHANDLER_TYPE_HANDLER, gHANDLER_TYPE_OBJECT, gHANDLER_TYPE_CONTROLLER:
if item, ok := s.routesMap[regKey]; ok {
glog.Fatalf(`duplicated route registry "%s", already registered at %s`, pattern, item[0].file)
s.Logger().Fatalf(`duplicated route registry "%s", already registered at %s`, pattern, item[0].file)
return
}
}

View File

@ -12,7 +12,6 @@ import (
"github.com/gogf/gf/text/gstr"
"github.com/gogf/gf/os/glog"
"github.com/gogf/gf/util/gconv"
)
@ -139,7 +138,7 @@ func (g *RouterGroup) Bind(items []GroupItem) *RouterGroup {
group := g.Clone()
for _, item := range items {
if len(item) < 3 {
glog.Fatalf("invalid router item: %s", item)
g.server.Logger().Fatalf("invalid router item: %s", item)
}
bindType := gstr.ToUpper(gconv.String(item[0]))
switch bindType {
@ -259,7 +258,7 @@ func (g *RouterGroup) doBind(bindType string, pattern string, object interface{}
if len(prefix) > 0 {
domain, method, path, err := g.server.parsePattern(pattern)
if err != nil {
glog.Fatalf("invalid pattern: %s", pattern)
g.server.Logger().Fatalf("invalid pattern: %s", pattern)
}
// If there'a already a domain, unset the domain field in the pattern.
if g.domain != nil {
@ -338,7 +337,7 @@ func (g *RouterGroup) doBind(bindType string, pattern string, object interface{}
g.domain.BindHookHandler(pattern, extras[0], h)
}
} else {
glog.Fatalf("invalid hook handler for pattern:%s", pattern)
g.server.Logger().Fatalf("invalid hook handler for pattern:%s", pattern)
}
}
return g

View File

@ -12,7 +12,6 @@ import (
"strings"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/os/glog"
"github.com/gogf/gf/text/gregex"
"github.com/gogf/gf/text/gstr"
)
@ -53,7 +52,7 @@ func (s *Server) doBindController(pattern string, controller Controller, method
// 当pattern中的method为all时去掉该method以便于后续方法判断
domain, method, path, err := s.parsePattern(pattern)
if err != nil {
glog.Fatal(err)
s.Logger().Fatal(err)
return
}
if strings.EqualFold(method, gDEFAULT_METHOD) {
@ -81,11 +80,11 @@ func (s *Server) doBindController(pattern string, controller Controller, method
if _, ok := v.Method(i).Interface().(func()); !ok {
if len(methodMap) > 0 {
// 指定的方法名称注册,那么需要使用错误提示
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
s.Logger().Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, methodName, v.Method(i).Type().String())
} else {
// 否则只是Debug提示
glog.Debugf(`ignore route method: %s.%s.%s defined as "%s", no match "func()"`,
s.Logger().Debugf(`ignore route method: %s.%s.%s defined as "%s", no match "func()"`,
pkgPath, ctlName, methodName, v.Method(i).Type().String())
}
continue
@ -132,7 +131,7 @@ func (s *Server) doBindControllerMethod(pattern string, controller Controller, m
methodName := strings.TrimSpace(method)
methodValue := v.MethodByName(methodName)
if !methodValue.IsValid() {
glog.Fatal("invalid method name: " + methodName)
s.Logger().Fatal("invalid method name: " + methodName)
return
}
pkgPath := t.Elem().PkgPath()
@ -142,7 +141,7 @@ func (s *Server) doBindControllerMethod(pattern string, controller Controller, m
ctlName = fmt.Sprintf(`(%s)`, ctlName)
}
if _, ok := methodValue.Interface().(func()); !ok {
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
s.Logger().Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, methodName, methodValue.Type().String())
return
}
@ -178,7 +177,7 @@ func (s *Server) doBindControllerRest(pattern string, controller Controller, mid
ctlName = fmt.Sprintf(`(%s)`, ctlName)
}
if _, ok := v.Method(i).Interface().(func()); !ok {
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
s.Logger().Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, methodName, v.Method(i).Type().String())
return
}

View File

@ -12,7 +12,6 @@ import (
"strings"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/os/glog"
"github.com/gogf/gf/text/gregex"
"github.com/gogf/gf/text/gstr"
)
@ -51,7 +50,7 @@ func (s *Server) doBindObject(pattern string, object interface{}, method string,
// 当pattern中的method为all时去掉该method以便于后续方法判断
domain, method, path, err := s.parsePattern(pattern)
if err != nil {
glog.Fatal(err)
s.Logger().Fatal(err)
return
}
if strings.EqualFold(method, gDEFAULT_METHOD) {
@ -87,11 +86,11 @@ func (s *Server) doBindObject(pattern string, object interface{}, method string,
if !ok {
if len(methodMap) > 0 {
// 指定的方法名称注册,那么需要使用错误提示
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
s.Logger().Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
pkgPath, objName, methodName, v.Method(i).Type().String())
} else {
// 否则只是Debug提示
glog.Debugf(`ignore route method: %s.%s.%s defined as "%s", no match "func(*ghttp.Request)"`,
s.Logger().Debugf(`ignore route method: %s.%s.%s defined as "%s", no match "func(*ghttp.Request)"`,
pkgPath, objName, methodName, v.Method(i).Type().String())
}
continue
@ -136,7 +135,7 @@ func (s *Server) doBindObjectMethod(pattern string, object interface{}, method s
methodName := strings.TrimSpace(method)
methodValue := v.MethodByName(methodName)
if !methodValue.IsValid() {
glog.Fatal("invalid method name: " + methodName)
s.Logger().Fatal("invalid method name: " + methodName)
return
}
initFunc := (func(*Request))(nil)
@ -155,7 +154,7 @@ func (s *Server) doBindObjectMethod(pattern string, object interface{}, method s
}
itemFunc, ok := methodValue.Interface().(func(*Request))
if !ok {
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
s.Logger().Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
pkgPath, objName, methodName, methodValue.Type().String())
return
}
@ -198,7 +197,7 @@ func (s *Server) doBindObjectRest(pattern string, object interface{}, middleware
}
itemFunc, ok := v.Method(i).Interface().(func(*Request))
if !ok {
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
s.Logger().Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
pkgPath, objName, methodName, v.Method(i).Type().String())
continue
}

View File

@ -0,0 +1,59 @@
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// static service testing.
package ghttp_test
import (
"fmt"
"github.com/gogf/gf/os/gtime"
"github.com/gogf/gf/text/gstr"
"testing"
"time"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/test/gtest"
)
func Test_Log(t *testing.T) {
gtest.Case(t, func() {
logDir := gfile.Join(gfile.TempDir(), gtime.TimestampNanoStr())
p := ports.PopRand()
s := g.Server(p)
s.BindHandler("/hello", func(r *ghttp.Request) {
r.Response.Write("hello")
})
s.BindHandler("/error", func(r *ghttp.Request) {
panic("custom error")
})
s.SetLogPath(logDir)
s.SetAccessLogEnabled(true)
s.SetErrorLogEnabled(true)
s.SetLogStdout(false)
s.SetPort(p)
s.Start()
defer s.Shutdown()
defer gfile.Remove(logDir)
time.Sleep(100 * time.Millisecond)
client := ghttp.NewClient()
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
gtest.Assert(client.GetContent("/hello"), "hello")
gtest.Assert(client.GetContent("/error"), "custom error")
logPath1 := gfile.Join(logDir, gtime.Now().Format("Y-m-d")+".log")
gtest.Assert(gstr.Contains(gfile.GetContents(logPath1), "http server started listening on"), true)
gtest.Assert(gstr.Contains(gfile.GetContents(logPath1), "HANDLER"), true)
logPath2 := gfile.Join(logDir, "access-"+gtime.Now().Format("Ymd")+".log")
gtest.Assert(gstr.Contains(gfile.GetContents(logPath2), " /hello "), true)
gtest.Assert(gstr.Contains(gfile.GetContents(logPath2), "[ERRO]"), true)
gtest.Assert(gstr.Contains(gfile.GetContents(logPath2), "custom error"), true)
})
}

View File

@ -47,6 +47,13 @@ func DefaultLogger() *Logger {
return logger
}
// SetDefaultLogger sets the default logger for package glog.
// Note that there might be concurrent safety issue if calls this function
// in different goroutines.
func SetDefaultLogger(l *Logger) {
logger = l
}
// SetPath sets the directory path for file logging.
func SetPath(path string) error {
return logger.SetPath(path)