mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
improve logger feautre, add unit testing cases for ghttp.Server; add SetDefaultLogger function for glog
This commit is contained in:
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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).
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
59
net/ghttp/ghttp_unit_log_test.go
Normal file
59
net/ghttp/ghttp_unit_log_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user