日誌庫基本上寫完了,可是就完成了,尚未。目前來講,咱們的文件寫日誌的方式採用同步方式,若是在大量日誌寫入的時候,同步寫入的缺陷就暴露出來了。並且日誌跟咱們的業務邏輯也沒有什麼太大的關係,哪怕掉了幾條也沒什麼影響,因此這裏能夠將同步寫改成異步寫。異步
這裏採用go的channel進行異步寫日誌。ui
首先,咱們定義一個channel的結構體用來傳遞日誌數據,在util.go
中新建一個結構體:spa
type LogData struct {
Message string
TimeStr string
LevelStr string
FileName string
FuncName string
LineNo int
IsWarn bool //是否寫入錯誤日誌文件
}
複製代碼
有些這個數據後,咱們就能夠定義一個channel來進行操做。在file.go
中增長一個channel:線程
type FileLog struct {
logPath string
logName string
file *os.File
warnFile *os.File
logDataChan chan *LogData
}
func NewFileLog(config map[string]string) (logFile Log, err error) {
...
logChanSize, ok := config["log_chan_size"]
if !ok {
logChanSize = "50000"
}
chanSize, e := strconv.Atoi(logChanSize) // string to int
if e != nil {
chanSize = 50000 // channel最大容量
}
logFile = &FileLog{
logPath: logPath,
logName: logName,
logDataChan: make(chan *LogData, chanSize),// 初始化channel
}
logFile.Init()
return
}
func (f *FileLog) Init() {
...
go f.writeLogBackGround() // go 關鍵字啓動一個線程
}
func (f *FileLog) writeLogBackGround() {
for logData := range f.logDataChan {
var file = f.file
// 切換日誌文件
if logData.IsWarn {
file = f.warnFile
}
fmt.Fprintf(file, "%s %s [%s/%s:%d] %s\n", logData.TimeStr, logData.LevelStr,
logData.FileName, logData.FuncName, logData.LineNo, logData.Message)
}
}
func (f *FileLog) Debug(format string, args ...interface{}) {
logData := writeLog(DebugLevel, format, args)
select {
case f.logDataChan <- logData: // 將logData放入f.logDataChan中
default:
}
}
...
func (f *FileLog) Info(format string, args ...interface{}) {
logData := writeLog(InfoLevel, format, args)
select {
case f.logDataChan <- logData:
default:
}
}
...
複製代碼
將以前的writeLog改進一下.日誌
func writeLog(level int, format string, args ...interface{}) *LogData {
now := time.Now()
nowStr := now.Format("2006-01-02 15:04:05.999")
levelStr := LogLevelString(level)
fileName, funcName, lineNo := GetLineInfo()
fileName = path.Base(fileName)
funcName = path.Base(funcName)
msg := fmt.Sprintf(format, args...)
isWarn := level >= WarnLevel && level <= FatalLevel
return &LogData{
Message: msg,
TimeStr: nowStr,
LevelStr: levelStr,
FileName: fileName,
FuncName: funcName,
LineNo: lineNo,
IsWarn: isWarn,
}
}
複製代碼
這樣就把同步改成了異步,咱們日誌庫又健壯了一些。 因爲writeLog有改動,因此還須要修改一下console.go
的內容。code
func (c *ConsoleLog) Debug(format string, args ...interface{}) {
logData := MsgInfo(DebugLevel, format, args)
fmt.Fprintf(os.Stdout, "%s %s [%s/%s:%d] %s\n", logData.TimeStr, logData.LevelStr, logData.FileName, logData.FuncName, logData.LineNo, logData.Message)
}
...
func (c *ConsoleLog) Error(format string, args ...interface{}) {
logData := MsgInfo(ErrorLevel, format, args)
fmt.Fprintf(os.Stdout, "%s %s [%s/%s:%d] %s\n", logData.TimeStr, logData.LevelStr, logData.FileName, logData.FuncName, logData.LineNo, logData.Message)
}
...
複製代碼
雖然咱們修改了那麼多,可是在使用日誌庫的時候沒有什麼不一樣,只是咱們的日誌庫更完善了一下。orm
func initLog(logPath, logName string) {
//log := hm_log.NewFileLog(logPath, logName)
config := make(map[string]string, 8)
config["log_path"] = "."
config["log_name"] = "server"
config["log_chan_size"] = "50000" //chan size 能夠不用
err := InitLog("file", config)
if err != nil {
return
}
}
複製代碼
OK,咱們再來運行一下,日誌正常寫入,終端也正常打印。server