diff --git a/g/os/gfilepool/gfilepool.go b/g/os/gfilepool/gfilepool.go index 5c233bb8e..751f99a98 100644 --- a/g/os/gfilepool/gfilepool.go +++ b/g/os/gfilepool/gfilepool.go @@ -12,10 +12,10 @@ import ( "time" "sync" "strconv" - "sync/atomic" "gitee.com/johng/gf/g/os/gtime" "gitee.com/johng/gf/g/container/gmap" "gitee.com/johng/gf/g/container/glist" + "gitee.com/johng/gf/g/container/gtype" ) // 文件指针池 @@ -23,23 +23,23 @@ type Pool struct { path string // 文件绝对路径 flag int // 文件打开标识 list *glist.List // 可用/闲置的文件指针链表 - idlemax int // 闲置最大时间,超过该时间则被系统回收(秒) - closed bool // 连接池是否已关闭 + idle int // 闲置最大时间,超过该时间则被系统回收(秒) + closed *gtype.Bool // 连接池是否已关闭 } // 文件指针池指针 -type File struct { - sync.RWMutex - pool *Pool // 所属池 - file *os.File // 指针对象 - expire int64 // 过期时间(秒) +type PoolItem struct { + mu sync.RWMutex + pool *Pool // 所属池 + file *os.File // 指针对象 + expire *gtype.Int64 // 过期时间(秒) } // 全局指针池,expire < 0表示不过期,expire = 0表示使用完立即回收,expire > 0表示超时回收 -var pools *gmap.StringInterfaceMap = gmap.NewStringInterfaceMap() +var pools = gmap.NewStringInterfaceMap() // 获得文件对象,并自动创建指针池 -func OpenWithPool(path string, flag int, expire int) (*File, error) { +func OpenWithPool(path string, flag int, expire int) (*PoolItem, error) { key := path + strconv.Itoa(flag) + strconv.Itoa(expire) result := pools.Get(key) if result != nil { @@ -56,21 +56,22 @@ func New(path string, flag int, expire int) *Pool { path : path, flag : flag, list : glist.New(), - idlemax : expire, + idle : expire, } // 独立的线程执行过期清理工作 if expire != -1 { go func(p *Pool) { // 遍历可用指针列表,判断是否过期 - for !p.closed { - r := p.list.Front() - if r != nil && r.Value != nil { - f := r.Value.(*File) + for !p.closed.Val() { + if r := p.list.PopFront(); r != nil { + f := r.(*PoolItem) // 必须小于,中间有1秒的缓存时间,防止同时获取和判断过期时冲突 - if f.getExpire() < gtime.Second() { + if f.expire.Val() < gtime.Second() { f.destroy() - p.list.Remove(r) - continue + } else { + // 重新推回去 + p.list.PushFront(f) + break } } time.Sleep(3 * time.Second) @@ -81,21 +82,19 @@ func New(path string, flag int, expire int) *Pool { } // 获得一个文件打开指针 -func (p *Pool) File() (*File, error) { +func (p *Pool) File() (*PoolItem, error) { if p.list.Len() > 0 { - // 遍历可用指针列表,返回一个未过期的指针 for { - r := p.list.PopBack() - if r != nil { - f := r.(*File) - // 必须大于 - if f.getExpire() > gtime.Second() { + // 从队列头依次查找,返回一个未过期的指针 + if r := p.list.PopFront(); r != nil { + f := r.(*PoolItem) + if f.expire.Val() > gtime.Second() { return f, nil } else if f.file != nil { f.destroy() } } else { - break; + break } } } @@ -103,44 +102,30 @@ func (p *Pool) File() (*File, error) { if err != nil { return nil, err } - return &File { - pool : p, - file : file, + return &PoolItem { + pool : p, + file : file, + expire : gtype.NewInt64(), }, nil } // 关闭指针池 func (p *Pool) Close() { - p.closed = true + p.closed.Set(true) } // 获得底层文件指针 -func (f *File) File() *os.File { +func (f *PoolItem) File() *os.File { return f.file } // 关闭指针链接(软关闭),放回池中重复使用 -func (f *File) Close() { - f.setExpire(gtime.Second() + int64(f.pool.idlemax)) - f.pool.list.PushFront(f) +func (f *PoolItem) Close() { + f.expire.Set(gtime.Second() + int64(f.pool.idle)) + f.pool.list.PushBack(f) } // 销毁指针 -func (f *File) destroy() { - f.Lock() - defer f.Unlock() - if f.file != nil { - f.file.Close() - f.file = nil - } -} - -// 获取指针过期时间 -func (f *File) setExpire(expire int64) { - atomic.StoreInt64(&f.expire, expire) -} - -// 获取指针过期时间 -func (f *File) getExpire() int64 { - return atomic.LoadInt64(&f.expire) +func (f *PoolItem) destroy() { + f.file.Close() } \ No newline at end of file diff --git a/g/os/glog/glog.go b/g/os/glog/glog.go index 23b96eb71..eb8cd3118 100644 --- a/g/os/glog/glog.go +++ b/g/os/glog/glog.go @@ -9,27 +9,16 @@ package glog import ( - "sync" - "os" "io" - "time" - "fmt" - "errors" - "strings" - "path/filepath" - "gitee.com/johng/gf/g/os/gfile" - "gitee.com/johng/gf/g/os/gfilepool" - "runtime" - "strconv" - "gitee.com/johng/gf/g/util/gregx" + "sync" + "gitee.com/johng/gf/g/container/gtype" ) type Logger struct { - mutex sync.RWMutex - logio io.Writer - debug bool // 是否允许输出DEBUG信息 - logpath string // 日志写入的目录路径 - lastlogdate string // 上一次写入日志的日期,例如: 2006-01-02 + mu sync.RWMutex + io io.Writer // 日志内容写入的IO接口 + path *gtype.String // 日志写入的目录路径 + debug *gtype.Bool // 是否允许输出DEBUG信息 } // 默认的日志对象 @@ -37,14 +26,16 @@ var logger = New() // 新建自定义的日志操作对象 func New() *Logger { - return &Logger{ - debug : true, + return &Logger { + io : nil, + path : gtype.NewString(), + debug : gtype.NewBool(true), } } // 日志日志目录绝对路径 -func SetLogPath(path string) { - logger.SetLogPath(path) +func SetPath(path string) { + logger.SetPath(path) } // 设置是否允许输出DEBUG信息 @@ -53,8 +44,8 @@ func SetDebug(debug bool) { } // 获取日志目录绝对路径 -func GetLogPath() string { - return logger.GetLogPath() +func GetPath() string { + return logger.path.Val() } func Print(v ...interface{}) { @@ -176,274 +167,3 @@ func Errorfln(format string, v ...interface{}) { func Criticalfln(format string, v ...interface{}) { logger.Criticalfln(format, v...) } - -func (l *Logger) GetLogIO() io.Writer { - l.mutex.RLock() - r := l.logio - l.mutex.RUnlock() - return r -} - -func (l *Logger) GetDebug() bool { - l.mutex.RLock() - r := l.debug - l.mutex.RUnlock() - return r -} - -func (l *Logger) GetLogPath() string { - l.mutex.RLock() - r := l.logpath - l.mutex.RUnlock() - return r -} - -func (l *Logger) GetLastLogDate() string { - l.mutex.RLock() - r := l.lastlogdate - l.mutex.RUnlock() - return r -} - -func (l *Logger) SetLogIO(w io.Writer) { - l.mutex.RLock() - l.logio = w - l.mutex.RUnlock() -} - -func (l *Logger) SetDebug(debug bool) { - l.mutex.Lock() - l.debug = debug - l.mutex.Unlock() -} - -// 设置日志文件的存储目录路径 -func (l *Logger) SetLogPath(path string) error { - // 检测目录权限 - if !gfile.Exists(path) { - if err := gfile.Mkdir(path); err != nil { - fmt.Fprintln(os.Stderr, err) - return err - } - } - if !gfile.IsWritable(path) { - errstr := path + " is no writable for current user" - fmt.Fprintln(os.Stderr, errstr) - return errors.New(errstr) - } - l.mutex.Lock() - l.logpath = strings.TrimRight(path, string(filepath.Separator)) - l.mutex.Unlock() - // 重新检查日志io对象 - l.checkLogIO() - return nil -} - -// 检查文件名称是否已经过期,如果过期那么需要新建一个日志文件(默认按照日期分隔) -func (l *Logger) checkLogIO() { - date := time.Now().Format("2006-01-02") - if date != l.GetLastLogDate() { - if path := l.GetLogPath(); path != "" { - fname := date + ".log" - fpath := path + string(filepath.Separator) + fname - if fp, err := gfilepool.OpenWithPool(fpath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 600); err == nil { - l.SetLogIO(fp.File()) - fp.Close() - } else { - fmt.Fprintln(os.Stderr, err) - } - } - } -} - -// 这里的互斥锁保证统一时刻只会写入一行日志,防止串日志的情况 -func (l *Logger) print(logio io.Writer, s string) { - l.mutex.Lock() - fmt.Fprint(logio, l.format(s)) - l.mutex.Unlock() -} - -// 核心打印数据方法(标准输出) -func (l *Logger) stdPrint(s string) { - l.checkLogIO() - logio := l.GetLogIO() - if logio == nil { - logio = os.Stdout - } - l.print(logio, s) -} - -// 核心打印数据方法(标准错误) -func (l *Logger) errPrint(s string) { - l.checkLogIO() - logio := l.GetLogIO() - if logio == nil { - logio = os.Stderr - } - // 记录调用回溯信息 - backtrace := l.backtrace() - if s[len(s) - 1] == byte('\n') { - s = s + backtrace + "\n" - } else { - s = s + "\n" + backtrace + "\n" - } - l.print(logio, s) -} - -// 调用回溯字符串 -func (l *Logger) backtrace() string { - backtrace := "Trace:\n" - for i := 1; i < 10000; i++ { - if _, cfile, cline, ok := runtime.Caller(i + 3); ok { - // 不打印出go源码路径 - if !gregx.IsMatchString("^" + runtime.GOROOT(), cfile) { - backtrace += strconv.Itoa(i) + ". " + cfile + ":" + strconv.Itoa(cline) + "\n" - } - } else { - break - } - } - return backtrace -} - -func (l *Logger) format(s string) string { - return time.Now().Format("2006-01-02 15:04:05.000 ") + s -} - -func (l *Logger) Print(v ...interface{}) { - l.stdPrint(fmt.Sprint(v...)) -} - -func (l *Logger) Printf(format string, v ...interface{}) { - l.stdPrint(fmt.Sprintf(format, v...)) -} - -func (l *Logger) Println(v ...interface{}) { - l.stdPrint(fmt.Sprintln(v...)) -} - -func (l *Logger) Printfln(format string, v ...interface{}) { - l.stdPrint(fmt.Sprintf(format + "\n", v...)) -} - -func (l *Logger) Fatal(v ...interface{}) { - l.errPrint(fmt.Sprint(v...)) - os.Exit(1) -} - -func (l *Logger) Fatalf(format string, v ...interface{}) { - l.errPrint(fmt.Sprintf(format, v...)) - os.Exit(1) -} - -func (l *Logger) Fatalln(v ...interface{}) { - l.errPrint(fmt.Sprintln(v...)) - os.Exit(1) -} - -func (l *Logger) Fatalfln(format string, v ...interface{}) { - l.errPrint(fmt.Sprintf(format + "\n", v...)) - os.Exit(1) -} - -func (l *Logger) Panic(v ...interface{}) { - s := fmt.Sprint(v...) - l.errPrint(s) - panic(s) -} - -func (l *Logger) Panicf(format string, v ...interface{}) { - s := fmt.Sprintf(format, v...) - l.errPrint(s) - panic(s) -} - -func (l *Logger) Panicln(v ...interface{}) { - s := fmt.Sprintln(v...) - l.errPrint(s) - panic(s) -} - -func (l *Logger) Panicfln(format string, v ...interface{}) { - s := fmt.Sprintf(format + "\n", v...) - l.errPrint(s) - panic(s) -} - -func (l *Logger) Info(v ...interface{}) { - l.stdPrint("[INFO] " + fmt.Sprintln(v...)) -} - -func (l *Logger) Debug(v ...interface{}) { - if l.GetDebug() { - l.stdPrint("[DEBU] " + fmt.Sprintln(v...)) - } -} - -func (l *Logger) Notice(v ...interface{}) { - l.errPrint("[NOTI] " + fmt.Sprintln(v...)) -} - -func (l *Logger) Warning(v ...interface{}) { - l.errPrint("[WARN] " + fmt.Sprintln(v...)) -} - -func (l *Logger) Error(v ...interface{}) { - l.errPrint("[ERRO] " + fmt.Sprintln(v...)) -} - -func (l *Logger) Critical(v ...interface{}) { - l.errPrint("[CRIT] " + fmt.Sprintln(v...)) -} - -func (l *Logger) Infof(format string, v ...interface{}) { - l.stdPrint("[INFO] " + fmt.Sprintf(format, v...)) -} - -func (l *Logger) Debugf(format string, v ...interface{}) { - if l.GetDebug() { - l.stdPrint("[DEBU] " + fmt.Sprintf(format, v...)) - } -} - -func (l *Logger) Noticef(format string, v ...interface{}) { - l.errPrint("[NOTI] " + fmt.Sprintf(format, v...)) -} - -func (l *Logger) Warningf(format string, v ...interface{}) { - l.errPrint("[WARN] " + fmt.Sprintf(format, v...)) -} - -func (l *Logger) Errorf(format string, v ...interface{}) { - l.errPrint("[ERRO] " + fmt.Sprintf(format, v...)) -} - -func (l *Logger) Criticalf(format string, v ...interface{}) { - l.errPrint("[CRIT] " + fmt.Sprintf(format, v...)) -} - -func (l *Logger) Infofln(format string, v ...interface{}) { - l.stdPrint("[INFO] " + fmt.Sprintf(format, v...) + "\n") -} - -func (l *Logger) Debugfln(format string, v ...interface{}) { - if l.GetDebug() { - l.stdPrint("[DEBU] " + fmt.Sprintf(format, v...) + "\n") - } -} - -func (l *Logger) Noticefln(format string, v ...interface{}) { - l.errPrint("[NOTI] " + fmt.Sprintf(format, v...) + "\n") -} - -func (l *Logger) Warningfln(format string, v ...interface{}) { - l.errPrint("[WARN] " + fmt.Sprintf(format, v...) + "\n") -} - -func (l *Logger) Errorfln(format string, v ...interface{}) { - l.errPrint("[ERRO] " + fmt.Sprintf(format, v...) + "\n") -} - -func (l *Logger) Criticalfln(format string, v ...interface{}) { - l.errPrint("[CRIT] " + fmt.Sprintf(format, v...) + "\n") -} \ No newline at end of file diff --git a/g/os/glog/glog_logger.go b/g/os/glog/glog_logger.go new file mode 100644 index 000000000..58888cc0a --- /dev/null +++ b/g/os/glog/glog_logger.go @@ -0,0 +1,270 @@ +// Copyright 2017 gf Author(https://gitee.com/johng/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://gitee.com/johng/gf. + +package glog + +import ( + "os" + "io" + "time" + "fmt" + "errors" + "strings" + "runtime" + "strconv" + "gitee.com/johng/gf/g/os/gfile" + "gitee.com/johng/gf/g/util/gregx" + "gitee.com/johng/gf/g/os/gfilepool" +) + +const ( + gDEFAULT_FILE_POOL_FLAGS = os.O_CREATE|os.O_WRONLY|os.O_APPEND +) + +// 可自定义IO接口 +func (l *Logger) SetIO(w io.Writer) { + l.mu.RLock() + l.io = w + l.mu.RUnlock() +} + +// 返回自定义IO +func (l *Logger) GetIO() io.Writer { + l.mu.RLock() + r := l.io + l.mu.RUnlock() + return r +} + +// 获取默认的文件IO +func (l *Logger) getFileByPool() *gfilepool.PoolItem { + if path := l.path.Val(); path != "" { + fpath := path + gfile.Separator + time.Now().Format("2006-01-02.log") + if fp, err := gfilepool.OpenWithPool(fpath, gDEFAULT_FILE_POOL_FLAGS, 86400); err == nil { + return fp + } else { + fmt.Fprintln(os.Stderr, err) + } + } + return nil +} + +func (l *Logger) GetDebug() bool { + return l.debug.Val() +} + +func (l *Logger) SetDebug(debug bool) { + l.debug.Set(debug) +} + +// 设置日志文件的存储目录路径 +func (l *Logger) SetPath(path string) error { + // 检测目录权限 + if !gfile.Exists(path) { + if err := gfile.Mkdir(path); err != nil { + fmt.Fprintln(os.Stderr, err) + return err + } + } + if !gfile.IsWritable(path) { + errstr := path + " is no writable for current user" + fmt.Fprintln(os.Stderr, errstr) + return errors.New(errstr) + } + l.path.Set(strings.TrimRight(path, gfile.Separator)) + return nil +} + +// 这里的写锁保证统一时刻只会写入一行日志,防止串日志的情况 +func (l *Logger) print(defaultIO io.Writer, s string) { + w := l.GetIO() + if w == nil { + if v := l.getFileByPool(); v != nil { + w = v.File() + defer v.Close() + } else { + w = defaultIO + } + } + l.mu.Lock() + fmt.Fprint(w, l.format(s)) + l.mu.Unlock() +} + +// 核心打印数据方法(标准输出) +func (l *Logger) stdPrint(s string) { + l.print(os.Stdout, s) +} + +// 核心打印数据方法(标准错误) +func (l *Logger) errPrint(s string) { + // 记录调用回溯信息 + backtrace := l.backtrace() + if s[len(s) - 1] == byte('\n') { + s = s + backtrace + "\n" + } else { + s = s + "\n" + backtrace + "\n" + } + l.print(os.Stderr, s) +} + +// 调用回溯字符串 +func (l *Logger) backtrace() string { + backtrace := "Trace:\n" + for i := 1; i < 10000; i++ { + if _, cfile, cline, ok := runtime.Caller(i + 3); ok { + // 不打印出go源码路径 + if !gregx.IsMatchString("^" + runtime.GOROOT(), cfile) { + backtrace += strconv.Itoa(i) + ". " + cfile + ":" + strconv.Itoa(cline) + "\n" + } + } else { + break + } + } + return backtrace +} + +func (l *Logger) format(s string) string { + return time.Now().Format("2006-01-02 15:04:05.000 ") + s +} + +func (l *Logger) Print(v ...interface{}) { + l.stdPrint(fmt.Sprint(v...)) +} + +func (l *Logger) Printf(format string, v ...interface{}) { + l.stdPrint(fmt.Sprintf(format, v...)) +} + +func (l *Logger) Println(v ...interface{}) { + l.stdPrint(fmt.Sprintln(v...)) +} + +func (l *Logger) Printfln(format string, v ...interface{}) { + l.stdPrint(fmt.Sprintf(format + "\n", v...)) +} + +func (l *Logger) Fatal(v ...interface{}) { + l.errPrint(fmt.Sprint(v...)) + os.Exit(1) +} + +func (l *Logger) Fatalf(format string, v ...interface{}) { + l.errPrint(fmt.Sprintf(format, v...)) + os.Exit(1) +} + +func (l *Logger) Fatalln(v ...interface{}) { + l.errPrint(fmt.Sprintln(v...)) + os.Exit(1) +} + +func (l *Logger) Fatalfln(format string, v ...interface{}) { + l.errPrint(fmt.Sprintf(format + "\n", v...)) + os.Exit(1) +} + +func (l *Logger) Panic(v ...interface{}) { + s := fmt.Sprint(v...) + l.errPrint(s) + panic(s) +} + +func (l *Logger) Panicf(format string, v ...interface{}) { + s := fmt.Sprintf(format, v...) + l.errPrint(s) + panic(s) +} + +func (l *Logger) Panicln(v ...interface{}) { + s := fmt.Sprintln(v...) + l.errPrint(s) + panic(s) +} + +func (l *Logger) Panicfln(format string, v ...interface{}) { + s := fmt.Sprintf(format + "\n", v...) + l.errPrint(s) + panic(s) +} + +func (l *Logger) Info(v ...interface{}) { + l.stdPrint("[INFO] " + fmt.Sprintln(v...)) +} + +func (l *Logger) Debug(v ...interface{}) { + if l.GetDebug() { + l.stdPrint("[DEBU] " + fmt.Sprintln(v...)) + } +} + +func (l *Logger) Notice(v ...interface{}) { + l.errPrint("[NOTI] " + fmt.Sprintln(v...)) +} + +func (l *Logger) Warning(v ...interface{}) { + l.errPrint("[WARN] " + fmt.Sprintln(v...)) +} + +func (l *Logger) Error(v ...interface{}) { + l.errPrint("[ERRO] " + fmt.Sprintln(v...)) +} + +func (l *Logger) Critical(v ...interface{}) { + l.errPrint("[CRIT] " + fmt.Sprintln(v...)) +} + +func (l *Logger) Infof(format string, v ...interface{}) { + l.stdPrint("[INFO] " + fmt.Sprintf(format, v...)) +} + +func (l *Logger) Debugf(format string, v ...interface{}) { + if l.GetDebug() { + l.stdPrint("[DEBU] " + fmt.Sprintf(format, v...)) + } +} + +func (l *Logger) Noticef(format string, v ...interface{}) { + l.errPrint("[NOTI] " + fmt.Sprintf(format, v...)) +} + +func (l *Logger) Warningf(format string, v ...interface{}) { + l.errPrint("[WARN] " + fmt.Sprintf(format, v...)) +} + +func (l *Logger) Errorf(format string, v ...interface{}) { + l.errPrint("[ERRO] " + fmt.Sprintf(format, v...)) +} + +func (l *Logger) Criticalf(format string, v ...interface{}) { + l.errPrint("[CRIT] " + fmt.Sprintf(format, v...)) +} + +func (l *Logger) Infofln(format string, v ...interface{}) { + l.stdPrint("[INFO] " + fmt.Sprintf(format, v...) + "\n") +} + +func (l *Logger) Debugfln(format string, v ...interface{}) { + if l.GetDebug() { + l.stdPrint("[DEBU] " + fmt.Sprintf(format, v...) + "\n") + } +} + +func (l *Logger) Noticefln(format string, v ...interface{}) { + l.errPrint("[NOTI] " + fmt.Sprintf(format, v...) + "\n") +} + +func (l *Logger) Warningfln(format string, v ...interface{}) { + l.errPrint("[WARN] " + fmt.Sprintf(format, v...) + "\n") +} + +func (l *Logger) Errorfln(format string, v ...interface{}) { + l.errPrint("[ERRO] " + fmt.Sprintf(format, v...) + "\n") +} + +func (l *Logger) Criticalfln(format string, v ...interface{}) { + l.errPrint("[CRIT] " + fmt.Sprintf(format, v...) + "\n") +} \ No newline at end of file diff --git a/geg/other/test.go b/geg/other/test.go index cb468f30c..4494b20ca 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -2,12 +2,19 @@ package main import ( "gitee.com/johng/gf/g/net/ghttp" + "gitee.com/johng/gf/g/frame/gins" ) func main() { s := ghttp.GetServer() - s.SetServerRoot("/home/john/Documents") - s.SetIndexFolder(true) - s.SetPort(8199) + s.BindHandler("/template2", func(r *ghttp.Request){ + tplcontent := `id:{{.id}}, name:{{.name}}` + content, _ := gins.View().ParseContent(tplcontent, map[string]interface{}{ + "id" : 123, + "name" : "john", + }) + r.Response.Write(content) + }) + //s.SetPort(8199) s.Run() } \ No newline at end of file