log

package
v0.0.0-...-fda1b34 Latest Latest
Warning

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

Go to latest
Published: Nov 24, 2022 License: Apache-2.0 Imports: 15 Imported by: 0

README

日志记录器

概述

以太坊官方提供了6种级别的日志记录模式,分别是:

  • Trace
  • Debug
  • Info
  • Warn
  • Error
  • Crit

以上六个级别的日志等级从上到下逐渐递增。

此外,还支持将日志信息重定向到三种输出通道:

  • 控制台
  • 文件
  • 网络连接

最后,支持三种日志输出格式:

  • 控制台格式
  • JSON格式
  • 普通日志格式

使用方法

控制台格式输出日志

如果我们是在包外使用本包中定义的日志记录器,首先需要导入本包,然后按照下面的代码实例化一个日志记录器:

l := log.New("blockchain", "ethereum")
l.SetHandler(StreamHandler(os.Stdout, TerminalFormat(true)))

上面代码里的"blockchain""ethereum"作为是一对键值对,以后每次使用logger输出日志时,都会打印这对键值对,然后第二行代码是用来设置输出 日志的处理器,这里我们设置将日志信息输出到操作系统的标准输出里,并且以控制台显示的格式输出,然后对于不同日志等级还会显式不同的颜色:

l.Info("start service")

输出:

INFO [01-01|00:00:00.000] start service blockchain=ethereum

ERROR[01-01|00:00:00.000] start service blockchain=ethereum

JSON格式输出日志

实例化一个以JSON格式输出日志信息的日志记录器:

l := New("blockchain", "ethereum")
l.SetHandler(StreamHandler(os.Stdout, JSONFormat()))
l.Info("start service")
l.Error("start service")

输出

{"blockchain":"ethereum","lvl":"info","msg":"start service","t":"0001-01-01T00:00:00Z"}

{"blockchain":"ethereum","lvl":"eror","msg":"start service","t":"0001-01-01T00:00:00Z"}

普通日志格式

LogfmtFormat()函数定义了将日志信息按照普通日志格式打印的逻辑:

l := New("blockchain", "ethereum")
l.SetHandler(StreamHandler(os.Stdout, LogfmtFormat()))
l.Trace("trace logger")

输出:

t=0001-01-01T00:00:00Z lvl=trce msg="trace logger" blockchain=ethereum

将日志信息打印到文件里
l := New("blockchain", "ethereum")
file, _ := os.OpenFile("text.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0664)
l.SetHandler(StreamHandler(file, TerminalFormat(false)))
l.Info("start service")
l.Error("start service")

结果:

image-20221124143154963

将日志打印到网络连接通道里

这里我们利用net包建立了一对连接,然后在服务端把日志信息发送给客户端,客户端接收到以后再打印到控制台上:

l := New("blockchain", "ethereum")
stopc := make(chan struct{})
server, err := net.Listen("tcp", "0.0.0.0:8080")
assert.Nil(t, err)
go func() {
	for {
		conn, err := server.Accept()
		assert.Nil(t, err)
		l.SetHandler(StreamHandler(conn, TerminalFormat(true)))
		l.Trace("welcome")
	}
}()

go func() {
	conn, err := net.Dial("tcp", "127.0.0.1:8080")
	assert.Nil(t, err)
	for {
		buf := make([]byte, 1024)
		n, err := conn.Read(buf)
		assert.Nil(t, err)
		fmt.Println(string(buf[:n]))
		stopc <- struct{}{}
	}
}()
<-stopc

输出:

client: TRACE[01-01|00:00:00.000] welcome blockchain=ethereum

设置打印日志的级别

在下面的例子里,我们要求最多只打印Warn这一级别的日志,也就是说,Trace Debug Info这三个级别的日志不会被打印

l := New("blockchain", "ethereum")
l.SetHandler(LvlFilterHandler(LvlWarn, StreamHandler(os.Stdout, TerminalFormat(true))))
l.Info("info logger")
l.Warn("warn logger")
l.Error("error logger")

输出:

WARN [01-01|00:00:00.000] warn logger blockchain=ethereum

ERROR[01-01|00:00:00.000] error logger blockchain=ethereum

调试代码时输出日志

调试代码时输出的日志信息要想包含"file:line"这样的位置信息,打印日志的格式需要设置成控制台格式才能有效:

PrintOrigins(true)
l := New("blockchain", "ethereum")
l.SetHandler(StreamHandler(os.Stdout, TerminalFormat(true)))
l.Trace("trace logger")

PrintOrigins(true)函数里的true参数会把输出位置信息的开关打开。

输出:

TRACE[01-01|00:00:00.000|/log/log_test.go:24] trace logger blockchain=ethereum

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	StdoutHandler = StreamHandler(os.Stdout, LogfmtFormat())
)

Functions

func Crit

func Crit(msg string, ctx ...interface{})

func Debug

func Debug(msg string, ctx ...interface{})

func Error

func Error(msg string, ctx ...interface{})

func FormatLogfmtInt64

func FormatLogfmtInt64(n int64) string

