扫码订阅《 》或入驻星球,即可阅读文章!

GOLANG ROADMAP

阅读模式

  • 沉浸
  • 自动
  • 日常
首页
Go学习
  • Go学院

    • Go小课
    • Go视界
    • Go小考
    • Go实战
  • Go资源

    • 优质课程
    • 在线宝典
    • 资源下载
    • 帮找资源
训练营 🔥
  • Go体系课&实战训练营
  • 升值加薪陪跑训练营
Go求职
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
  • 求职服务

    • 内推互助
    • 求职助力
    • 内推公司
Go友会
  • 城市
  • 校园
推广返佣
  • 返佣排行
  • 返佣规则
  • 推广学院
实验区
  • Go周边
  • Go宝典

    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
更多
  • 用户中心

    • 我的信息
    • 我的返佣
    • 我的消息
  • 玩转星球

    • 星球介绍
    • 星主权益
    • 吐槽专区
    • 成长记录
  • 合作交流

    • 商务合作
    • 讲师招募
    • 生态伙伴
author-avatar

GOLANG ROADMAP


首页
Go学习
  • Go学院

    • Go小课
    • Go视界
    • Go小考
    • Go实战
  • Go资源

    • 优质课程
    • 在线宝典
    • 资源下载
    • 帮找资源
训练营 🔥
  • Go体系课&实战训练营
  • 升值加薪陪跑训练营
Go求职
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
  • 求职服务

    • 内推互助
    • 求职助力
    • 内推公司
Go友会
  • 城市
  • 校园
推广返佣
  • 返佣排行
  • 返佣规则
  • 推广学院
实验区
  • Go周边
  • Go宝典

    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
更多
  • 用户中心

    • 我的信息
    • 我的返佣
    • 我的消息
  • 玩转星球

    • 星球介绍
    • 星主权益
    • 吐槽专区
    • 成长记录
  • 合作交流

    • 商务合作
    • 讲师招募
    • 生态伙伴
  • Go语言Web编程

    • 课程介绍
  • Web基础

  • 表单

  • 访问数据库

  • session和数据存储

  • 文本处理

  • Web服务

  • 安全与加密

  • 国际化和本地化

  • 错误处理,调试和测试

  • 部署与维护

    • 第1节:部署与维护
    • 第2节:应用日志
    • 第3节:网站错误处理
    • 第4节:应用部署
    • 第5节:备份和恢复
    • 第6节:小结
  • 如何设计一个Web框架

  • 扩展Web框架

扫码订阅《 》或入驻星球,即可阅读文章!

第2节:应用日志


ASTA谢

我们期望开发的 Web 应用程序能够把整个程序运行过程中出现的各种事件一一记录下来,Go 语言中提供了一个简易的 log 包,我们使用该包可以方便的实现日志记录的功能,这些日志都是基于 fmt 包的打印再结合 panic 之类的函数来进行一般的打印、抛出错误处理。 Go 目前标准包只是包含了简单的功能,如果我们想把我们的应用日志保存到文件,然后又能够结合日志实现很多复杂的功能(编写过Java 或者 C++ 的读者应该都使用过 log4j 和 log4cpp 之类的日志工具),可以使用第三方开发的日志系统: logrus (opens new window) 和 seelog (opens new window),它们实现了很强大的日志功能,可以结合自己项目选择。接下来我们介绍如何通过该日志系统来实现我们应用的日志功能。

# logrus 介绍

logrus 是用 Go 语言实现的一个日志系统,与标准库 log 完全兼容并且核心 API 很稳定, 是 Go 语言目前最活跃的日志库

首先安装 logrus

go get -u github.com/sirupsen/logrus
1

简单例子:

package main

import (
	log "github.com/Sirupsen/logrus"
)

func main() {
log.WithFields(log.Fields{
	"animal": "walrus",
}).Info("A walrus appears")
}
1
2
3
4
5
6
7
8
9
10
11

# 基于 logrus 的自定义日志处理

package main

