diff --git a/.example/net/ghttp/server/https/https.go b/.example/net/ghttp/server/https/https.go index b3430c996..3c2da3cec 100644 --- a/.example/net/ghttp/server/https/https.go +++ b/.example/net/ghttp/server/https/https.go @@ -1,11 +1,12 @@ package main import ( + "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" ) func main() { - s := ghttp.GetServer() + s := g.Server() s.BindHandler("/", func(r *ghttp.Request) { r.Response.Writeln("来自于HTTPS的:哈喽世界!") }) diff --git a/.example/net/ghttp/server/https/https_http.go b/.example/net/ghttp/server/https/https_http.go index 5bb96bb22..ad53a0fda 100644 --- a/.example/net/ghttp/server/https/https_http.go +++ b/.example/net/ghttp/server/https/https_http.go @@ -1,11 +1,12 @@ package main import ( + "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" ) func main() { - s := ghttp.GetServer() + s := g.Server() s.BindHandler("/", func(r *ghttp.Request) { r.Response.Writeln("您可以同时通过HTTP和HTTPS方式看到该内容!") }) diff --git a/.example/net/ghttp/server/log/config.toml b/.example/net/ghttp/server/log/config.toml new file mode 100644 index 000000000..32a428e4d --- /dev/null +++ b/.example/net/ghttp/server/log/config.toml @@ -0,0 +1,7 @@ +[server] + LogPath = "/tmp/gflog/server" + LogStdout = true + ErrorLogEnabled = true + ErrorLogPattern = "error.log" + AccessLogEnabled = true + AccessLogPattern = "access.log" \ No newline at end of file diff --git a/.example/net/ghttp/server/log/log.go b/.example/net/ghttp/server/log/log.go index b7796547d..75e95e43f 100644 --- a/.example/net/ghttp/server/log/log.go +++ b/.example/net/ghttp/server/log/log.go @@ -1,26 +1,21 @@ package main import ( - "net/http" - + "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" + "net/http" ) func main() { - s := ghttp.GetServer() - s.BindHandler("/log/handler", func(r *ghttp.Request) { - r.Response.WriteStatus(http.StatusNotFound, "文件找不到了") + s := g.Server() + s.Group("/", func(g *ghttp.RouterGroup) { + g.ALL("/", func(r *ghttp.Request) { + r.Response.Write("halo world!") + }) + g.ALL("/log/handler", func(r *ghttp.Request) { + r.Response.WriteStatus(http.StatusNotFound, "File Not Found!") + }) }) - s.SetAccessLogEnabled(true) - s.SetErrorLogEnabled(true) - //s.SetLogHandler(func(r *ghttp.Request, error ...interface{}) { - // if len(error) > 0 { - // // 如果是错误日志 - // fmt.Println("错误产生了:", error[0]) - // } - // // 这里是请求日志 - // fmt.Println("请求处理完成,请求地址:", r.URL.String(), "请求结果:", r.Response.Status) - //}) s.SetPort(8199) s.Run() } diff --git a/.example/net/ghttp/server/pprof.go b/.example/net/ghttp/server/pprof.go index 73d75e4dc..fd16f2766 100644 --- a/.example/net/ghttp/server/pprof.go +++ b/.example/net/ghttp/server/pprof.go @@ -6,7 +6,7 @@ import ( func main() { s := ghttp.GetServer() - s.EnablePprof() + s.EnablePProf() s.BindHandler("/", func(r *ghttp.Request) { r.Response.Writeln("哈喽世界!") }) diff --git a/net/ghttp/ghttp_server.go b/net/ghttp/ghttp_server.go index 9097ddc23..182d0c5a2 100644 --- a/net/ghttp/ghttp_server.go +++ b/net/ghttp/ghttp_server.go @@ -176,10 +176,9 @@ func SetGraceful(enabled bool) { // Web Server进程初始化. // 注意该方法不能放置于包初始化方法init中,不使用ghttp.Server的功能便不能初始化对应的协程goroutine逻辑. func serverProcessInit() { - if serverProcessInited.Val() { + if !serverProcessInited.Cas(false, true) { return } - serverProcessInited.Set(true) // 如果是完整重启,那么需要等待主进程销毁后,才开始执行监听,防止端口冲突 if genv.Get(gADMIN_ACTION_RESTART_ENVKEY) != "" { if p, e := os.FindProcess(gproc.PPid()); e == nil { @@ -251,7 +250,7 @@ func (s *Server) Start() error { // 没有注册任何路由,且没有开启文件服务,那么提示错误 if len(s.routesMap) == 0 && !s.config.FileServerEnabled { - glog.Fatal("[ghttp] no router set or static feature enabled, did you forget import the router?") + glog.Fatal("[ghttp] There's no route set or static feature enabled, did you forget import the router?") } // Default session storage. @@ -261,12 +260,17 @@ func (s *Server) Start() error { // Initialize session manager when start running. s.sessionManager = gsession.New(s.config.SessionMaxAge, s.config.SessionStorage) - // 底层http server配置 + // PProf feature. + if s.config.PProfEnabled { + s.EnablePProf(s.config.PProfPattern) + } + + // Default HTTP handler. if s.config.Handler == nil { s.config.Handler = http.HandlerFunc(s.defaultHttpHandle) } - // 启动http server + // Start the HTTP server. reloaded := false fdMapStr := genv.Get(gADMIN_ACTION_RELOAD_ENVKEY) if len(fdMapStr) > 0 { @@ -421,7 +425,7 @@ func Wait() { func (s *Server) startServer(fdMap listenerFdMap) { var httpsEnabled bool // 判断是否启用HTTPS - if len(s.config.TLSConfig.Certificates) > 0 || (len(s.config.HTTPSCertPath) > 0 && len(s.config.HTTPSKeyPath) > 0) { + if s.config.TLSConfig != nil || (s.config.HTTPSCertPath != "" && s.config.HTTPSKeyPath != "") { // ================ // HTTPS // ================ @@ -502,7 +506,7 @@ func (s *Server) startServer(fdMap listenerFdMap) { s.serverCount.Add(1) err := (error)(nil) if server.isHttps { - err = server.ListenAndServeTLS(s.config.HTTPSCertPath, s.config.HTTPSKeyPath, &s.config.TLSConfig) + err = server.ListenAndServeTLS(s.config.HTTPSCertPath, s.config.HTTPSKeyPath, s.config.TLSConfig) } else { err = server.ListenAndServe() } diff --git a/net/ghttp/ghttp_server_config.go b/net/ghttp/ghttp_server_config.go index 8cae3649e..80d37e737 100644 --- a/net/ghttp/ghttp_server_config.go +++ b/net/ghttp/ghttp_server_config.go @@ -32,10 +32,10 @@ const ( URI_TYPE_CAMEL = 3 // 采用驼峰命名方式 ) -// 自定义日志处理方法类型 +// LogHandler is the log handler function type. type LogHandler func(r *Request, err ...error) -// HTTP Server 设置结构体,静态配置 +// HTTP Server configuration. type ServerConfig struct { Address string // Server listening address like ":port", multiple addresses separated using ',' HTTPSAddr string // HTTPS服务监听地址(支持多个地址,使用","号分隔) @@ -46,7 +46,7 @@ type ServerConfig struct { WriteTimeout time.Duration // 写入超时 IdleTimeout time.Duration // 等待超时 MaxHeaderBytes int // 最大的header长度 - TLSConfig tls.Config // HTTPS证书配置 + TLSConfig *tls.Config // HTTPS证书配置 KeepAlive bool // 是否开启长连接 ServerAgent string // Server Agent View *gview.View // 模板引擎对象 @@ -71,7 +71,11 @@ type ServerConfig struct { LogStdout bool // Logging: 是否打印日志到终端(默认开启) ErrorStack bool // Logging: 当产生错误时打印调用链详细堆栈 ErrorLogEnabled bool // Logging: 是否开启error log(默认开启) + ErrorLogPattern string // Logging: Error log file pattern like: error-{Ymd}.log AccessLogEnabled bool // Logging: 是否开启access log(默认关闭) + AccessLogPattern string // Logging: Error log file pattern like: access-{Ymd}.log + PProfEnabled bool // PProf: Enable PProf feature or not. + PProfPattern string // PProf: PProf pattern for router, it enables PProf feature if it's not empty. FormParsingMemory int64 // Mess: 表单解析内存限制(byte) NameToUriType int // Mess: 服务注册时对象和方法名称转换为URI时的规则 GzipContentTypes []string // Mess: 允许进行gzip压缩的文件类型 @@ -91,7 +95,7 @@ var defaultServerConfig = ServerConfig{ KeepAlive: true, IndexFiles: []string{"index.html", "index.htm"}, IndexFolder: false, - ServerAgent: "gf http server", + ServerAgent: "GF HTTP Server", ServerRoot: "", StaticPaths: make([]staticPathItem, 0), FileServerEnabled: false, @@ -103,7 +107,9 @@ var defaultServerConfig = ServerConfig{ LogStdout: true, ErrorStack: true, ErrorLogEnabled: true, + ErrorLogPattern: "error-{Ymd}.log", AccessLogEnabled: false, + AccessLogPattern: "access-{Ymd}.log", DumpRouteMap: true, FormParsingMemory: 1024 * 1024 * 1024, RouterCacheExpire: 60, @@ -131,10 +137,14 @@ func (s *Server) SetConfig(c ServerConfig) error { c.Handler = http.HandlerFunc(s.defaultHttpHandle) } s.config = c - + // Logging. if c.LogPath != "" { return s.logger.SetPath(c.LogPath) } + // HTTPS. + if c.TLSConfig == nil && c.HTTPSCertPath != "" { + s.EnableHTTPS(c.HTTPSCertPath, c.HTTPSKeyPath) + } return nil } @@ -185,7 +195,7 @@ func (s *Server) SetHTTPSPort(port ...int) { } // 开启HTTPS支持,但是必须提供Cert和Key文件,tlsConfig为可选项 -func (s *Server) EnableHTTPS(certFile, keyFile string, tlsConfig ...tls.Config) { +func (s *Server) EnableHTTPS(certFile, keyFile string, tlsConfig ...*tls.Config) { certFileRealPath := gfile.RealPath(certFile) if certFileRealPath == "" { certFileRealPath = gfile.RealPath(gfile.Pwd() + gfile.Separator + certFile) @@ -214,7 +224,7 @@ func (s *Server) EnableHTTPS(certFile, keyFile string, tlsConfig ...tls.Config) } // 设置TLS配置对象 -func (s *Server) SetTLSConfig(tlsConfig tls.Config) { +func (s *Server) SetTLSConfig(tlsConfig *tls.Config) { s.config.TLSConfig = tlsConfig } diff --git a/net/ghttp/ghttp_server_graceful.go b/net/ghttp/ghttp_server_graceful.go index 0ea5bfc10..7a29ef8fd 100644 --- a/net/ghttp/ghttp_server_graceful.go +++ b/net/ghttp/ghttp_server_graceful.go @@ -91,11 +91,13 @@ func (s *gracefulServer) setFd(fd int) { // 执行HTTPS监听 func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string, tlsConfig ...*tls.Config) error { itemFunc := s.httpServer.Addr - config := (*tls.Config)(nil) - if len(tlsConfig) > 0 { + var config *tls.Config + if len(tlsConfig) > 0 && tlsConfig[0] != nil { config = tlsConfig[0] } else if s.httpServer.TLSConfig != nil { - *config = *s.httpServer.TLSConfig + config = s.httpServer.TLSConfig + } else { + config = &tls.Config{} } if config.NextProtos == nil { config.NextProtos = []string{"http/1.1"} diff --git a/net/ghttp/ghttp_server_log.go b/net/ghttp/ghttp_server_log.go index 398af41b8..7a8968cc5 100644 --- a/net/ghttp/ghttp_server_log.go +++ b/net/ghttp/ghttp_server_log.go @@ -38,7 +38,7 @@ func (s *Server) handleAccessLog(r *Request) { ) content += fmt.Sprintf(` %.3f`, float64(r.LeaveTime-r.EnterTime)/1000) content += fmt.Sprintf(`, %s, "%s", "%s"`, r.GetClientIp(), r.Referer(), r.UserAgent()) - s.logger.Cat("access").StackWithFilter(gPATH_FILTER_KEY).Stdout(s.config.LogStdout).Println(content) + s.logger.File(s.config.AccessLogPattern).StackWithFilter(gPATH_FILTER_KEY).Stdout(s.config.LogStdout).Println(content) } // 处理服务错误信息,主要是panic,http请求的status由access log进行管理 @@ -71,5 +71,5 @@ func (s *Server) handleErrorLog(err error, r *Request) { content += "\n" + stack } } - s.logger.Cat("error").Stack(false).Stdout(s.config.LogStdout).Error(content) + s.logger.File(s.config.AccessLogPattern).Stack(false).Stdout(s.config.LogStdout).Error(content) } diff --git a/net/ghttp/ghttp_server_pprof.go b/net/ghttp/ghttp_server_pprof.go index 5ca66615b..476aa50bc 100644 --- a/net/ghttp/ghttp_server_pprof.go +++ b/net/ghttp/ghttp_server_pprof.go @@ -15,10 +15,33 @@ import ( "github.com/gogf/gf/os/gview" ) -// 用于pprof的对象 -type utilPprof struct{} +// utilPProf is the PProf interface implementer. +type utilPProf struct{} -func (p *utilPprof) Index(r *Request) { +const ( + gDEFAULT_PPROF_PATTERN = "/debug/pprof" +) + +// EnablePProf enables PProf feature for server. +func (s *Server) EnablePProf(pattern ...string) { + p := gDEFAULT_PPROF_PATTERN + if len(pattern) > 0 && pattern[0] != "" { + p = pattern[0] + } + up := &utilPProf{} + _, _, uri, _ := s.parsePattern(p) + uri = strings.TrimRight(uri, "/") + s.Group(uri, func(g *RouterGroup) { + g.ALL("/*action", up.Index) + g.ALL("/cmdline", up.Cmdline) + g.ALL("/profile", up.Profile) + g.ALL("/symbol", up.Symbol) + g.ALL("/trace", up.Trace) + }) +} + +// Index shows the PProf index page. +func (p *utilPProf) Index(r *Request) { profiles := runpprof.Profiles() action := r.GetString("action") data := map[string]interface{}{ @@ -52,34 +75,30 @@ func (p *utilPprof) Index(r *Request) { } } -func (p *utilPprof) Cmdline(r *Request) { +// Cmdline responds with the running program's +// command line, with arguments separated by NUL bytes. +// The package initialization registers it as /debug/pprof/cmdline. +func (p *utilPProf) Cmdline(r *Request) { netpprof.Cmdline(r.Response.Writer, r.Request) } -func (p *utilPprof) Profile(r *Request) { +// Profile responds with the pprof-formatted cpu profile. +// Profiling lasts for duration specified in seconds GET parameter, or for 30 seconds if not specified. +// The package initialization registers it as /debug/pprof/profile. +func (p *utilPProf) Profile(r *Request) { netpprof.Profile(r.Response.Writer, r.Request) } -func (p *utilPprof) Symbol(r *Request) { +// Symbol looks up the program counters listed in the request, +// responding with a table mapping program counters to function names. +// The package initialization registers it as /debug/pprof/symbol. +func (p *utilPProf) Symbol(r *Request) { netpprof.Symbol(r.Response.Writer, r.Request) } -func (p *utilPprof) Trace(r *Request) { +// Trace responds with the execution trace in binary form. +// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified. +// The package initialization registers it as /debug/pprof/trace. +func (p *utilPProf) Trace(r *Request) { netpprof.Trace(r.Response.Writer, r.Request) } - -// 开启pprof支持 -func (s *Server) EnablePprof(pattern ...string) { - p := "/debug/pprof" - if len(pattern) > 0 { - p = pattern[0] - } - up := &utilPprof{} - _, _, uri, _ := s.parsePattern(p) - uri = strings.TrimRight(uri, "/") - s.BindHandler(uri+"/*action", up.Index) - s.BindHandler(uri+"/cmdline", up.Cmdline) - s.BindHandler(uri+"/profile", up.Profile) - s.BindHandler(uri+"/symbol", up.Symbol) - s.BindHandler(uri+"/trace", up.Trace) -}