diff --git a/net/ghttp/ghttp_server.go b/net/ghttp/ghttp_server.go index ed0655eb4..76456316d 100644 --- a/net/ghttp/ghttp_server.go +++ b/net/ghttp/ghttp_server.go @@ -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 { diff --git a/net/ghttp/ghttp_server_config.go b/net/ghttp/ghttp_server_config.go index 7e7754f3e..eb067c532 100644 --- a/net/ghttp/ghttp_server_config.go +++ b/net/ghttp/ghttp_server_config.go @@ -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 diff --git a/net/ghttp/ghttp_server_config_static.go b/net/ghttp/ghttp_server_config_static.go index 36c482b49..ee0c62d8b 100644 --- a/net/ghttp/ghttp_server_config_static.go +++ b/net/ghttp/ghttp_server_config_static.go @@ -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 } diff --git a/net/ghttp/ghttp_server_graceful.go b/net/ghttp/ghttp_server_graceful.go index 44e3c0c42..ac7b4305b 100644 --- a/net/ghttp/ghttp_server_graceful.go +++ b/net/ghttp/ghttp_server_graceful.go @@ -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) } } diff --git a/net/ghttp/ghttp_server_log.go b/net/ghttp/ghttp_server_log.go index 4e10c766f..1310d69f4 100644 --- a/net/ghttp/ghttp_server_log.go +++ b/net/ghttp/ghttp_server_log.go @@ -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 +} + // 处理服务错误信息,主要是panic,http请求的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). diff --git a/net/ghttp/ghttp_server_plugin.go b/net/ghttp/ghttp_server_plugin.go index 2683c36c6..55d7478d1 100644 --- a/net/ghttp/ghttp_server_plugin.go +++ b/net/ghttp/ghttp_server_plugin.go @@ -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) } } } diff --git a/net/ghttp/ghttp_server_router.go b/net/ghttp/ghttp_server_router.go index 9f7d7ddf1..d76a5b17b 100644 --- a/net/ghttp/ghttp_server_router.go +++ b/net/ghttp/ghttp_server_router.go @@ -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 } } diff --git a/net/ghttp/ghttp_server_router_group.go b/net/ghttp/ghttp_server_router_group.go index 71b5f508e..3a9d03d67 100644 --- a/net/ghttp/ghttp_server_router_group.go +++ b/net/ghttp/ghttp_server_router_group.go @@ -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 diff --git a/net/ghttp/ghttp_server_service_controller.go b/net/ghttp/ghttp_server_service_controller.go index 4afecc2df..991c49c2f 100644 --- a/net/ghttp/ghttp_server_service_controller.go +++ b/net/ghttp/ghttp_server_service_controller.go @@ -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 } diff --git a/net/ghttp/ghttp_server_service_object.go b/net/ghttp/ghttp_server_service_object.go index a9f1254b3..06f90c193 100644 --- a/net/ghttp/ghttp_server_service_object.go +++ b/net/ghttp/ghttp_server_service_object.go @@ -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 } diff --git a/net/ghttp/ghttp_unit_log_test.go b/net/ghttp/ghttp_unit_log_test.go new file mode 100644 index 000000000..40d2916ef --- /dev/null +++ b/net/ghttp/ghttp_unit_log_test.go @@ -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) + }) +} diff --git a/os/glog/glog.go b/os/glog/glog.go index 0521cdecb..9dafb97d0 100644 --- a/os/glog/glog.go +++ b/os/glog/glog.go @@ -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)