文档章节

保存一个别人的golang 日志库

敲代码中
 敲代码中
发布于 2014/06/17 11:22
字数 863
阅读 164
收藏 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
简单扩展性好的日志库 - Go Logger

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

phachon
2017/10/12
0
1
产品环境中 Go 语言的最佳实践

在SoundCloud,我们为客户构建了产品的API。或者说,我们主要的网站、手机客户端和手机应用是该API的第一批客户。该API背后是一个领域性的服务:SoundCloud基本上以面向服务体系结构的形式运...

oschina
2014/04/27
10.8K
12
程序日志由浅入深(Go语言描述)

程序中记录日志的首要目的:Troubleshooting。通过记录程序中对外部系统与模块的依赖调用、重要状态信息的变化、关键变量、关键逻辑等,显示基于时间轴的程序运行轨迹,显示业务是否正常、是...

RiboseYim
2017/05/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

MySQL主从配置——双主

MySQL主从配置——双主 本人是测试环境,准备了两台安装好mysql的服务器(masterA和masterB),可以保证没数据写入,否则需要先将两台服务器上的数据一致,然后再进行主从配置,步骤是:先m...

弓正
2分钟前
0
0
centos下如何使用 beyond compare 对比工具

我这里的环境是centos7桌面版 三条命令安装beyond compare wget http://www.scootersoftware.com/bcompare-4.2.3.22587.x86_64.rpmrpm --import http://www.scootersoftware.com/RPM-GPG-K......

linuxprobe16
6分钟前
0
0
http协议请求头的意义

GET /day31_Http_306/index.jsp HTTP/1.1: GET请求,请求服务器路径为/hello/index.jsp,协议为1.1 请求头 1.Host:localhost:请求的主机名为localhost2.User-Agent:Mozilla/5.0(Windows NT......

潇潇程序缘
44分钟前
6
0
Netty 简单服务器 (三)

经过对Netty的基础认识,设计模型的初步了解,来写个测试,试试手感 上篇也说到官方推荐我们使用主从线程池模型,那就选择这个模型进行操作 需要操作的步骤: 需要构建两个主从线程组 写一个服务器...

_大侠__
54分钟前
9
0
day02:管道符、shell及环境变量

1、管道符:"|" 用于将前一个指令的输出作为后一个指令的输入,且管道符后面跟的是命令(针对文档的操作):cat less head tail grep cut sort wc uniq tee tr split sed awk等) [root@localho...

芬野de博客
今天
16
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部