FormatLogfmtInt64 ♏ |作者:吴翔宇| 🍁 |日期:2022/11/22|

FormatLogfmtInt64 方法接受一个整数作为输入参数,注意该方法与 FormatLogfmtUint64 方法不同的地方在于, 那个方法仅限于接受正整数作为输入参数,而该方法可以接受正数,也可以接受负数,然后对给定的整数进行格式化输出, 例如:

  1. 如果给定的整数为:1234567890,得到的输出是:1,234,567,890
  2. 如果给定的整数为:-1234567890,得到的输出是:-1,234,567,890

func FormatLogfmtUint64

func FormatLogfmtUint64(n uint64) string

FormatLogfmtUint64 ♏ |作者:吴翔宇| 🍁 |日期:2022/11/22|

FormatLogfmtUint64 方法接受一个uint64类型的正整数作为输入,然后对该整数进行格式化输出,例如:

  • 给定的正整数是:1234567890,得到的输出是:1,234,567,890

func Info

func Info(msg string, ctx ...interface{})

func PrintOrigins

func PrintOrigins(enabled bool)

PrintOrigins ♏ |作者:吴翔宇| 🍁 |日期:2022/11/22|

PrintOrigins 接受一个bool类型的数据作为输入参数,该方法是一个开关函数,如果传入的参数等于true,那 么在以后打印日志信息,会打印出输出日志信息所在的代码文件和代码行,类似于:"file:line"。

func Trace

func Trace(msg string, ctx ...interface{})

func Warn

func Warn(msg string, ctx ...interface{})

Types

type Ctx

type Ctx map[string]interface{}

Ctx ♏ |作者:吴翔宇| 🍁 |日期:2022/11/23|

Ctx 结构存储了日志信息里的键值对。

type Format

type Format interface {
	Format(r *Record) []byte
}

func FormatFunc

func FormatFunc(f func(*Record) []byte) Format

func JSONFormat

func JSONFormat() Format

JSONFormat ♏ |作者:吴翔宇| 🍁 |日期:2022/11/22|

JSONFormat 返回一个格式化句柄,该句柄将 Record 格式化为 JSON 样式的输出格式,例如:

实例化一个 Record 对象:
r := Record{
	Time: time.Now(),
	Lvl:  3,
	Msg:  "Start network",
	Ctx:  []interface{}{"app", "ethereum/server", "consensus", "POS"},
	Call: stack.Caller(2),
	KeyNames: RecordKeyNames{
		Time: timeKey,
		Msg:  msgKey,
		Lvl:  lvlKey,
		Ctx:  ctxKey,
	},
}
经过 JSONFormat 方法格式化后得到:
{"app":"ethereum/server","consensus":"POS","lvl":"info","msg":"Start network","t":"2022-11-22T16:08:06.96890076+08:00"}

func LogfmtFormat

func LogfmtFormat() Format

LogfmtFormat ♏ |作者:吴翔宇| 🍁 |日期:2022/11/22|

LogfmtFormat 方法将日志记录里的键值对按照人们易读的方式组合输出,例如:

t=2022-11-22T19:51:30+08:00 lvl=info msg="Start network" app=ethereum/server consensus=POS

func TerminalFormat

func TerminalFormat(useColor bool) Format

TerminalFormat ♏ |作者:吴翔宇| 🍁 |日期:2022/11/22|

TerminalFormat

type Handler

type Handler interface {
	Log(r *Record) error
}

Handler ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

Handler 接收日志记录器产生的日志条目,然后 Handler 定义了怎样将日志条目输出出去。

func DiscardHandler

func DiscardHandler() Handler

DiscardHandler ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

DiscardHandler 方法用于禁用日志功能。

func FileHandler

func FileHandler(path string, fmtr Format) (Handler, error)

FileHandler ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

FileHandler 方法接受两个参数,第一个参数是日志文件的路径,第二个参数是记载日志的格式,如果给定的日志文件 存在,就在该文件后面追加日志条目,否则就创建一个日志文件。

func FilterHandler

func FilterHandler(fn func(r *Record) bool, h Handler) Handler

FilterHandler ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

FilterHandler 接受两个参数作为入参,分别是函数fn func(r *Record) bool和 Handler,如果fn的返回值等于 true,则调用 Handler 的Log方法将日志内容输出出去,否则什么也不干,忽略这条日志信息。例如,我们只输出日志中 存在"err"键,并且其对应的值不等于"nil"的日志:

logger.SetHandler(FilterHandler(func(r *Record) bool {
    for i := 0; i < len(r.Ctx); i += 2 {
        if r.Ctx[i] == "err" {
            return r.Ctx[i+1] != nil
        }
    }
    return false
}, h))

func FuncHandler

func FuncHandler(fn func(r *Record) error) Handler

FuncHandler ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

FuncHandler 根据给定的函数返回对应的 Handler。

func LazyHandler

func LazyHandler(h Handler) Handler

LazyHandler ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

