文档章节

保存一个别人的golang 日志库

敲代码中
 敲代码中
发布于 2014/06/17 11:22
字数 863
阅读 156
收藏 0

package logger


import (

"fmt"

"log"

"os"

"runtime"

"strconv"

"sync"

"time"

)


const (

_VER string = "1.0.0"

)


type LEVEL int32


var logLevel LEVEL = 1

var maxFileSize int64

var maxFileCount int32

var dailyRolling bool = true

var consoleAppender bool = true

var RollingFile bool = false

var logObj *_FILE


const DATEFORMAT = "2006-01-02"


type UNIT int64


const (

_       = iota

KB UNIT = 1 << (iota * 10)

MB

GB

TB

)


const (

ALL LEVEL = iota

DEBUG

INFO

WARN

ERROR

FATAL

OFF

)


type _FILE struct {

dir      string

filename string

_suffix  int

isCover  bool

_date    *time.Time

mu       *sync.RWMutex

logfile  *os.File

lg       *log.Logger

}


func SetConsole(isConsole bool) {

consoleAppender = isConsole

}


func SetLevel(_level LEVEL) {

logLevel = _level

}


func SetRollingFile(fileDir, fileName string, maxNumber int32, maxSize int64, _unit UNIT) {

maxFileCount = maxNumber

maxFileSize = maxSize * int64(_unit)

RollingFile = true

dailyRolling = false

logObj = &_FILE{dir: fileDir, filename: fileName, isCover: false, mu: new(sync.RWMutex)}

logObj.mu.Lock()

defer logObj.mu.Unlock()

for i := 1; i <= int(maxNumber); i++ {

if isExist(fileDir + "/" + fileName + "." + strconv.Itoa(i)) {

logObj._suffix = i

} else {

break

}

}

if !logObj.isMustRename() {

logObj.logfile, _ = os.OpenFile(fileDir+"/"+fileName, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0)

logObj.lg = log.New(logObj.logfile, "\n", log.Ldate|log.Ltime|log.Lshortfile)

} else {

logObj.rename()

}

go fileMonitor()

}


func SetRollingDaily(fileDir, fileName string) {

RollingFile = false

dailyRolling = true

t, _ := time.Parse(DATEFORMAT, time.Now().Format(DATEFORMAT))

logObj = &_FILE{dir: fileDir, filename: fileName, _date: &t, isCover: false, mu: new(sync.RWMutex)}

logObj.mu.Lock()

defer logObj.mu.Unlock()


if !logObj.isMustRename() {

logObj.logfile, _ = os.OpenFile(fileDir+"/"+fileName, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0)

logObj.lg = log.New(logObj.logfile, "\n", log.Ldate|log.Ltime|log.Lshortfile)

} else {

logObj.rename()

}

}


func console(s ...interface{}) {

if consoleAppender {

_, file, line, _ := runtime.Caller(2)

short := file

for i := len(file) - 1; i > 0; i-- {

if file[i] == '/' {

short = file[i+1:]

break

}

}

file = short

log.Println(file+":"+strconv.Itoa(line), s)

}

}


func catchError() {

if err := recover(); err != nil {

log.Println("err", err)

}

}


func Debug(v ...interface{}) {

if dailyRolling {

fileCheck()

}

defer catchError()

logObj.mu.RLock()

defer logObj.mu.RUnlock()


if logLevel <= DEBUG {

logObj.lg.Output(2, fmt.Sprintln("debug", v))

console("debug", v)

}

}

func Info(v ...interface{}) {

if dailyRolling {

fileCheck()

}

defer catchError()

logObj.mu.RLock()

defer logObj.mu.RUnlock()

if logLevel <= INFO {

logObj.lg.Output(2, fmt.Sprintln("info", v))

console("info", v)

}

}

func Warn(v ...interface{}) {

if dailyRolling {

fileCheck()

}

defer catchError()

logObj.mu.RLock()

defer logObj.mu.RUnlock()

if logLevel <= WARN {

logObj.lg.Output(2, fmt.Sprintln("warn", v))

console("warn", v)

}

}

