log

package module
v0.0.0-...-f7c8bd4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2018 License: MIT Imports: 12 Imported by: 9

README

Build Status

log

Golang 标准库中提供了基本的 log 模块 http://golang.org/pkg/log ,能 print/fatal/panic 日志,但唯独不能像 Java log4j 一样设置日志输出级别, debug 日志开发时输出,生产上关闭。这不能 不说是个巨大的遗憾, gopher 们只能抱怨 Golang 标准库的 log 就是个然并卵,实际项目大多不会使用 它。尽管 print 可以当成 error 使用(标准库确实把日志打印到错误输出流 os.Stdout),但是开发时 debug/info 就没办法。

或许对标准库的设计 Golang 开发团队有自己的考虑,但是对应用开发者来说,log4j 已经成为事实上的标 准。为了向这个标准库靠近,出现了众多第三方 log 库,有在标准库基础上扩展的(也许 Golang 设计者 们也是想让开发者自己扩展标准库的 log 呢),也就另辟蹊径,也有玩各种花样的。

虽然有那么多的 log 库,但都是大同小异,我们需要的也只是个标准的可以自定义级别的 log 库而已,就 像 slf4j(Simple Logging Facade for Java) 一样,所以这个 log 库的需要完成得任务就是提供一 个标准统一的接口,同时也提供了一个基本的实现,可以自己定义模板格式,输出各种类型的日志,如 csv/json/xml,同时支持 TraceID。

使用这个 log 库打印日志,可以随时切换日志级别,可以更换不同的 logger 实现,以打印不同格式的日 志,也可以改变日志输出位置,输出到数据库、消息队列等,者所有的改变都无需修改已经写好的项目源码。

Usage

安装:go get -v -u github.com/gotips/log

使用:

package main

import "github.com/gotips/log"

func main() {
    log.Debugf("this is a test message, %d", 1111)

	format := fmt.Sprintf("%s %s %s %s:%d %s", "2006-01-02 15:04:05.000000", log.TagToken,
		log.LevelToken, log.ProjectToken, log.LineToken, log.MessageToken)
	log.ChangeFormat(format)
	log.Tinfof("6ba7b814-9dad-11d1-80b4-00c04fd430c8", "this is a test message, %d", 1111)

	format = fmt.Sprintf(`{"date": "%s", "time": "%s", "level": "%s", "file": "%s", "line": %d, "log": "%s"}`,
		"2006-01-02", "15:04:05.999", log.LevelToken, log.ProjectToken, log.LineToken, log.MessageToken)
	log.ChangeFormat(format)
	log.Infof("this is a test message, %d", 1111)

	format = fmt.Sprintf(`<log><date>%s</date><time>%s</time><level>%s</level><file>%s</file><line>%d</line><msg>%s</msg><log>`,
		"2006-01-02", "15:04:05.000", log.LevelToken, log.ProjectToken, log.LineToken, log.MessageToken)
	log.ChangeFormat(format)
	log.Tinfof("6ba7b814-9dad-11d1-80b4-00c04fd430c8", "this is a test message, %d", 1111)
}

日志输出:

2016-01-16 20:28:34 debug examples/main.go:10 this is a test message, 1111
2016-01-16 20:28:34.280601 6ba7b814-9dad-11d1-80b4-00c04fd430c8 info examples/main.go:15 this is a test message, 1111
{"date": "2016-01-16", "time": "20:28:34.28", "level": "info", "file": "examples/main.go", "line": 20, "log": "this is a test message, 1111"}
<log><date>2016-01-16</date><time>20:28:34.280</time><level>info</level><file>examples/main.go</file><line>25</line><msg>this is a test message, 1111</msg><log>

更多用法 examples

log/Printer/Standard

Golang 不同于 Java,非面向对象语言(没有继承,只有组合,不能把组合实例赋给被组合的实例,即 Java 说的 子对象 赋给 父对象),为了方便使用,很多函数都是包封装的,无需创建 struct ,就可以直接调用。

(一般把裸漏的方法称为函数,结构体和其他类型的方法才称为某某的方法)

