mirror of
https://gitee.com/johng/gf
synced 2026-06-20 23:29:27 +08:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3dd8b6ad33 | |||
| 3e0a975a88 | |||
| 6aa1c5b1eb | |||
| 1fb5a8cd6f | |||
| 8925460718 |
16
g/g_setting.go
Normal file
16
g/g_setting.go
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
package g
|
||||
|
||||
import "github.com/gogf/gf/g/net/ghttp"
|
||||
|
||||
// SetServerGraceful enables/disables graceful reload feature of ghttp Web Server.
|
||||
//
|
||||
// 是否开启WebServer的平滑重启特性。
|
||||
func SetServerGraceful(enabled bool) {
|
||||
ghttp.SetGraceful(enabled)
|
||||
}
|
||||
@ -140,17 +140,24 @@ var (
|
||||
doneChan = make(chan struct{}, 1000)
|
||||
|
||||
// 用于服务进程初始化,只能初始化一次,采用“懒初始化”(在server运行时才初始化)
|
||||
serverProcInited = gtype.NewBool()
|
||||
serverProcessInited = gtype.NewBool()
|
||||
|
||||
// 是否开启WebServer平滑重启特性, 会开启额外的本地端口监听,用于进程管理通信
|
||||
gracefulEnabled = true
|
||||
)
|
||||
|
||||
// 是否开启平滑重启特性
|
||||
func SetGraceful(enabled bool) {
|
||||
gracefulEnabled = enabled
|
||||
}
|
||||
|
||||
// Web Server进程初始化.
|
||||
// 注意该方法不能放置于包初始化方法init中,不使用ghttp.Server的功能便不能初始化对应的协程goroutine逻辑.
|
||||
func serverProcInit() {
|
||||
if serverProcInited.Val() {
|
||||
func serverProcessInit() {
|
||||
if serverProcessInited.Val() {
|
||||
return
|
||||
}
|
||||
serverProcInited.Set(true)
|
||||
serverProcessInited.Set(true)
|
||||
// 如果是完整重启,那么需要等待主进程销毁后,才开始执行监听,防止端口冲突
|
||||
if genv.Get(gADMIN_ACTION_RESTART_ENVKEY) != "" {
|
||||
if p, e := os.FindProcess(gproc.PPid()); e == nil {
|
||||
@ -164,7 +171,9 @@ func serverProcInit() {
|
||||
// 信号量管理操作监听
|
||||
go handleProcessSignal()
|
||||
// 异步监听进程间消息
|
||||
go handleProcessMessage()
|
||||
if gracefulEnabled {
|
||||
go handleProcessMessage()
|
||||
}
|
||||
}
|
||||
|
||||
// 获取/创建一个默认配置的HTTP Server(默认监听端口是80)
|
||||
@ -207,7 +216,7 @@ func GetServer(name...interface{}) (*Server) {
|
||||
// 需要结合Wait方式一起使用
|
||||
func (s *Server) Start() error {
|
||||
// 服务进程初始化,只会初始化一次
|
||||
serverProcInit()
|
||||
serverProcessInit()
|
||||
|
||||
// 当前Web Server状态判断
|
||||
if s.Status() == SERVER_STATUS_RUNNING {
|
||||
@ -253,7 +262,7 @@ func (s *Server) Start() error {
|
||||
if gproc.IsChild() {
|
||||
gtimer.SetTimeout(2*time.Second, func() {
|
||||
if err := gproc.Send(gproc.PPid(), []byte("exit"), gADMIN_GPROC_COMM_GROUP); err != nil {
|
||||
panic(err)
|
||||
glog.Error("ghttp server error in process communication:", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -117,23 +117,23 @@ func newSchedule(pattern string) (*cronSchedule, error) {
|
||||
schedule.hour = m
|
||||
}
|
||||
// 天
|
||||
if m, err := parseItem(match[4], 1, 31, false); err != nil {
|
||||
if m, err := parseItem(match[4], 1, 31, true); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
schedule.day = m
|
||||
}
|
||||
// 周
|
||||
if m, err := parseItem(match[5], 0, 6, false); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
schedule.week = m
|
||||
}
|
||||
// 月
|
||||
if m, err := parseItem(match[6], 1, 12, false); err != nil {
|
||||
if m, err := parseItem(match[5], 1, 12, false); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
schedule.month = m
|
||||
}
|
||||
// 周
|
||||
if m, err := parseItem(match[6], 0, 6, true); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
schedule.week = m
|
||||
}
|
||||
return schedule, nil
|
||||
} else {
|
||||
return nil, errors.New(fmt.Sprintf(`invalid pattern: "%s"`, pattern))
|
||||
@ -200,14 +200,14 @@ func parseItemValue(value string, valueType byte) (int, error) {
|
||||
} else {
|
||||
// 英文字母
|
||||
switch valueType {
|
||||
case 'w':
|
||||
if i, ok := weekMap[strings.ToLower(value)]; ok {
|
||||
return int(i), nil
|
||||
}
|
||||
case 'm':
|
||||
if i, ok := monthMap[strings.ToLower(value)]; ok {
|
||||
return int(i), nil
|
||||
}
|
||||
case 'w':
|
||||
if i, ok := weekMap[strings.ToLower(value)]; ok {
|
||||
return int(i), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, errors.New(fmt.Sprintf(`invalid pattern value: "%s"`, value))
|
||||
@ -234,10 +234,10 @@ func (s *cronSchedule) meet(t time.Time) bool {
|
||||
if _, ok := s.day[t.Day()]; !ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := s.week[int(t.Weekday())]; !ok {
|
||||
if _, ok := s.month[int(t.Month())]; !ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := s.month[int(t.Month())]; !ok {
|
||||
if _, ok := s.week[int(t.Weekday())]; !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
@ -47,31 +47,16 @@ func (c *Cache) GetBinContents(path string) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
// 添加文件监控
|
||||
// 添加文件监控,一旦文件有变化立即清除缓存,下一次读取的时候再执行缓存。
|
||||
func (c *Cache) addMonitor(path string) {
|
||||
// 防止多goroutine同时调用
|
||||
if c.cache.Contains(path) {
|
||||
return
|
||||
}
|
||||
gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
//glog.Debug("gfcache:", event)
|
||||
length := 0
|
||||
if r := c.cache.Get(path); r != nil {
|
||||
length = len(r.([]byte))
|
||||
}
|
||||
// 是否删除
|
||||
if event.IsRemove() {
|
||||
c.cache.Remove(path)
|
||||
c.size.Add(-length)
|
||||
return
|
||||
}
|
||||
// 更新缓存内容
|
||||
if c.cap.Val() == 0 || c.size.Val() < c.cap.Val() {
|
||||
b := gfile.GetBinContents(path)
|
||||
if len(b) > 0 {
|
||||
c.size.Add(len(b) - length)
|
||||
c.cache.Set(path, b)
|
||||
}
|
||||
c.size.Add(-len(r.([]byte)))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -7,8 +7,7 @@
|
||||
|
||||
// Package glog implements powerful and easy-to-use levelled logging functionality.
|
||||
//
|
||||
// 日志模块,
|
||||
// 直接文件/输出操作,没有异步逻辑,没有使用缓存或者通道
|
||||
// 日志模块, 直接文件/输出操作,没有异步逻辑,没有使用缓存或者通道
|
||||
package glog
|
||||
|
||||
import (
|
||||
@ -28,10 +27,10 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// glog默认的日志等级,影响全局
|
||||
// default level for log
|
||||
defaultLevel = gtype.NewInt(LEVEL_ALL)
|
||||
|
||||
// 默认的日志对象
|
||||
// default logger object, for package method usage
|
||||
logger = New()
|
||||
)
|
||||
|
||||
@ -39,101 +38,157 @@ func init() {
|
||||
SetDebug(cmdenv.Get("gf.glog.debug", true).Bool())
|
||||
}
|
||||
|
||||
// 日志日志目录绝对路径
|
||||
// SetPath sets the directory path for file logging.
|
||||
//
|
||||
// 日志日志目录绝对路径.
|
||||
func SetPath(path string) {
|
||||
logger.SetPath(path)
|
||||
}
|
||||
|
||||
// 日志文件名称
|
||||
func SetFile(file string) {
|
||||
logger.SetFile(file)
|
||||
// SetFile sets the file name <pattern> for file logging.
|
||||
// Datetime pattern can be used in <pattern>, eg: access-{Ymd}.log.
|
||||
// The default file name pattern is: Y-m-d.log, eg: 2018-01-01.log
|
||||
//
|
||||
// 日志文件名称.
|
||||
func SetFile(pattern string) {
|
||||
logger.SetFile(pattern)
|
||||
}
|
||||
|
||||
// 设置全局的日志记录等级
|
||||
// SetLevel sets the default logging level.
|
||||
//
|
||||
// 设置全局的日志记录等级.
|
||||
func SetLevel(level int) {
|
||||
logger.SetLevel(level)
|
||||
defaultLevel.Set(level)
|
||||
}
|
||||
|
||||
// 可自定义IO接口,IO可以是文件输出、标准输出、网络输出
|
||||
// SetWriter sets the customed logging <writer> for logging.
|
||||
// The <writer> object should implements the io.Writer interface.
|
||||
// Developer can use customed logging <writer> to redirect logging output to another service,
|
||||
// eg: kafka, mysql, mongodb, etc.
|
||||
//
|
||||
// 可自定义IO接口,IO可以是文件输出、标准输出、网络输出.
|
||||
func SetWriter(writer io.Writer) {
|
||||
logger.SetWriter(writer)
|
||||
}
|
||||
|
||||
// 返回自定义的IO,默认为nil
|
||||
// GetWriter returns the customed writer object, which implements the io.Writer interface.
|
||||
// It returns nil if no customed writer set.
|
||||
//
|
||||
// 返回自定义的IO,默认为nil.
|
||||
func GetWriter() io.Writer {
|
||||
return logger.GetWriter()
|
||||
}
|
||||
|
||||
// 获取全局的日志记录等级
|
||||
// GetLevel returns the default logging level value.
|
||||
//
|
||||
// 获取全局的日志记录等级.
|
||||
func GetLevel() int {
|
||||
return defaultLevel.Val()
|
||||
}
|
||||
|
||||
// 设置是否允许输出DEBUG信息
|
||||
// SetDebug enables/disables the debug level for default logger.
|
||||
// The debug level is enbaled in default.
|
||||
//
|
||||
// 设置是否允许输出DEBUG信息.
|
||||
func SetDebug(debug bool) {
|
||||
logger.SetDebug(debug)
|
||||
}
|
||||
|
||||
// SetStdPrint sets whether ouptput the logging contents to stdout, which is false indefault.
|
||||
//
|
||||
// 设置写日志的同时开启or关闭控制台打印,默认是关闭的
|
||||
func SetStdPrint(open bool) {
|
||||
logger.SetStdPrint(open)
|
||||
}
|
||||
|
||||
// GetPath returns the logging directory path for file logging.
|
||||
// It returns empty string if no directory path set.
|
||||
//
|
||||
// 获取日志目录绝对路径
|
||||
func GetPath() string {
|
||||
return logger.GetPath()
|
||||
}
|
||||
|
||||
// PrintBacktrace prints the caller backtrace,
|
||||
// the optional parameter <skip> specify the skipped backtraces offset from the end point.
|
||||
//
|
||||
// 打印文件调用回溯信息
|
||||
func PrintBacktrace(skip...int) {
|
||||
logger.PrintBacktrace(skip...)
|
||||
}
|
||||
|
||||
// 获取文件调用回溯信息
|
||||
// GetBacktrace returns the caller backtrace content,
|
||||
// the optional parameter <skip> specify the skipped backtraces offset from the end point.
|
||||
//
|
||||
// 获取文件调用回溯信息.
|
||||
func GetBacktrace(skip...int) string {
|
||||
return logger.GetBacktrace(skip...)
|
||||
}
|
||||
|
||||
// SetBacktrace enables/disables the backtrace feature in failure logging outputs.
|
||||
//
|
||||
// 是否关闭全局的backtrace信息
|
||||
func SetBacktrace(enabled bool) {
|
||||
logger.SetBacktrace(enabled)
|
||||
}
|
||||
|
||||
// To is a chaining function,
|
||||
// which redirects current logging content output to the sepecified <writer>.
|
||||
//
|
||||
// 链式操作,设置下一次写入日志内容的Writer
|
||||
func To(writer io.Writer) *Logger {
|
||||
return logger.To(writer)
|
||||
}
|
||||
|
||||
// 设置下一次输出的分类,支持多级分类设置
|
||||
// Cat is a chaining function,
|
||||
// which sets the category to <category> for current logging content output.
|
||||
//
|
||||
// 设置下一次输出的分类,支持多级分类设置.
|
||||
func Cat(category string) *Logger {
|
||||
return logger.Cat(category)
|
||||
}
|
||||
|
||||
// File is a chaining function,
|
||||
// which sets file name <pattern> for the current logging content output.
|
||||
//
|
||||
// 设置日志输出文件名称格式
|
||||
func File(file string) *Logger {
|
||||
return logger.File(file)
|
||||
func File(pattern string) *Logger {
|
||||
return logger.File(pattern)
|
||||
}
|
||||
|
||||
// 设置日志打印等级
|
||||
// Level is a chaining function,
|
||||
// which sets logging level for the current logging content output.
|
||||
//
|
||||
// 设置日志打印等级.
|
||||
func Level(level int) *Logger {
|
||||
return logger.Level(level)
|
||||
}
|
||||
|
||||
// 设置文件调用回溯信息
|
||||
// Backtrace is a chaining function,
|
||||
// which sets backtrace options for the current logging content output .
|
||||
//
|
||||
// 设置文件调用回溯信息.
|
||||
func Backtrace(enabled bool, skip...int) *Logger {
|
||||
return logger.Backtrace(enabled, skip...)
|
||||
}
|
||||
|
||||
// StdPrint is a chaining function,
|
||||
// which enables/disables stdout for the current logging content output.
|
||||
//
|
||||
// 是否允许在设置输出文件时同时也输出到终端
|
||||
func StdPrint(enabled bool) *Logger {
|
||||
return logger.StdPrint(enabled)
|
||||
}
|
||||
|
||||
// Header is a chaining function,
|
||||
// which enables/disables log header for the current logging content output.
|
||||
//
|
||||
// 是否打印每行日志头信息(默认开启)
|
||||
func Header(enabled bool) *Logger {
|
||||
return logger.Header(enabled)
|
||||
}
|
||||
|
||||
func Print(v ...interface{}) {
|
||||
logger.Print(v ...)
|
||||
}
|
||||
@ -150,14 +205,17 @@ func Printfln(format string, v ...interface{}) {
|
||||
logger.Printfln(format, v ...)
|
||||
}
|
||||
|
||||
// Fatal prints the logging content with [FATA] header and newline, then exit the current process.
|
||||
func Fatal(v ...interface{}) {
|
||||
logger.Fatal(v ...)
|
||||
}
|
||||
|
||||
// Fatalf prints the logging content with [FATA] header and custom format, then exit the current process.
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
logger.Fatalf(format, v ...)
|
||||
}
|
||||
|
||||
// Fatalf prints the logging content with [FATA] header, custom format and newline, then exit the current process.
|
||||
func Fatalfln(format string, v ...interface{}) {
|
||||
logger.Fatalfln(format, v ...)
|
||||
}
|
||||
|
||||
@ -58,6 +58,8 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// New creates a custom logger.
|
||||
//
|
||||
// 新建自定义的日志操作对象
|
||||
func New() *Logger {
|
||||
return &Logger {
|
||||
@ -72,7 +74,9 @@ func New() *Logger {
|
||||
}
|
||||
}
|
||||
|
||||
// Logger深拷贝
|
||||
// Clone returns a new logger, which is the clone the current logger.
|
||||
//
|
||||
// Logger拷贝.
|
||||
func (l *Logger) Clone() *Logger {
|
||||
return &Logger {
|
||||
pr : l,
|
||||
@ -87,16 +91,23 @@ func (l *Logger) Clone() *Logger {
|
||||
}
|
||||
}
|
||||
|
||||
// SetLevel sets the logging level.
|
||||
//
|
||||
// 设置日志记录等级
|
||||
func (l *Logger) SetLevel(level int) {
|
||||
l.level.Set(level)
|
||||
}
|
||||
|
||||
// GetLevel returns the logging level value.
|
||||
//
|
||||
// 获取日志记录等级
|
||||
func (l *Logger) GetLevel() int {
|
||||
return l.level.Val()
|
||||
}
|
||||
|
||||
// SetDebug enables/disables the debug level for logger.
|
||||
// The debug level is enbaled in default.
|
||||
//
|
||||
// 快捷方法,打开或关闭DEBU日志信息
|
||||
func (l *Logger) SetDebug(debug bool) {
|
||||
if debug {
|
||||
@ -106,6 +117,7 @@ func (l *Logger) SetDebug(debug bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// SetBacktrace enables/disables the backtrace feature in failure logging outputs.
|
||||
func (l *Logger) SetBacktrace(enabled bool) {
|
||||
if enabled {
|
||||
l.btStatus.Set(1)
|
||||
@ -115,11 +127,16 @@ func (l *Logger) SetBacktrace(enabled bool) {
|
||||
|
||||
}
|
||||
|
||||
// 设置BacktraceSkip
|
||||
// SetBacktraceSkip sets the backtrace offset from the end point.
|
||||
func (l *Logger) SetBacktraceSkip(skip int) {
|
||||
l.btSkip.Set(skip)
|
||||
}
|
||||
|
||||
// SetWriter sets the customed logging <writer> for logging.
|
||||
// The <writer> object should implements the io.Writer interface.
|
||||
// Developer can use customed logging <writer> to redirect logging output to another service,
|
||||
// eg: kafka, mysql, mongodb, etc.
|
||||
//
|
||||
// 可自定义IO接口,IO可以是文件输出、标准输出、网络输出
|
||||
func (l *Logger) SetWriter(writer io.Writer) {
|
||||
l.mu.Lock()
|
||||
@ -127,6 +144,9 @@ func (l *Logger) SetWriter(writer io.Writer) {
|
||||
l.mu.Unlock()
|
||||
}
|
||||
|
||||
// GetWriter returns the customed writer object, which implements the io.Writer interface.
|
||||
// It returns nil if no customed writer set.
|
||||
//
|
||||
// 返回自定义的IO,默认为nil
|
||||
func (l *Logger) GetWriter() io.Writer {
|
||||
l.mu.RLock()
|
||||
@ -135,7 +155,10 @@ func (l *Logger) GetWriter() io.Writer {
|
||||
return r
|
||||
}
|
||||
|
||||
// 获取默认的文件IO
|
||||
// getFilePointer returns the file pinter for file logging.
|
||||
// It returns nil if file logging disabled, or file open fails.
|
||||
//
|
||||
// 获取默认的文件IO.
|
||||
func (l *Logger) getFilePointer() *gfpool.File {
|
||||
if path := l.path.Val(); path != "" {
|
||||
// 文件名称中使用"{}"包含的内容使用gtime格式化
|
||||
@ -159,7 +182,9 @@ func (l *Logger) getFilePointer() *gfpool.File {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 设置日志文件的存储目录路径
|
||||
// SetPath sets the directory path for file logging.
|
||||
//
|
||||
// 设置日志文件的存储目录路径.
|
||||
func (l *Logger) SetPath(path string) error {
|
||||
// path必须有值
|
||||
if path == "" {
|
||||
@ -176,16 +201,25 @@ func (l *Logger) SetPath(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPath returns the logging directory path for file logging.
|
||||
// It returns empty string if no directory path set.
|
||||
//
|
||||
// 获取设置的日志目录路径
|
||||
func (l *Logger) GetPath() string {
|
||||
return l.path.Val()
|
||||
}
|
||||
|
||||
// 日志文件名称
|
||||
func (l *Logger) SetFile(file string) {
|
||||
l.file.Set(file)
|
||||
// SetFile sets the file name <pattern> for file logging.
|
||||
// Datetime pattern can be used in <pattern>, eg: access-{Ymd}.log.
|
||||
// The default file name pattern is: Y-m-d.log, eg: 2018-01-01.log
|
||||
//
|
||||
// 设置日志文件名称格式.
|
||||
func (l *Logger) SetFile(pattern string) {
|
||||
l.file.Set(pattern)
|
||||
}
|
||||
|
||||
// SetStdPrint sets whether ouptput the logging contents to stdout, which is false indefault.
|
||||
//
|
||||
// 设置写日志时开启or关闭控制台打印,默认是关闭的
|
||||
func (l *Logger) SetStdPrint(enabled bool) {
|
||||
l.alsoStdPrint.Set(enabled)
|
||||
@ -263,11 +297,17 @@ func (l *Logger) appendBacktrace(s string, skip...int) string {
|
||||
return s
|
||||
}
|
||||
|
||||
// PrintBacktrace prints the caller backtrace,
|
||||
// the optional parameter <skip> specify the skipped backtraces offset from the end point.
|
||||
//
|
||||
// 直接打印回溯信息,参数skip表示调用端往上多少级开始回溯
|
||||
func (l *Logger) PrintBacktrace(skip...int) {
|
||||
l.Println(l.appendBacktrace("", skip...))
|
||||
}
|
||||
|
||||
// GetBacktrace returns the caller backtrace content,
|
||||
// the optional parameter <skip> specify the skipped backtraces offset from the end point.
|
||||
//
|
||||
// 获取文件调用回溯字符串,参数skip表示调用端往上多少级开始回溯
|
||||
func (l *Logger) GetBacktrace(skip...int) string {
|
||||
customSkip := 0
|
||||
@ -322,16 +362,19 @@ func (l *Logger) Printfln(format string, v ...interface{}) {
|
||||
l.stdPrint(fmt.Sprintf(format + ln, v...))
|
||||
}
|
||||
|
||||
// Fatal prints the logging content with [FATA] header and newline, then exit the current process.
|
||||
func (l *Logger) Fatal(v ...interface{}) {
|
||||
l.errPrint("[FATA] " + fmt.Sprintln(v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fatalf prints the logging content with [FATA] header and custom format, then exit the current process.
|
||||
func (l *Logger) Fatalf(format string, v ...interface{}) {
|
||||
l.errPrint("[FATA] " + fmt.Sprintf(format, v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fatalf prints the logging content with [FATA] header, custom format and newline, then exit the current process.
|
||||
func (l *Logger) Fatalfln(format string, v ...interface{}) {
|
||||
l.errPrint("[FATA] " + fmt.Sprintf(format + ln, v...))
|
||||
os.Exit(1)
|
||||
@ -463,6 +506,8 @@ func (l *Logger) Criticalfln(format string, v ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// checkLevel checks whether the given <level> could be output.
|
||||
//
|
||||
// 判断给定level是否满足
|
||||
func (l *Logger) checkLevel(level int) bool {
|
||||
return l.level.Val() & level > 0
|
||||
|
||||
@ -11,6 +11,9 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// To is a chaining function,
|
||||
// which redirects current logging content output to the sepecified <writer>.
|
||||
//
|
||||
// 链式操作,设置下一次写入日志内容的Writer
|
||||
func (l *Logger) To(writer io.Writer) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
@ -23,6 +26,9 @@ func (l *Logger) To(writer io.Writer) *Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
// Cat is a chaining function,
|
||||
// which sets the category to <category> for current logging content output.
|
||||
//
|
||||
// 链式操作,设置下一次输出的日志分类(可以按照文件目录层级设置),在当前logpath或者当前工作目录下创建category目录,
|
||||
// 这是一个链式操作,可以设置多个分类,将会创建层级的日志分类目录。
|
||||
func (l *Logger) Cat(category string) *Logger {
|
||||
@ -39,6 +45,9 @@ func (l *Logger) Cat(category string) *Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
// File is a chaining function,
|
||||
// which sets file name <pattern> for the current logging content output.
|
||||
//
|
||||
// 日志文件格式
|
||||
func (l *Logger) File(file string) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
@ -51,6 +60,9 @@ func (l *Logger) File(file string) *Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
// Level is a chaining function,
|
||||
// which sets logging level for the current logging content output.
|
||||
//
|
||||
// 设置日志打印等级
|
||||
func (l *Logger) Level(level int) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
@ -63,6 +75,9 @@ func (l *Logger) Level(level int) *Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
// Backtrace is a chaining function,
|
||||
// which sets backtrace options for the current logging content output .
|
||||
//
|
||||
// 设置文件调用回溯信息
|
||||
func (l *Logger) Backtrace(enabled bool, skip...int) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
@ -78,6 +93,9 @@ func (l *Logger) Backtrace(enabled bool, skip...int) *Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
// StdPrint is a chaining function,
|
||||
// which enables/disables stdout for the current logging content output.
|
||||
//
|
||||
// 是否允许在设置输出文件时同时也输出到终端
|
||||
func (l *Logger) StdPrint(enabled bool) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
@ -90,6 +108,9 @@ func (l *Logger) StdPrint(enabled bool) *Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
// Header is a chaining function,
|
||||
// which enables/disables log header for the current logging content output.
|
||||
//
|
||||
// 是否打印每行日志头信息(默认开启)
|
||||
func (l *Logger) Header(enabled bool) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
@ -27,8 +27,10 @@ const (
|
||||
gPROC_TEMP_DIR_ENV_KEY = "GPROC_TEMP_DIR"
|
||||
)
|
||||
|
||||
// 进程开始执行时间
|
||||
var processStartTime = time.Now()
|
||||
var (
|
||||
// 进程开始执行时间
|
||||
processStartTime = time.Now()
|
||||
)
|
||||
|
||||
// 获取当前进程ID
|
||||
func Pid() int {
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
// 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.
|
||||
|
||||
// "不要通过共享内存来通信,而应该通过通信来共享内存"
|
||||
|
||||
|
||||
@ -26,16 +27,43 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// 是否已开启TCP端口监听服务(使用int而非bool,以便于使用原子操作判断是否开启)
|
||||
tcpListeningCount = gtype.NewInt()
|
||||
// 是否已开启TCP端口监听服务
|
||||
tcpListened = gtype.NewBool()
|
||||
)
|
||||
|
||||
// 获取其他进程传递到当前进程的消息包,阻塞执行。
|
||||
// 进程只有在执行该方法后才会打开请求端口,默认情况下不允许进程间通信。
|
||||
func Receive(group...string) *Msg {
|
||||
// 一个进程只能开启一个监听goroutine
|
||||
if tcpListened.Set(true) == false {
|
||||
go startTcpListening()
|
||||
}
|
||||
queue := (*gqueue.Queue)(nil)
|
||||
groupName := gPROC_COMM_DEAFULT_GRUOP_NAME
|
||||
if len(group) > 0 {
|
||||
groupName = group[0]
|
||||
}
|
||||
if v := commReceiveQueues.Get(groupName); v == nil {
|
||||
commReceiveQueues.LockFunc(func(m map[string]interface{}) {
|
||||
if v, ok := m[groupName]; ok {
|
||||
queue = v.(*gqueue.Queue)
|
||||
} else {
|
||||
queue = gqueue.New(gPROC_MSG_QUEUE_MAX_LENGTH)
|
||||
m[groupName] = queue
|
||||
}
|
||||
})
|
||||
} else {
|
||||
queue = v.(*gqueue.Queue)
|
||||
}
|
||||
|
||||
if v := queue.Pop(); v != nil {
|
||||
return v.(*Msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 创建本地进程TCP通信服务
|
||||
func startTcpListening() {
|
||||
// 一个进程只能开启一个监听goroutine
|
||||
if tcpListeningCount.Add(1) != 1 {
|
||||
return
|
||||
}
|
||||
var listen *net.TCPListener
|
||||
for i := gPROC_DEFAULT_TCP_PORT; ; i++ {
|
||||
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("127.0.0.1:%d", i))
|
||||
@ -48,7 +76,6 @@ func startTcpListening() {
|
||||
}
|
||||
// 将监听的端口保存到通信文件中(字符串类型存放)
|
||||
gfile.PutContents(getCommFilePath(Pid()), gconv.String(i))
|
||||
//glog.Printfln("%d: gproc listening on [%s]", Pid(), addr)
|
||||
break
|
||||
}
|
||||
for {
|
||||
@ -133,32 +160,3 @@ func bufferToMsgs(buffer []byte) []*Msg {
|
||||
return msgs
|
||||
}
|
||||
|
||||
// 获取其他进程传递到当前进程的消息包,阻塞执行。
|
||||
func Receive(group...string) *Msg {
|
||||
// 开启接收协程时才会开启端口监听
|
||||
go startTcpListening()
|
||||
|
||||
var queue *gqueue.Queue
|
||||
groupName := gPROC_COMM_DEAFULT_GRUOP_NAME
|
||||
if len(group) > 0 {
|
||||
groupName = group[0]
|
||||
}
|
||||
|
||||
if v := commReceiveQueues.Get(groupName); v == nil {
|
||||
commReceiveQueues.LockFunc(func(m map[string]interface{}) {
|
||||
if v, ok := m[groupName]; ok {
|
||||
queue = v.(*gqueue.Queue)
|
||||
} else {
|
||||
queue = gqueue.New(gPROC_MSG_QUEUE_MAX_LENGTH)
|
||||
m[groupName] = queue
|
||||
}
|
||||
})
|
||||
} else {
|
||||
queue = v.(*gqueue.Queue)
|
||||
}
|
||||
|
||||
if v := queue.Pop(); v != nil {
|
||||
return v.(*Msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -7,16 +7,16 @@
|
||||
package gproc
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/net/gtcp"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"github.com/gogf/gf/g/encoding/gbinary"
|
||||
"fmt"
|
||||
"errors"
|
||||
"time"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/encoding/gbinary"
|
||||
"github.com/gogf/gf/g/net/gtcp"
|
||||
"github.com/gogf/gf/g/os/gfcache"
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -26,7 +26,7 @@ const (
|
||||
gPROC_COMM_DEAFULT_GRUOP_NAME = "" // 默认分组名称
|
||||
)
|
||||
|
||||
// 向指定gproc进程发送数据
|
||||
// 向指定gproc进程发送数据.
|
||||
// 数据格式:总长度(24bit)|发送进程PID(24bit)|接收进程PID(24bit)|分组长度(8bit)|分组名称(变长)|校验(32bit)|参数(变长)
|
||||
func Send(pid int, data []byte, group...string) error {
|
||||
groupName := gPROC_COMM_DEAFULT_GRUOP_NAME
|
||||
@ -85,6 +85,6 @@ func getConnByPid(pid int) (*gtcp.Conn, error) {
|
||||
// 获取指定进程监听的端口号
|
||||
func getPortByPid(pid int) int {
|
||||
path := getCommFilePath(pid)
|
||||
content := gfile.GetContents(path)
|
||||
content := gfcache.GetContents(path)
|
||||
return gconv.Int(content)
|
||||
}
|
||||
@ -13,17 +13,25 @@ import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Quote quotes <s> by replacing special chars in <s>
|
||||
// to match the rules of regular expression pattern.
|
||||
// And returns the copy.
|
||||
//
|
||||
// 转移正则规则字符串,例如:Quote(`[foo]`) 返回 `\[foo\]`
|
||||
func Quote(s string) string {
|
||||
return regexp.QuoteMeta(s)
|
||||
}
|
||||
|
||||
// Validate checks whether given regular expression pattern <pattern> valid.
|
||||
//
|
||||
// 校验所给定的正则表达式是否符合规范
|
||||
func Validate(pattern string) error {
|
||||
_, err := getRegexp(pattern)
|
||||
return err
|
||||
}
|
||||
|
||||
// IsMatch checks whether given bytes <src> matches <pattern>.
|
||||
//
|
||||
// 正则表达式是否匹配
|
||||
func IsMatch(pattern string, src []byte) bool {
|
||||
if r, err := getRegexp(pattern); err == nil {
|
||||
@ -32,10 +40,15 @@ func IsMatch(pattern string, src []byte) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsMatchString checks whether given string <src> matches <pattern>.
|
||||
//
|
||||
// 判断给定的字符串<src>是否满足正则表达式<pattern>.
|
||||
func IsMatchString(pattern string, src string) bool {
|
||||
return IsMatch(pattern, []byte(src))
|
||||
}
|
||||
|
||||
// MatchString return bytes slice that matched <pattern>.
|
||||
//
|
||||
// 正则匹配,并返回匹配的列表(参数[]byte)
|
||||
func Match(pattern string, src []byte) ([][]byte, error) {
|
||||
if r, err := getRegexp(pattern); err == nil {
|
||||
@ -45,6 +58,8 @@ func Match(pattern string, src []byte) ([][]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// MatchString return strings that matched <pattern>.
|
||||
//
|
||||
// 正则匹配,并返回匹配的列表(参数[]string)
|
||||
func MatchString(pattern string, src string) ([]string, error) {
|
||||
if r, err := getRegexp(pattern); err == nil {
|
||||
@ -54,6 +69,8 @@ func MatchString(pattern string, src string) ([]string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// MatchAll return all bytes slices that matched <pattern>.
|
||||
//
|
||||
// 正则匹配,并返回所有匹配的列表(参数[]string)
|
||||
func MatchAll(pattern string, src []byte) ([][][]byte, error) {
|
||||
if r, err := getRegexp(pattern); err == nil {
|
||||
@ -63,7 +80,9 @@ func MatchAll(pattern string, src []byte) ([][][]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 正则匹配,并返回所有匹配的列表(参数[][]string)
|
||||
// MatchAllString return all strings that matched <pattern>.
|
||||
//
|
||||
// 正则匹配,并返回所有匹配的列表(参数[][]string).
|
||||
func MatchAllString(pattern string, src string) ([][]string, error) {
|
||||
if r, err := getRegexp(pattern); err == nil {
|
||||
return r.FindAllStringSubmatch(src, -1), nil
|
||||
@ -72,7 +91,9 @@ func MatchAllString(pattern string, src string) ([][]string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 正则替换(全部替换)
|
||||
// ReplaceString replace all matched <pattern> in bytes <src> with bytes <replace>.
|
||||
//
|
||||
// 正则替换(全部替换).
|
||||
func Replace(pattern string, replace, src []byte) ([]byte, error) {
|
||||
if r, err := getRegexp(pattern); err == nil {
|
||||
return r.ReplaceAll(src, replace), nil
|
||||
@ -81,12 +102,17 @@ func Replace(pattern string, replace, src []byte) ([]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ReplaceString replace all matched <pattern> in string <src> with string <replace>.
|
||||
//
|
||||
// 正则替换(全部替换),字符串
|
||||
func ReplaceString(pattern, replace, src string) (string, error) {
|
||||
r, e := Replace(pattern, []byte(replace), []byte(src))
|
||||
return string(r), e
|
||||
}
|
||||
|
||||
// ReplaceFunc replace all matched <pattern> in bytes <src>
|
||||
// with custom replacement function <replaceFunc>.
|
||||
//
|
||||
// 正则替换(全部替换),给定自定义替换方法
|
||||
func ReplaceFunc(pattern string, src []byte, replaceFunc func(b []byte) []byte) ([]byte, error) {
|
||||
if r, err := getRegexp(pattern); err == nil {
|
||||
@ -96,6 +122,9 @@ func ReplaceFunc(pattern string, src []byte, replaceFunc func(b []byte) []byte)
|
||||
}
|
||||
}
|
||||
|
||||
// ReplaceStringFunc replace all matched <pattern> in string <src>
|
||||
// with custom replacement function <replaceFunc>.
|
||||
//
|
||||
// 正则替换(全部替换),给定自定义替换方法
|
||||
func ReplaceStringFunc(pattern string, src string, replaceFunc func(s string) string) (string, error) {
|
||||
bytes, err := ReplaceFunc(pattern, []byte(src), func(bytes []byte) []byte {
|
||||
|
||||
@ -6,9 +6,10 @@
|
||||
|
||||
// go test *.go -bench=".*"
|
||||
|
||||
package gregex
|
||||
package gregex_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -18,42 +19,42 @@ var replace = "johng.cn"
|
||||
|
||||
func BenchmarkValidate(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Validate(pattern)
|
||||
gregex.Validate(pattern)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIsMatch(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsMatch(pattern, []byte(src))
|
||||
gregex.IsMatch(pattern, []byte(src))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIsMatchString(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsMatchString(pattern, src)
|
||||
gregex.IsMatchString(pattern, src)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMatchString(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
MatchString(pattern, src)
|
||||
gregex.MatchString(pattern, src)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMatchAllString(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
MatchAllString(pattern, src)
|
||||
gregex.MatchAllString(pattern, src)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReplace(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Replace(pattern, []byte(replace), []byte(src))
|
||||
gregex.Replace(pattern, []byte(replace), []byte(src))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReplaceString(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
ReplaceString(pattern, replace, src)
|
||||
gregex.ReplaceString(pattern, replace, src)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/os/gcron"
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cron := gcron.New()
|
||||
glog.Println("start")
|
||||
cron.DelayAddOnce(1, "* * * * * *", func() {
|
||||
glog.Println("run")
|
||||
})
|
||||
func test() {
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
_, err := gcron.Add("*/10 * * * * ?", test)
|
||||
fmt.Println(err)
|
||||
fmt.Println(gcron.Entries())
|
||||
time.Sleep(10*time.Second)
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
package gf
|
||||
|
||||
const VERSION = "v1.5.3"
|
||||
const VERSION = "v1.5.4"
|
||||
const AUTHORS = "john<john@goframe.org>"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user