func Error(v ...interface{}) {

if dailyRolling {

fileCheck()

}

defer catchError()

logObj.mu.RLock()

defer logObj.mu.RUnlock()

if logLevel <= ERROR {

logObj.lg.Output(2, fmt.Sprintln("error", v))

console("error", v)

}

}

func Fatal(v ...interface{}) {

if dailyRolling {

fileCheck()

}

defer catchError()

logObj.mu.RLock()

defer logObj.mu.RUnlock()

if logLevel <= FATAL {

logObj.lg.Output(2, fmt.Sprintln("fatal", v))

console("fatal", v)

}

}


func (f *_FILE) isMustRename() bool {

if dailyRolling {

t, _ := time.Parse(DATEFORMAT, time.Now().Format(DATEFORMAT))

if t.After(*f._date) {

return true

}

} else {

if maxFileCount > 1 {

if fileSize(f.dir+"/"+f.filename) >= maxFileSize {

return true

}

}

}

return false

}


func (f *_FILE) rename() {

if dailyRolling {

fn := f.dir + "/" + f.filename + "." + f._date.Format(DATEFORMAT)

if !isExist(fn) && f.isMustRename() {

if f.logfile != nil {

f.logfile.Close()

}

err := os.Rename(f.dir+"/"+f.filename, fn)

if err != nil {

f.lg.Println("rename err", err.Error())

}

t, _ := time.Parse(DATEFORMAT, time.Now().Format(DATEFORMAT))

f._date = &t

f.logfile, _ = os.Create(f.dir + "/" + f.filename)

f.lg = log.New(logObj.logfile, "\n", log.Ldate|log.Ltime|log.Lshortfile)

}

} else {

f.coverNextOne()

}

}


func (f *_FILE) nextSuffix() int {

return int(f._suffix%int(maxFileCount) + 1)

}


func (f *_FILE) coverNextOne() {

f._suffix = f.nextSuffix()

if f.logfile != nil {

f.logfile.Close()

}

if isExist(f.dir + "/" + f.filename + "." + strconv.Itoa(int(f._suffix))) {

os.Remove(f.dir + "/" + f.filename + "." + strconv.Itoa(int(f._suffix)))

}

os.Rename(f.dir+"/"+f.filename, f.dir+"/"+f.filename+"."+strconv.Itoa(int(f._suffix)))

f.logfile, _ = os.Create(f.dir + "/" + f.filename)

f.lg = log.New(logObj.logfile, "\n", log.Ldate|log.Ltime|log.Lshortfile)

}


