需求

一个通用的日志包,应该满意以下几单要求:

兼容 log.Logger,标准库大量使用了 log.Logger 作为该荒谬内容之出口通道,比如 net/http.Server.ErrorLog,所以兼容 log.Logger 是生死攸关之急需;

打定义配置,不同之周转条件,往往得不同的日志输出配置,在非另行编译源码的情况下,就会转配置为理应成为平等码标配;

不同的输出类型,按照当前市面上绝大多数底日志库,大家拿日志分为以下六种植类型:INFOWARNDEBUGTRACEERROR 和 CRITICAL

本着日记内容的自定义处理,比如用日志按日段展开切割,或是重要内容作邮箱举办提示等。

接口设计

因上述要求,大家约上可规定下来接口的始末。

一个从部署文件举行起头化的接口:

func InitFromConfig(path string) error

暨各种输出类型的操作函数,最重点的哪怕是获取 *log.Logger 的接口,以及有常用之简化调用。以
INFO
类型为条例,大家可定义以下八只函数,另外体系为还无异,只是函数名不同。

func INFO() *log.Logger  // 返回与 INFO 类型对应的 *log.Logger 实例

// 针对 INFO 类型日志的一些常用操作进行封装
func Info(v ...interface{})                // 相当于 INFO().Println()
func Infof(format string, v...interface{}) // 相当于 INFO().Printf()

大家还需了解一个挂号接口,用于注册用户从定义的元素:

type Init func(args map[string]string)(io.Writer, error)

func Register(name string, fn Init)

配置文件

据悉上述之急需,我们得拟定一个以下格式的 XML 配置文件:

<?xml version="1.0" encoding="utf-8"?>
<logs>
    <info prefix="INFO" flag="log.lstdflag" >
        <!-- 向控制台输出信息 -->
        <console output="stderr" foreground="red" background="blue" />
    </info>

    <error prefix="ERROR" flag="log.lstdflag" />
        <!-- 向控制台输出信息 -->
        <console output="stderr" foreground="red" background="blue" />

        <!-- 输出到 /var/logs/debug 目录下,如果大于 5M,则新建文件 -->
        <rotate dir="/var/logs/debug/" size="5M" />
    </error>

    <critical prefix="CRITICAL" flag="log.lstdflag" >
        <!-- 向指定的邮箱发送错误信息 -->
        <smtp username="u"
        password="p"
        host="smtp.example.com"
        subject="CRITICAL"
        sendTo="u1@example.com;u2@example.com" />
    </critical>
</logs>

一品元素固定啊 logs

二级元素也 INFO 和 WARN 等六栽永恒的路,在加载时,将这么些开头为一个 *log.Logger 实例,初叶化参数可以一贯从
XML 的属性与子元素中得;

二级以下的元素,统一开端化为 io.Writer 实例,当作 log.New() 的参数,用于初阶化其父元素。用户可透过接口自定义这么些要素,若爆发开头化参数,则于那多少个XML 属性值中拿到。

如此这般即使达了一个自由度相对较大之安排文件。

实现

完的兑现代码在:https://github.com/issue9/logs

初稿地址:https://caixw.io/posts/2017/how-to-design-log-package-with-go.html

使用

假使在 main() 中正确定加载了部署文件,之后随处都好调用:

// main.go
func main() {
    err := logs.InitFromConfig("./config/logs.xml")
    if err !=nil {
        panic(err)
    }

    // do something
}

// file1.go
func h1(w http.ResponseWriter, r *http.Request) {
    if !auth() {
        logs.Infof("鉴权失败")
        w.WriteHeader(http.StatusUnauthorized)
        return
    }
}

// file2.go
func getServer(port string, h http.Handler) *http.Server {
    return &http.Server {
        Addr: port,
        Handler: h,
        ErrorLog: logs.INFO(),
    }
}

相关文章

网站地图xml地图