log 包也一样,使用时,无需 new ,直接用。log 包有所有级别的函数可以调用,所有函数最终都调用了 print 函数。print 函数又调用了包内部变量的 std 的 Print 方法。这个 std 是一个 Printer 接 口类型,定义了打印接口。用不同的实现改变 std 就可以打印出不同格式的日志,也可以输出到不同位置。

Printer 有个基本的实现 Standard,如果不改变,默认使用这个实现打印日志。

Standard 实现了的 Printer 接口,以简洁的格式把日志打印到 Stdout。

TraceID 问题

对有些项目,需要在各个系统之间跟踪请求链路,往往会产生一个请求的唯一标识 traceID,以下简称 tid, 需要在日志中打印出 tid。

Golang 1.4 之前可以取到 goroutine ID(goid),但之后就取不到了,不然 log 库就可以通过上下文 直接取到 tid。目前来说,只能有两个折中的办法:

  • tid 透传,所有方法都带上 tid 参数,或者使用 google context 库,传递更多参数,推荐后者,log 日志时,也带上这个 tid 参数;

  • 如果系统按功能模块划分,而不是按层次划分,可以定义一个 struct ,比如 Foo ,把 TID 作为它的 一个属性,每个请求进入时,new 一个 struct ,传入 tid ,Foo{tid},方法体内可以使用

func (f *Foo)Bar(){
    log.Tinfof( f.TID, "get %s", "something")
}

如果也不想在打印日志时传递 tid,可以定义一个 log 实现 Logger2 ,组合到 Foo 中,Logger 就可 以取到 tid 了,new Foo 时,也要 new Logger2 ,调用 f.Infof("%s", "something")。但这 样需要实现所有的 Trace/Debug/Info/Warn/Error/Fatal[f] 方法,而且无法切换 log 实现了,除 非改 Logger2 源码,这叫封装,就不是扩展了。不推荐这种极端做法!

TODO

  • examples
  • Benchmark Test
  • 把 ChangeFormat 和 ChangeWriter 方法提出 printer 之外,放到 log.go 中
  • 测试是否支持各种格式的日期
  • 处理秒和毫秒,如1:1:02.9
  • 实现日志文件按一定规则自动滚动
  • 错误日志着色,开发阶段非常有用

Others

最近更新请移步 https://github.com/omigo/log

Documentation

Overview

Package log 实现了一个标准的可以自定义级别的 log 库,就像 slf4j(Simple Logging Facade for Java) 一样。这个 log 库的需要完成得任务就是提供一个标准统一的接口,同时也提供了一个基本的实现。 使用这个 log 库打印日志,可以随时切换日志级别,可以更换不同的 logger 实现,以打印不同格式的日 志,也可以改变日志输出位置,输出到数据库、消息队列等,者所有的改变都无需修改已经写好的项目源码。

安装:

go get -v -u github.com/gotips/log

使用:

package main

import "github.com/gotips/log"

func main() {
    log.Debugf("this is a test message, %d", 1111)

    format := fmt.Sprintf("%s %s %s %s:%d %s", "2006-01-02 15:04:05.000000", log.TagToken,
    	log.LevelToken, log.ProjectToken, log.LineToken, log.MessageToken)
    log.ChangeFormat(format)
    log.Tinfof("6ba7b814-9dad-11d1-80b4-00c04fd430c8", "this is a test message, %d", 1111)

    format = fmt.Sprintf(`{"date": "%s", "time": "%s", "level": "%s", "file": "%s", "line": %d, "log": "%s"}`,
    	"2006-01-02", "15:04:05.999", log.LevelToken, log.ProjectToken, log.LineToken, log.MessageToken)
    log.ChangeFormat(format)
    log.Infof("this is a test message, %d", 1111)

    format = fmt.Sprintf(`<log><date>%s</date><time>%s</time><level>%s</level><file>%s</file><line>%d</line><msg>%s</msg><log>`,
    	"2006-01-02", "15:04:05.000", log.LevelToken, log.ProjectToken, log.LineToken, log.MessageToken)
    log.ChangeFormat(format)
    log.Tinfof("6ba7b814-9dad-11d1-80b4-00c04fd430c8", "this is a test message, %d", 1111)
}

