123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- package logger
- import (
- "crypto/md5"
- "encoding/hex"
- "fmt"
- "log"
- "os"
- "runtime"
- "runtime/debug"
- "strconv"
- "sync"
- "sync/atomic"
- "time"
- )
- var defaultlog *logBean = getdefaultLogger()
- var skip int = 4
- type logger struct {
- lb *logBean
- }
- func (this *logger) SetConsole(isConsole bool) {
- this.lb.setConsole(isConsole)
- }
- func (this *logger) SetLevel(_level LEVEL) {
- this.lb.setLevel(_level)
- }
- func (this *logger) SetFormat(logFormat string) {
- this.lb.setFormat(logFormat)
- }
- func (this *logger) SetRollingFile(fileDir, fileName string, maxNumber int32, maxSize int64, _unit UNIT) {
- this.lb.setRollingFile(fileDir, fileName, maxNumber, maxSize, _unit)
- }
- func (this *logger) SetRollingDaily(fileDir, fileName string) {
- this.lb.setRollingDaily(fileDir, fileName)
- }
- func (this *logger) Debug(v ...interface{}) {
- this.lb.debug(v...)
- }
- func (this *logger) Info(v ...interface{}) {
- this.lb.info(v...)
- }
- func (this *logger) Warn(v ...interface{}) {
- this.lb.warn(v...)
- }
- func (this *logger) Error(v ...interface{}) {
- this.lb.error(v...)
- }
- func (this *logger) Fatal(v ...interface{}) {
- this.lb.fatal(v...)
- }
- func (this *logger) SetLevelFile(level LEVEL, dir, fileName string) {
- this.lb.setLevelFile(level, dir, fileName)
- }
- type logBean struct {
- mu *sync.Mutex
- logLevel LEVEL
- maxFileSize int64
- maxFileCount int32
- consoleAppender bool
- rolltype _ROLLTYPE
- format string
- id string
- d, i, w, e, f string //id
- }
- type fileBeanFactory struct {
- fbs map[string]*fileBean
- mu *sync.RWMutex
- }
- var fbf = &fileBeanFactory{fbs: make(map[string]*fileBean, 0), mu: new(sync.RWMutex)}
- func (this *fileBeanFactory) add(dir, filename string, _suffix int, maxsize int64, maxfileCount int32) {
- this.mu.Lock()
- defer this.mu.Unlock()
- id := md5str(fmt.Sprint(dir, filename))
- if _, ok := this.fbs[id]; !ok {
- this.fbs[id] = newFileBean(dir, filename, _suffix, maxsize, maxfileCount)
- }
- }
- func (this *fileBeanFactory) get(id string) *fileBean {
- this.mu.RLock()
- defer this.mu.RUnlock()
- return this.fbs[id]
- }
- type fileBean struct {
- id string
- dir string
- filename string
- _suffix int
- _date *time.Time
- mu *sync.RWMutex
- logfile *os.File
- lg *log.Logger
- filesize int64
- maxFileSize int64
- maxFileCount int32
- }
- func GetLogger() (l *logger) {
- l = new(logger)
- l.lb = getdefaultLogger()
- return
- }
- func getdefaultLogger() (lb *logBean) {
- lb = &logBean{}
- lb.mu = new(sync.Mutex)
- lb.setConsole(true)
- return
- }
- func (this *logBean) setConsole(isConsole bool) {
- this.consoleAppender = isConsole
- }
- func (this *logBean) setLevelFile(level LEVEL, dir, fileName string) {
- key := md5str(fmt.Sprint(dir, fileName))
- switch level {
- case DEBUG:
- this.d = key
- case INFO:
- this.i = key
- case WARN:
- this.w = key
- case ERROR:
- this.e = key
- case FATAL:
- this.f = key
- default:
- return
- }
- var _suffix = 0
- if this.maxFileCount < 1<<31-1 {
- for i := 1; i < int(this.maxFileCount); i++ {
- if isExist(dir + "/" + fileName + "." + strconv.Itoa(i)) {
- _suffix = i
- } else {
- break
- }
- }
- }
- fbf.add(dir, fileName, _suffix, this.maxFileSize, this.maxFileCount)
- }
- func (this *logBean) setLevel(_level LEVEL) {
- this.logLevel = _level
- }
- func (this *logBean) setFormat(logFormat string) {
- this.format = logFormat
- }
- func (this *logBean) setRollingFile(fileDir, fileName string, maxNumber int32, maxSize int64, _unit UNIT) {
- this.mu.Lock()
- defer this.mu.Unlock()
- if maxNumber > 0 {
- this.maxFileCount = maxNumber
- } else {
- this.maxFileCount = 1<<31 - 1
- }
- this.maxFileSize = maxSize * int64(_unit)
- this.rolltype = _ROLLFILE
- mkdirlog(fileDir)
- var _suffix = 0
- for i := 1; i < int(maxNumber); i++ {
- if isExist(fileDir + "/" + fileName + "." + strconv.Itoa(i)) {
- _suffix = i
- } else {
- break
- }
- }
- this.id = md5str(fmt.Sprint(fileDir, fileName))
- fbf.add(fileDir, fileName, _suffix, this.maxFileSize, this.maxFileCount)
- }
- func (this *logBean) setRollingDaily(fileDir, fileName string) {
- this.rolltype = _DAILY
- mkdirlog(fileDir)
- this.id = md5str(fmt.Sprint(fileDir, fileName))
- fbf.add(fileDir, fileName, 0, 0, 0)
- }
- func (this *logBean) console(v ...interface{}) {
- s := fmt.Sprint(v...)
- if this.consoleAppender {
- _, file, line, _ := runtime.Caller(skip)
- short := file
- for i := len(file) - 1; i > 0; i-- {
- if file[i] == '/' {
- short = file[i+1:]
- break
- }
- }
- file = short
- if this.format == "" {
- log.Println(file, strconv.Itoa(line), s)
- } else {
- vs := make([]interface{}, 0)
- vs = append(vs, file)
- vs = append(vs, strconv.Itoa(line))
- for _, vv := range v {
- vs = append(vs, vv)
- }
- log.Printf(fmt.Sprint("%s %s ", this.format, "\n"), vs...)
- }
- }
- }
- func (this *logBean) log(level string, v ...interface{}) {
- defer catchError()
- //s := fmt.Sprint(v...)
- s := ""
- for _, val := range v {
- s += " " + fmt.Sprint(val)
- }
- length := len([]byte(s))
- var lg *fileBean = fbf.get(this.id)
- var _level = ALL
- switch level {
- case "debug":
- if this.d != "" {
- lg = fbf.get(this.d)
- }
- _level = DEBUG
- case "info":
- if this.i != "" {
- lg = fbf.get(this.i)
- }
- _level = INFO
- case "warn":
- if this.w != "" {
- lg = fbf.get(this.w)
- }
- _level = WARN
- case "error":
- if this.e != "" {
- lg = fbf.get(this.e)
- }
- _level = ERROR
- case "fatal":
- if this.f != "" {
- lg = fbf.get(this.f)
- }
- _level = FATAL
- }
- if lg != nil {
- this.fileCheck(lg)
- lg.addsize(int64(length))
- if this.logLevel <= _level {
- if lg != nil {
- if this.format == "" {
- lg.write(level, s)
- } else {
- lg.writef(this.format, v...)
- }
- }
- this.console(v...)
- }
- } else {
- this.console(v...)
- }
- }
- func (this *logBean) debug(v ...interface{}) {
- this.log("debug", v...)
- }
- func (this *logBean) info(v ...interface{}) {
- this.log("info", v...)
- }
- func (this *logBean) warn(v ...interface{}) {
- this.log("warn", v...)
- }
- func (this *logBean) error(v ...interface{}) {
- this.log("error", v...)
- }
- func (this *logBean) fatal(v ...interface{}) {
- this.log("fatal", v...)
- }
- func (this *logBean) fileCheck(fb *fileBean) {
- defer catchError()
- if this.isMustRename(fb) {
- this.mu.Lock()
- defer this.mu.Unlock()
- if this.isMustRename(fb) {
- fb.rename(this.rolltype)
- }
- }
- }
- //--------------------------------------------------------------------------------
- func (this *logBean) isMustRename(fb *fileBean) bool {
- switch this.rolltype {
- case _DAILY:
- t, _ := time.Parse(_DATEFORMAT, time.Now().Format(_DATEFORMAT))
- if t.After(*fb._date) {
- return true
- }
- case _ROLLFILE:
- return fb.isOverSize()
- }
- return false
- }
- func (this *fileBean) nextSuffix() int {
- return int(this._suffix%int(this.maxFileCount) + 1)
- }
- func newFileBean(fileDir, fileName string, _suffix int, maxSize int64, maxfileCount int32) (fb *fileBean) {
- t, _ := time.Parse(_DATEFORMAT, time.Now().Format(_DATEFORMAT))
- fb = &fileBean{dir: fileDir, filename: fileName, _date: &t, mu: new(sync.RWMutex)}
- fb.logfile, _ = os.OpenFile(fileDir+"/"+fileName, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
- fb.lg = log.New(fb.logfile, "", log.Ldate|log.Ltime|log.Lshortfile)
- fb._suffix = _suffix
- fb.maxFileSize = maxSize
- fb.maxFileCount = maxfileCount
- fb.filesize = fileSize(fileDir + "/" + fileName)
- fb._date = &t
- return
- }
- func (this *fileBean) rename(rolltype _ROLLTYPE) {
- this.mu.Lock()
- defer this.mu.Unlock()
- this.close()
- nextfilename := ""
- switch rolltype {
- case _DAILY:
- nextfilename = fmt.Sprint(this.dir, "/", this.filename, ".", this._date.Format(_DATEFORMAT))
- case _ROLLFILE:
- nextfilename = fmt.Sprint(this.dir, "/", this.filename, ".", this.nextSuffix())
- this._suffix = this.nextSuffix()
- }
- if isExist(nextfilename) {
- os.Remove(nextfilename)
- }
- os.Rename(this.dir+"/"+this.filename, nextfilename)
- t, _ := time.Parse(_DATEFORMAT, time.Now().Format(_DATEFORMAT))
- this._date = &t
- this.logfile, _ = os.OpenFile(this.dir+"/"+this.filename, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
- this.lg = log.New(this.logfile, "", log.Ldate|log.Ltime|log.Lshortfile)
- this.filesize = fileSize(this.dir + "/" + this.filename)
- }
- func (this *fileBean) addsize(size int64) {
- atomic.AddInt64(&this.filesize, size)
- }
- func (this *fileBean) write(level string, v ...interface{}) {
- this.mu.RLock()
- defer this.mu.RUnlock()
- s := fmt.Sprint(v...)
- this.lg.Output(skip+1, fmt.Sprintln(level, s))
- }
- func (this *fileBean) writef(format string, v ...interface{}) {
- this.mu.RLock()
- defer this.mu.RUnlock()
- this.lg.Output(skip+1, fmt.Sprintf(format, v...))
- }
- func (this *fileBean) isOverSize() bool {
- return this.filesize >= this.maxFileSize
- }
- func (this *fileBean) close() {
- this.logfile.Close()
- }
- //-----------------------------------------------------------------------------------------------
- func mkdirlog(dir string) (e error) {
- _, er := os.Stat(dir)
- b := er == nil || os.IsExist(er)
- if !b {
- if err := os.MkdirAll(dir, 0666); err != nil {
- if os.IsPermission(err) {
- e = err
- }
- }
- }
- return
- }
- func fileSize(file string) int64 {
- f, e := os.Stat(file)
- if e != nil {
- fmt.Println(e.Error())
- return 0
- }
- return f.Size()
- }
- func isExist(path string) bool {
- _, err := os.Stat(path)
- return err == nil || os.IsExist(err)
- }
- func md5str(s string) string {
- m := md5.New()
- m.Write([]byte(s))
- return hex.EncodeToString(m.Sum(nil))
- }
- func catchError() {
- if err := recover(); err != nil {
- fmt.Println(string(debug.Stack()))
- }
- }
|