刚上手golang的时候看log库,为了练手就写了个logger库自己用 主要是设定几个日志级别,然后可以按照大小轮转日志,并限定日志个数。
####模拟linux的syslog轮转xxx.log.1 xxx.log.2 .... 这样
####希望大家帮忙看看,有什么问题,谢谢
####logger.go
package logger
import (
"fmt"
"os"
"sync"
"path/filepath"
"strings"
"strconv"
"time"
"runtime"
)
// 检查文件或目录是否存在
// 如果由 filename 指定的文件或目录存在则返回 true,否则返回 false
func Exist(filename string) bool {
_, err := os.Stat(filename)
return err == nil || os.IsExist(err)
}
type level int
const (
DetailLog level = iota
DebugLog
InfoLog
WarnLog
ErrorLog
PanicLog
LevelNum = 6
)
const levelChar = "TDIWEP"
var levelName = []string{
DetailLog: "DETAIL",
DebugLog: "DEBUG",
InfoLog: "INFO",
WarnLog: "WARN",
ErrorLog: "ERROR",
PanicLog: "PANIC",
}
var logging = &loggingT{toStderr:true, outputLevel:DetailLog, w:os.Stderr}
func SetLevel(l level) {
logging.outputLevel = l
}
func SetRotatingFile(path string, maxBytes int64, backCount int) bool {
dir := filepath.Dir(path)
if !strings.EqualFold(dir, ".") {
if err := os.MkdirAll(dir, 0755); err != nil {
fmt.Printf("ERROR - MkdirAll(%s): %s\n", dir, err.Error())
return false
}
}
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
fmt.Printf("ERROR - OpenFile(%s): %s\n", path, err.Error())
return false
}
logging.toStderr = false
logging.filename = path
logging.w = f
logging.maxBytes = maxBytes
logging.backCount = backCount
//fmt.Printf("%#v", logging)
return true
}
func Detail(format string, v ...interface{}) {
logging.printf(DetailLog, format, v...)
}
func Debug(format string, v ...interface{}) {
logging.printf(DebugLog, format, v...)
}
func Info(format string, v ...interface{}) {
logging.printf(InfoLog, format, v...)
}
func Warn(format string, v ...interface{}) {
logging.printf(WarnLog, format, v...)
}
func Error(format string, v ...interface{}) {
logging.printf(ErrorLog, format, v...)
}
func Panic(format string, v ...interface{}) {
logging.printf(PanicLog, format, v...)
}
// loggingT collects all the global state of the logging setup.
type loggingT struct {
// 是否打印到终端
toStderr bool
// 日志的输出级别
outputLevel level
// mu protects the remaining elements of this structure and is
// used to synchronize logging.
mu sync.Mutex
// 日志文件名称 用于打开文件和轮转日志
filename string
// 写日志的对象
//文件对象
w *os.File
// 保留的日志个数 main.log.1
backCount int
// 单文件大小
maxBytes int64
}
func (self *loggingT) rotatingFile() {
self.w.Close()
self.w = nil
for i := self.backCount; i >= 0; i-- {
backFilename := self.filename + "." + strconv.Itoa(i)
backFilename_obj := self.filename + "." + strconv.Itoa(i+1)
if i > 0 && !Exist(backFilename) { continue }
if i == self.backCount {
os.Remove(backFilename)
} else if i == 0 {
os.Rename(self.filename, backFilename_obj)
} else {
os.Rename(backFilename, backFilename_obj)
}
}
f, err := os.OpenFile(self.filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
println(err)
return
}
self.w = f
}
func (self *loggingT) printf(l level, format string, v ...interface{}) {
if self.outputLevel > l { return }
msg := fmt.Sprintf(format, v...)
self.mu.Lock()
defer self.mu.Unlock()
if self.toStderr == false {
info, err := self.w.Stat();
if err == nil && info.Size() >= self.maxBytes {
self.rotatingFile()
}
}
_, file, line, ok := runtime.Caller(2)
if !ok {
file = "???"
line = 1
} else {
slash := strings.LastIndex(file, "/")
if slash >= 0 {
file = file[slash+1:]
}
}
fmt.Fprintf(self.w, "%s %s - %s [%s:%d]\n", time.Now().Format("2006-01-02 15:04:05"), levelName[l], msg, file, line)
}
####logger_test.go
package logger
import (
"testing"
)
func TestNormal(t *testing.T) {
SetLevel(DetailLog)
Detail("%d", DetailLog)
Debug("%d", DebugLog)
Info("%d", InfoLog)
Error("%d", ErrorLog)
Panic("%d", PanicLog)
}