func fileSize(file string) int64 {

fmt.Println("fileSize", file)

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 fileMonitor() {

timer := time.NewTicker(1 * time.Second)

for {

select {

case <-timer.C:

fileCheck()

}

}

}


func fileCheck() {

defer func() {

if err := recover(); err != nil {

log.Println(err)

}

}()

if logObj != nil && logObj.isMustRename() {

logObj.mu.Lock()

defer logObj.mu.Unlock()

logObj.rename()

}

}


使用方法

package example

import (
"github.com/donnie4w/go-logger/logger"
"runtime"
"strconv"
"testing"
"time"
)

func log(i int) {
logger.Debug("Debug>>>>>>>>>>>>>>>>>>>>>>" + strconv.Itoa(i))
logger.Info("Info>>>>>>>>>>>>>>>>>>>>>>>>>" + strconv.Itoa(i))
logger.Warn("Warn>>>>>>>>>>>>>>>>>>>>>>>>>" + strconv.Itoa(i))
logger.Error("Error>>>>>>>>>>>>>>>>>>>>>>>>>" + strconv.Itoa(i))
logger.Fatal("Fatal>>>>>>>>>>>>>>>>>>>>>>>>>" + strconv.Itoa(i))
}

func Test(t *testing.T) {
runtime.GOMAXPROCS(runtime.NumCPU())

//指定是否控制台打印,默认为true
logger.SetConsole(true)
//指定日志文件备份方式为文件大小的方式
//第一个参数为日志文件存放目录
//第二个参数为日志文件命名
//第三个参数为备份文件最大数量
//第四个参数为备份文件大小
//第五个参数为文件大小的单位
//logger.SetRollingFile("d:/logtest", "test.log", 10, 5, logger.KB)

//指定日志文件备份方式为日期的方式
//第一个参数为日志文件存放目录
//第二个参数为日志文件命名
logger.SetRollingDaily("d:/logtest", "test.log")

//指定日志级别  ALL,DEBUG,INFO,WARN,ERROR,FATAL,OFF 级别由低到高
//一般习惯是测试阶段为debug,生成环境为info以上
logger.SetLevel(logger.ERROR)

for i := 10000; i > 0; i-- {
go log(i)
time.Sleep(1000 * time.Millisecond)
}
time.Sleep(15 * time.Second)
}



本文转载自:https://github.com/donnie4w/go-logger

共有 人打赏支持
敲代码中
粉丝 1
博文 16
码字总数 5522
作品 0
厦门
学习golang并做一个简单分布式存储项目

从14年中开始陆续一年,断断续续学习了下Golang,看了Go语言编程,Go语言程序设计2本书。 始终觉得应该做点项目锻炼下,因为正好看《从paxos到zookeeper》,就尝试写一些网络应用,分布式存储...

丁永
2015/11/19
0
0
Golang中使用log(二):Golang 标准库log的实现

前一篇文章我们看到了Golang标准库中log模块的使用,那么它是如何实现的呢?下面我从log.Logger开始逐步分析其实现。 其源码可以参考官方地址 1.Logger结构 首先来看下类型Logger的定义: ty...

gotaly
06/28
0
0
Golang中使用log(一):Golang 标准库提供的Log

Golang的标准库提供了log的机制,但是该模块的功能较为简单(看似简单,其实他有他的设计思路)。不过比手写fmt. Printxxx还是强很多的。至少在输出的位置做了线程安全的保护。其官方手册见G...

gotaly
06/28
0
0
简单扩展性好的日志库 - Go Logger

go-logger 一个简单而强大的 golang 日志工具包 English document 功能 支持同时输出到 console, file, url 命令行输出字体可带颜色 文件输出支持根据 文件大小,文件行数,日期三种方式切分...

phachon
2017/10/12
0
1
Golang依赖关联工具:glide从入门到精通使用

介绍 不论是开发Java还是你正在学习的Golang,都会遇到依赖管理问题。Java有牛逼轰轰的Maven和Gradle。 Golang亦有godep、govendor、glide、gvt、gopack等等,本文主要给大家介绍gilde。 gl...

梦朝思夕
2017/07/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

laravel 微信支付

1.composer加载laravel微信支付第三方文件 composer require "overtrue/laravel-wechat:~4.0" composer require simplesoftwareio/simple-qrcode 1.3.* //composer生成二维码文件 2.改confi......

vio小黑
30分钟前
1
0
学习设计模式——抽象工厂模式

1. 认识抽象工厂模式 1. 定义:提供一个创建一系列相关或互相依赖的对象的接口,而无需指定它们具体的类。 2. 组成结构: AbstractFactory:抽象工厂类,定义创建一系列对象的操作接口 Fact...

江左煤郎
30分钟前
2
0
ES6的let块级作用域和变量不可提升导致一个比较容易出现的错误

今天在写NodeJS代码的时候出现一个变量一直提示未定义,简化后的代码如下: let param = 1;{ console.log(param);} 就在想,不至于啊。不是继承上层的声明吗? 继续看下去,发现原来...

MKjy
37分钟前
2
0
50:nginx访问日记|日记切割|静态文件不记录日记和过期时间

1、nginx访问日记: 日记格式:在主配置文件nginx.conf里搜索log_format; [root@localhost_001 conf]# vim nginx.conflog_format combined_realip '$remote_addr $http_x_forwarded_for ......

芬野de博客
40分钟前
1
0
前后端正常交互的流程

1、评审阶段:产品召集前后端进行需求评审,前后端各自捋清楚自己的业务量以及联调之间工作量,从而进行开发时间评估。 2、开发准备阶段:前后端一起商量需求中需要联调的部分,进行接口的口...

Jack088
40分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部