import (
	"os"

	log "github.com/Sirupsen/logrus"
)

func init() {
	// 日志格式化为 JSON 而不是默认的 ASCII
	log.SetFormatter(&log.JSONFormatter{})

	// 输出 stdout 而不是默认的 stderr,也可以是一个文件
	log.SetOutput(os.Stdout)

	// 只记录严重或以上警告
	log.SetLevel(log.WarnLevel)
}

func main() {
	log.WithFields(log.Fields{
		"animal": "walrus",
		"size":   10,
	}).Info("A group of walrus emerges from the ocean")

	log.WithFields(log.Fields{
		"omg":    true,
		"number": 122,
	}).Warn("The group's number increased tremendously!")

	log.WithFields(log.Fields{
		"omg":    true,
		"number": 100,
	}).Fatal("The ice breaks!")

	// 通过日志语句重用字段
	// logrus.Entry 返回自 WithFields()
	contextLogger := log.WithFields(log.Fields{
		"common": "this is a common field",
		"other":  "I also should be logged always",
	})

	contextLogger.Info("I'll be logged with common and other field")
	contextLogger.Info("Me too")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# seelog 介绍

seelog 是用 Go 语言实现的一个日志系统,它提供了一些简单的函数来实现复杂的日志分配、过滤和格式化。主要有如下特性:

  • XML 的动态配置,可以不用重新编译程序而动态的加载配置信息

  • 支持热更新,能够动态改变配置而不需要重启应用

  • 支持多输出流,能够同时把日志输出到多种流中、例如文件流、网络流等

  • 支持不同的日志输出

    • 命令行输出
    • 文件输出
    • 缓存输出
    • 支持 log rotate
    • SMTP 邮件

上面只列举了部分特性,seelog 是一个特别强大的日志处理系统,详细的内容请参看官方 wiki。接下来我将简要介绍一下如何在项目中使用它:

首先安装 seelog

go get -u github.com/cihub/seelog
1

然后我们来看一个简单的例子:

package main

import log "github.com/cihub/seelog"

func main() {
    defer log.Flush()
    log.Info("Hello from Seelog!")
}

1
2
3
4
5
6
7
8
9

编译后运行如果出现了 Hello from seelog,说明 seelog 日志系统已经成功安装并且可以正常运行了。

# 基于 seelog 的自定义日志处理

seelog 支持自定义日志处理,下面是我基于它自定义的日志处理包的部分内容:

package logs

import (
	// "errors"
	"fmt"
	// "io"

	seelog "github.com/cihub/seelog"
)

var Logger seelog.LoggerInterface

func loadAppConfig() {
	appConfig := `
<seelog minlevel="warn">
    <outputs formatid="common">
        <rollingfile type="size" filename="/data/logs/roll.log" maxsize="100000" maxrolls="5"/>
		<filter levels="critical">
            <file path="/data/logs/critical.log" formatid="critical"/>
            <smtp formatid="criticalemail" senderaddress="astaxie@gmail.com" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword">
                <recipient address="xiemengjun@gmail.com"/>
            </smtp>
        </filter>
    </outputs>
    <formats>
        <format id="common" format="%Date/%Time [%LEV] %Msg%n" />
	    <format id="critical" format="%File %FullPath %Func %Msg%n" />
	    <format id="criticalemail" format="Critical error on our server!\n    %Time %Date %RelFile %Func %Msg \nSent by Seelog"/>
    </formats>
</seelog>
`
	logger, err := seelog.LoggerFromConfigAsBytes([]byte(appConfig))
	if err != nil {
		fmt.Println(err)
		return
	}
	UseLogger(logger)
}

func init() {
	DisableLog()
	loadAppConfig()
}

// DisableLog disables all library log output
func DisableLog() {
	Logger = seelog.Disabled
}

// UseLogger uses a specified seelog.LoggerInterface to output library log.
// Use this func if you are using Seelog logging system in your app.
func UseLogger(newLogger seelog.LoggerInterface) {
	Logger = newLogger
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

上面主要实现了三个函数,

  • DisableLog

    初始化全局变量 Logger 为 seelog 的禁用状态,主要为了防止 Logger 被多次初始化

  • loadAppConfig

    根据配置文件初始化 seelog 的配置信息,这里我们把配置文件通过字符串读取设置好了,当然也可以通过读取 XML 文件。里面的配置说明如下:

    • seelog

      minlevel 参数可选,如果被配置,高于或等于此级别的日志会被记录,同理 maxlevel。

    • outputs

      输出信息的目的地,这里分成了两份数据,一份记录到 log rotate 文件里面。另一份设置了 filter,如果这个错误级别是 critical,那么将发送报警邮件。

    • formats

      定义了各种日志的格式

  • UseLogger

    设置当前的日志器为相应的日志处理

上面我们定义了一个自定义的日志处理包,下面就是使用示例:

package main

import (
	"net/http"
	"project/logs"
	"project/configs"
	"project/routes"
)

func main() {
	addr, _ := configs.MainConfig.String("server", "addr")
	logs.Logger.Info("Start server at:%v", addr)
	err := http.ListenAndServe(addr, routes.NewMux())
	logs.Logger.Critical("Server err:%v", err)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 发生错误发送邮件

上面的例子解释了如何设置发送邮件,我们通过如下的 smtp 配置用来发送邮件:

<smtp formatid="criticalemail" senderaddress="astaxie@gmail.com" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword">
	<recipient address="xiemengjun@gmail.com"/>
</smtp>
1
2
3

邮件的格式通过 criticalemail 配置,然后通过其他的配置发送邮件服务器的配置,通过 recipient 配置接收邮件的用户,如果有多个用户可以再添加一行。

要测试这个代码是否正常工作,可以在代码中增加类似下面的一个假消息。不过记住过后要把它删除,否则上线之后就会收到很多垃圾邮件。

logs.Logger.Critical("test Critical message")
1

现在,只要我们的应用在线上记录一个 Critical 的信息,你的邮箱就会收到一个 Email,这样一旦线上的系统出现问题,你就能立马通过邮件获知,就能及时的进行处理。

# 使用应用日志

对于应用日志,每个人的应用场景可能会各不相同,有些人利用应用日志来做数据分析,有些人利用应用日志来做性能分析,有些人来做用户行为分析,还有些就是纯粹的记录,以方便应用出现问题的时候辅助查找问题。

举一个例子,我们需要跟踪用户尝试登录系统的操作。这里会把成功与不成功的尝试都记录下来。记录成功的使用 "Info" 日志级别,而不成功的使用 "warn" 级别。如果想查找所有不成功的登录,我们可以利用 linux 的 grep 之类的命令工具,如下:

# cat /data/logs/roll.log | grep "failed login"
2012-12-11 11:12:00 WARN : failed login attempt from 11.22.33.44 username password
1
2

通过这种方式我们就可以很方便的查找相应的信息,这样有利于我们针对应用日志做一些统计和分析。另外我们还需要考虑日志的大小,对于一个高流量的 Web 应用来说,日志的增长是相当可怕的,所以我们在 seelog 的配置文件里面设置了 logrotate,这样就能保证日志文件不会因为不断变大而导致我们的磁盘空间不够引起问题。

# 小结

通过上面对 seelog 系统及如何基于它进行自定义日志系统的学习,现在我们可以很轻松的随需构建一个合适的功能强大的日志处理系统了。日志处理系统为数据分析提供了可靠的数据源,比如通过对日志的分析,我们可以进一步优化系统,或者应用出现问题时方便查找定位问题,另外 seelog 也提供了日志分级功能,通过对 minlevel 的配置,我们可以很方便的设置测试或发布版本的输出消息级别。

  • logrus 介绍
  • 基于 logrus 的自定义日志处理
  • seelog 介绍
  • 基于 seelog 的自定义日志处理
  • 发生错误发送邮件
  • 使用应用日志
  • 小结