日志输出:

2016-01-16 20:28:34 debug examples/main.go:10 this is a test message, 1111
2016-01-16 20:28:34.280601 6ba7b814-9dad-11d1-80b4-00c04fd430c8 info examples/main.go:15 this is a test message, 1111
{"date": "2016-01-16", "time": "20:28:34.28", "level": "info", "file": "examples/main.go", "line": 20, "log": "this is a test message, 1111"}
<log><date>2016-01-16</date><time>20:28:34.280</time><level>info</level><file>examples/main.go</file><line>25</line><msg>this is a test message, 1111</msg><log>

Index

Constants

View Source
const (
	LevelToken   string = "info"
	TagToken            = "tag"
	PathToken           = "/go/src/github.com/gotips/log/examples/main.go"
	PackageToken        = "github.com/gotips/log/examples/main.go"
	ProjectToken        = "examples/main.go"
	FileToken           = "main.go"
	LineToken    int    = 88
	MessageToken string = "message"
)

可以用这些串和日期、时间(包含毫秒数)任意组合,拼成各种格式的日志,如 csv/json/xml

View Source
const (
	QUICKPAY    = "quickpay"
	PHANTOM     = "phantom"
	ANGRYCARD   = "angrycard"
	ANGRYNOTIFY = "angrynotify"
	BIGCAT      = "bigcat"
	MAGISYNC    = "magisync"
	MAGISETT    = "magisett"
	SHOPCODE    = "shopcode"
	MEDUSA      = "medusa"
	GOVERNOR    = "governor"
	PUMPKIN     = "pumpkin"
	LOGSTING    = "logsting"
	CARDCOMMON  = "cardcommon"
	FileType    = ".log"
)
View Source
const DefaultFormat = "2006-01-02 15:04:05 info examples/main.go:88 message"

DefaultFormat 默认日志格式

View Source
const DefaultFormatTag = "2006-01-02 15:04:05 tag info examples/main.go:88 message"

DefaultFormatTag 默认日志格式带标签

Variables

View Source
var Labels = [...]string{"all", "trace", "debug", "info", "warn", "error", "panic", "fatal", "print", "stack"}

Labels 每个级别对应的标签

View Source
var LogDir = "logs/"
View Source
var LogFile *os.File = nil

Functions

func ChangeFormat

func ChangeFormat(format string)

ChangeFormat 改变日志格式

func ChangeWriter

func ChangeWriter(w io.Writer)

ChangeWriter 改变输出位置,通过这个接口,可以实现日志文件按时间或按大小滚动

func Debug

func Debug(m ...interface{})

func Debugf

func Debugf(format string, m ...interface{})

func Error

func Error(m ...interface{})

func Errorf

func Errorf(format string, m ...interface{})

func Fatal

func Fatal(m ...interface{})

func Fatalf

func Fatalf(format string, m ...interface{})

func Info

func Info(m ...interface{})

func Infof

func Infof(format string, m ...interface{})

func IsDebugEnabled

func IsDebugEnabled() bool

func IsErrorEnabled

func IsErrorEnabled() bool

func IsFatalEnabled

func IsFatalEnabled() bool

func IsInfoEnabled

func IsInfoEnabled() bool

func IsMoreTwoMonth

func IsMoreTwoMonth(origDate, curDate string) bool

true:超过两个月

func IsPanicEnabled

func IsPanicEnabled() bool

func IsPrintEnabled

func IsPrintEnabled() bool

func IsStackEnabled

func IsStackEnabled() bool

func IsTraceEnabled

func IsTraceEnabled() bool

判断各种级别的日志是否会被输出

func IsWarnEnabled

func IsWarnEnabled() bool

func Panic

func Panic(m ...interface{})

func Panicf

func Panicf(format string, m ...interface{})

func PreLog

func PreLog()

由于该方法是定时任务,第一次和程序一起启动,如果失败,在控制台输出错误信息,如果后续定时任务出现处理失败,则沿用原来的log文件

func Print

func Print(m ...interface{})

func Printf

func Printf(format string, m ...interface{})