LazyHandler 方法接受一个 Handler 作为输入参数,LazyHandler 其实就是再将给定的 Handler 进行包装, LazyHandler 内部调用 FuncHandler 函数,并将其返回值返回,FuncHandler 接受的参数是一个函数的定义, 这个函数的定义是由 LazyHandler 函数设计的,将来我们调用 LazyHandler 函数返回的 Handler 的Log方法 时,实际上就是调用 LazyHandler -> FuncHandler -> 入参函数定义,在这个函数的定义内,会将日志记录 Record 里的 Ctx 过滤一遍,目的就是找到 Ctx 的value里面是否存在 Lazy 的实例,如果有的话,就执行这个 Lazy 实 例里的Fn函数,并将Fn函数的返回值替代Ctx中对应位置处的value。

func LvlFilterHandler

func LvlFilterHandler(maxLvl Lvl, h Handler) Handler

LvlFilterHandler ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

LvlFilterHandler 方法接受两个参数,分别是日志等级和 Handler,第一个参数设置了日志等级阈值,只有日志级别 小于第一个参数的日志才能被输出,众所周知,critical日志级别最高,trace日志级别最低。

func NetHandler

func NetHandler(network, addr string, fmtr Format) (Handler, error)

NetHandler ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

NetHandler 接受三个参数,前两个参数分别是网络类型和网络地址,例如:"tcp"和"67.28.31.12",第二个参数是 日志记载格式,该方法会主动拨通给定的网络地址,然后建立一个网络连接conn,并通过conn将日志内容发送给另一端的 网络设备,在那台网络设备上显式日志记录。

func StreamHandler

func StreamHandler(wr io.Writer, fmtr Format) Handler

StreamHandler ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

StreamHandler 接受两个参数:io.Writer 和 Format,其中第一个参数用来接受日志信息,第二个参数决定将以 什么样的格式把日志记录写入到 io.Writer 里。

func SyncHandler

func SyncHandler(h Handler) Handler

SyncHandler ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

SyncHandler 接收一个 Handler 作为输入参数,将给定的 Handler 包装成一个多线程安全的 Handler。

type Lazy

type Lazy struct {
	Fn interface{}
}

type Logger

type Logger interface {
	// New 生成一个新的日志记录器,给定的ctx是若干对键值对,这若干对键值对会在以后每次输出日志记录时被输出出去
	New(ctx ...interface{}) Logger

	GetHandler() Handler

	SetHandler(h Handler)

	// Trace ctx是若干对键值对
	Trace(msg string, ctx ...interface{})
	Debug(msg string, ctx ...interface{})
	Info(msg string, ctx ...interface{})
	Warn(msg string, ctx ...interface{})
	Error(msg string, ctx ...interface{})
	Crit(msg string, ctx ...interface{})
}

Logger ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

Logger

func New

func New(ctx ...interface{}) Logger

New ♏ |作者:吴翔宇| 🍁 |日期:2022/11/24|

New 方法接受若干对键值对作为新日志记录器的背景信息,每调用一次该方法,都会重新分配ctx,不会继承 之前的ctx,该方法返回一个全新的日志记录器。

func Root

func Root() Logger

type Lvl

type Lvl int
const (
	LvlCrit Lvl = iota
	LvlError
	LvlWarn
	LvlInfo
	LvlDebug
	LvlTrace
)

func LvlFromString

func LvlFromString(lvlString string) (Lvl, error)

LvlFromString ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

LvlFromString 方法接受一个字符串形式的日志等级作为输入,然后返回 Lvl 类型的值,如下所示:

"trace", "trce": LvlTrace
"debug", "dbug": LvlDebug
"info": LvlInfo
"warn": LvlWarn
"error", "eror": LvlError
"crit": LvlCrit

func (Lvl) AlignedString

func (l Lvl) AlignedString() string

AlignedString ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

AlignedString 方法返回日志级别的字符串名,返回的字符串名都是由5个字符组成,分别如下所示:

LvlTrace: "TRACE"
LvlDebug: "DEBUG"
LvlInfo:  "INFO "
LvlWarn:  "WARN "
LvlError: "ERROR"
LvlCrit:  "CRIT "

func (Lvl) String

func (l Lvl) String() string

String ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

String 方法返回日志级别的字符串名,不同于 AlignedString 方法,它返回的字符串仅有4个字符长度, 且是小写形式的,分别如下所示:

LvlTrace: "trce"
LvlDebug: "dbug"
LvlInfo:  "info "
LvlWarn:  "warn "
LvlError: "eror"
LvlCrit:  "crit "

type Record

type Record struct {
	Time     time.Time
	Lvl      Lvl
	Msg      string
	Ctx      []interface{}
	Call     stack.Call
	KeyNames RecordKeyNames
}

Record ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

Record

type RecordKeyNames

type RecordKeyNames struct {
	Time string
	Msg  string
	Lvl  string
	Ctx  string
}

RecordKeyNames ♏ |作者:吴翔宇| 🍁 |日期:2022/11/21|

RecordKeyNames

type TerminalStringer

type TerminalStringer interface {
	TerminalString() string
}

Jump to

Keyboard shortcuts

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