func RemoveLogFile

func RemoveLogFile()

func SetFileName

func SetFileName(fileName string)

func SetLevel

func SetLevel(l Level)

SetLevel 设置日志级别

func SetPrinter

func SetPrinter(p Printer)

SetPrinter 切换 Printer 实现

func Stack

func Stack(m ...interface{})

func Stackf

func Stackf(format string, m ...interface{})

func Tdebug

func Tdebug(tag string, m ...interface{})

func Tdebugf

func Tdebugf(tag string, format string, m ...interface{})

func Terror

func Terror(tag string, m ...interface{})

func Terrorf

func Terrorf(tag string, format string, m ...interface{})

func Tfatal

func Tfatal(tag string, m ...interface{})

func Tfatalf

func Tfatalf(tag string, format string, m ...interface{})

func Tinfo

func Tinfo(tag string, m ...interface{})

func Tinfof

func Tinfof(tag string, format string, m ...interface{})

func Tpanic

func Tpanic(tag string, m ...interface{})

func Tpanicf

func Tpanicf(tag string, format string, m ...interface{})

func Tprint

func Tprint(tag string, m ...interface{})

func Tprintf

func Tprintf(tag string, format string, m ...interface{})

func Trace

func Trace(m ...interface{})

打印日志

func Tracef

func Tracef(format string, m ...interface{})

按一定格式打印日志

func Tstack

func Tstack(tag string, m ...interface{})

func Tstackf

func Tstackf(tag string, format string, m ...interface{})

func Ttrace

func Ttrace(tag string, m ...interface{})

打印日志时带上 tag

func Ttracef

func Ttracef(tag string, format string, m ...interface{})

按一定格式打印日志,并在打印日志时带上 tag

func Twarn

func Twarn(tag string, m ...interface{})

func Twarnf

func Twarnf(tag string, format string, m ...interface{})

func Warn

func Warn(m ...interface{})

func Warnf

func Warnf(format string, m ...interface{})

Types

type Level

type Level uint8

Level 日志级别

const (
	AllLevel Level = iota // 等同于 TraceLevel

	TraceLevel
	DebugLevel // 默认日志级别,方便开发
	InfoLevel
	WarnLevel
	ErrorLevel
	PanicLevel // panic 打印错误栈,但是可以 recover
	FatalLevel // fatal 表明严重错误,程序直接退出,慎用

	// 提供这个级别日志,方便在无论何种情况下,都打印必要信息,比如服务启动信息
	PrintLevel
	StackLevel // 打印堆栈信息
)

所有日志级别常量,级别越高,日志越重要,级别越低,日志越详细

func ValueOfLevel

func ValueOfLevel(vstr string) (v Level, err error)

ValueOfLevel 字符串转换成 Level, "debug" => DebugLevel

func (*Level) MarshalJSON

func (v *Level) MarshalJSON() ([]byte, error)

MarshalJSON 便于 JSON 解析

func (Level) String

func (v Level) String() string

String 返回日志标签

func (*Level) UnmarshalJSON

func (v *Level) UnmarshalJSON(b []byte) error

UnmarshalJSON 便于 JSON 解析

type Printer

type Printer interface {

	// 所有方法最终归为这个方法,真正打印日志
	Tprintf(v, l Level, tag string, format string, m ...interface{})

	// ChangeFormat 改变日志格式
	ChangeFormat(format string)

	// ChangeWriter 改变输出流
	ChangeWriter(w io.Writer)
}

Printer 定义了打印接口

type Standard

type Standard struct {
	// contains filtered or unexported fields
}

Standard 日志输出基本实现

func NewStandard

func NewStandard(out io.Writer, format string) *Standard

NewStandard 返回标准实现

func (*Standard) ChangeFormat

func (s *Standard) ChangeFormat(format string)

ChangeFormat 改变日志格式

func (*Standard) ChangeWriter

func (s *Standard) ChangeWriter(w io.Writer)

ChangeWriter 改变输出流

func (*Standard) Tprintf

func (s *Standard) Tprintf(v, l Level, tag string, format string, m ...interface{})

Tprintf 打印日志

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL