|
1 | | -# 12.1 应用日志 |
2 | | -我们期望开发的Web应用程序能够把整个程序运行过程中出现的各种事件一一记录下来,Go语言中提供了一个简易的log包,我们使用该包可以方便的实现日志记录的功能,这些日志都是基本的给予fmt包的打印再结合panic之类的一些函数来处理我们一般的打印抛出错误之类的。如果我们想把我们的应用日志保存到文件,然后又能够结合日志实现很多复杂的功能,编写过Java或者C++的读者应该都使用过log4j和log4cpp之类的日志工具,Go目前标准包就如前面介绍的只是包含了一个简单的包,但是目前第三方开发的一个日志系统实现了很强大的日志功能,`https://github.com/cihub/seelog`,接下来我们介绍如何该日志系统来实现我们应用的日志功能。 |
3 | | - |
4 | | -## seelog介绍 |
5 | | -seelog是用Go语言实现的一个日志系统,他提供了一些简单的函数来实现复杂的日志分配、过滤和格式化。他主要有如下特性: |
6 | | - |
7 | | -- XML配置文件,可以不用重新编译程序而动态的加载配置信息 |
8 | | -- 能够动态改变配置而不需要重启应用 |
9 | | -- 能够同时把日志输出到多种流中 |
10 | | -- 支持不同的日志输出 |
11 | | - |
12 | | - - 命令行输出 |
13 | | - - 文件输出 |
14 | | - - 缓存输出 |
15 | | - - 支持log rotate |
16 | | - - SMTP邮件 |
17 | | - |
18 | | -上面介绍的只是部分特性,其他seelog是一个特别强大的日志处理系统,详细的可以参考官方网站的wiki。接下来介绍一下如何在项目中使用: |
19 | | - |
20 | | -首先安装seelog |
21 | | - |
22 | | - go get -u github.com/cihub/seelog |
23 | | - |
24 | | -然后我们来看一个简单的例子: |
25 | | - |
26 | | - package main |
27 | | - |
28 | | - import log "github.com/cihub/seelog" |
29 | | - |
30 | | - func main() { |
31 | | - defer log.Flush() |
32 | | - log.Info("Hello from Seelog!") |
33 | | - } |
34 | | - |
35 | | -我们编译之后可以正常的输出日志了,说明seelog日志系统已经成功安装并且可以正常运行了。 |
36 | | - |
37 | | -## 基于seelog的自定义日志处理 |
38 | | -seelog支持让我们给予seelog自定义日志处理,下面这个是我目前基于seelog日志系统做的自定义的日志处理包: |
39 | | - |
40 | | - package logs |
41 | | - |
42 | | - import ( |
43 | | - "errors" |
44 | | - "fmt" |
45 | | - seelog "github.com/cihub/seelog" |
46 | | - "io" |
47 | | - ) |
48 | | - |
49 | | - var Logger seelog.LoggerInterface |
50 | | - |
51 | | - func loadAppConfig() { |
52 | | - appConfig := ` |
53 | | - <seelog minlevel="warn"> |
54 | | - <outputs formatid="common"> |
55 | | - <rollingfile type="size" filename="/data/logs/roll.log" maxsize="100000" maxrolls="5"/> |
56 | | - <filter levels="critical"> |
57 | | - <file path="/data/logs/critical.log" formatid="critical"/> |
58 | | - <smtp formatid="criticalemail" senderaddress="[email protected]" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword"> |
59 | | - <recipient address="[email protected]"/> |
60 | | - </smtp> |
61 | | - </filter> |
62 | | - </outputs> |
63 | | - <formats> |
64 | | - <format id="common" format="%Date/%Time [%LEV] %Msg%n" /> |
65 | | - <format id="critical" format="%File %FullPath %Func %Msg%n" /> |
66 | | - <format id="criticalemail" format="Critical error on our server!\n %Time %Date %RelFile %Func %Msg \nSent by Seelog"/> |
67 | | - </formats> |
68 | | - </seelog> |
69 | | - ` |
70 | | - logger, err := seelog.LoggerFromConfigAsBytes([]byte(appConfig)) |
71 | | - if err != nil { |
72 | | - fmt.Println(err) |
73 | | - return |
74 | | - } |
75 | | - UseLogger(logger) |
76 | | - } |
77 | | - |
78 | | - func init() { |
79 | | - DisableLog() |
80 | | - loadAppConfig() |
81 | | - } |
82 | | - |
83 | | - // DisableLog disables all library log output |
84 | | - func DisableLog() { |
85 | | - Logger = seelog.Disabled |
86 | | - } |
87 | | - |
88 | | - // UseLogger uses a specified seelog.LoggerInterface to output library log. |
89 | | - // Use this func if you are using Seelog logging system in your app. |
90 | | - func UseLogger(newLogger seelog.LoggerInterface) { |
91 | | - Logger = newLogger |
92 | | - } |
93 | | - |
94 | | -上面主要实现了三个函数, |
95 | | - |
96 | | -- `DisableLog` |
97 | | - |
98 | | - 初始化全局变量Logger为目前seelog的禁用状态,主要防止Logger初始化多次 |
99 | | -- `loadAppConfig` |
100 | | - |
101 | | - 根据配置文件初始化seelog的配置信息,这里我们把配置文件通过字符串读取设置好了,当然也可以通过读取XML文件。里面的配置说明如下: |
102 | | - |
103 | | - - seelog |
104 | | - |
105 | | - minlevel可有可无,有的话设置最小级别的日志级别需要记录,还有maxlevel也是类似的原理 |
106 | | - - outputs |
107 | | - |
108 | | - 输出信息到那些地方,这里分成了两个数据,一个记录到log rotate文件里面。第二设置了一个filter,如果这个错误级别是critical,那么发送邮件。 |
109 | | - |
110 | | - - formats |
111 | | - |
112 | | - 定义了各种日志的格式 |
113 | | - |
114 | | -- `UseLogger` |
115 | | - |
116 | | - 设置当前的日志器为相应的日志处理 |
117 | | - |
118 | | -上面我们定义了一个自定义的日志处理包,下面就是使用示例: |
119 | | - |
120 | | - package main |
121 | | - |
122 | | - import ( |
123 | | - "net/http" |
124 | | - "project/logs" |
125 | | - "project/configs" |
126 | | - "project/routes" |
127 | | - ) |
128 | | - |
129 | | - func main() { |
130 | | - addr, _ := configs.MainConfig.String("server", "addr") |
131 | | - logs.Logger.Info("Start server at:%v", addr) |
132 | | - err := http.ListenAndServe(addr, routes.NewMux()) |
133 | | - logs.Logger.Critical("Server err:%v", err) |
134 | | - } |
135 | | - |
136 | | -## 发生错误发送邮件 |
137 | | -上面的例子解释了如何设置发送邮件,我们通过如下的smtp配置用来发送邮件: |
138 | | - |
139 | | - <smtp formatid="criticalemail" senderaddress="[email protected]" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword"> |
140 | | - <recipient address="[email protected]"/> |
141 | | - </smtp> |
142 | | - |
143 | | -邮件的格式通过criticalemail配置,然后通过其他的配置发送邮件服务器的配置,通过recipient配置接收邮件的用户,如果有多个用户可以再添加一行。 |
144 | | - |
145 | | -要测试这个代码是否正常工作,可以在代码中增加类似下面的一个假消息。不过记住过后要把它删除,否则上线之后就会收到很多垃圾邮件。 |
146 | | - |
147 | | - logs.Logger.Critical("test Critical message") |
148 | | - |
149 | | -现在,只要我们的应用在线上记录一个Critical的信息,你的邮箱就会收到一个Email,这样一旦线上的系统出现问题,你就能立马通过邮件获知,就能及时的进行处理。 |
150 | | -## 使用应用日志 |
151 | | -对于应用日志,每个人的应用场景可能会各不相同,有些人利用应用日志来做数据分析,有些人利用应用日志来做性能分析,有些人来做用户行为分析,还有些就是纯粹的记录方便应用出现问题的时候可以查找问题。 |
152 | | - |
153 | | -举一个例子,我们需要跟踪用户尝试登陆系统的操作。这里会把成功与不成功的尝试都记录下来。记录成功的使用"Info"日志级别,而不成功的使用"warn"级别。如果想查找所有不成功的登陆,我们可以利用linux的grep之类的命令工具,如下: |
154 | | - |
155 | | - # cat /data/logs/roll.log | grep "failed login" |
156 | | - 2012-12-11 11:12:00 WARN : failed login attempt from 11.22.33.44 username password |
157 | | - |
158 | | -通过这种方式我们就可以很方便的查找相应的信息,这样有利于我们针对应用日志做一些统计和分析。另外我们还需要考虑日志的大小,对于一个高流量的Web应用来说,日志的增长是相当可怕的,所以我们在seelog的配置文件里面设置了logrotate,这样就能保证日志文件不会因为不断变大而导致我们的磁盘空间不够引起问题。 |
159 | | -## 小结 |
160 | | -通过上面对seelog系统的介绍,以及如何开发基于seelog的日志处理包,我们现在可以很轻松的就搭建起来一个功能强大的日志处理系统,日志处理系统对于我们的数据分析提供可靠的数据源,通过分析可以进一步优化我们的系统,而且一旦应用出现问题也方便我们查找问题,而同时seelog也提供了调试输出的功能,这样对于开发阶段来说就可以很方便的来调试各种数据,上线的时候通过设置minlevel可以很方便的屏蔽这些调试级别的信息。 |
161 | | - |
162 | | -## links |
163 | | - * [目录](<preface.md>) |
164 | | - * 上一章: [部署与维护](<12.md>) |
| 1 | +# 12.1 应用日志 |
| 2 | +我们期望开发的Web应用程序能够把整个程序运行过程中出现的各种事件一一记录下来,Go语言中提供了一个简易的log包,我们使用该包可以方便的实现日志记录的功能,这些日志都是基本的给予fmt包的打印再结合panic之类的一些函数来处理我们一般的打印抛出错误之类的。如果我们想把我们的应用日志保存到文件,然后又能够结合日志实现很多复杂的功能,编写过Java或者C++的读者应该都使用过log4j和log4cpp之类的日志工具,Go目前标准包就如前面介绍的只是包含了一个简单的包,但是目前第三方开发的一个日志系统实现了很强大的日志功能,`https://github.com/cihub/seelog`,接下来我们介绍如何该日志系统来实现我们应用的日志功能。 |
| 3 | + |
| 4 | +## seelog介绍 |
| 5 | +seelog是用Go语言实现的一个日志系统,它提供了一些简单的函数来实现复杂的日志分配、过滤和格式化。主要有如下特性: |
| 6 | + |
| 7 | +- XML的动态配置,可以不用重新编译程序而动态的加载配置信息 |
| 8 | +- 支持热更新,能够动态改变配置而不需要重启应用 |
| 9 | +- 支持多输出流,能够同时把日志输出到多种流中、例如文件流、网络流等 |
| 10 | +- 支持不同的日志输出 |
| 11 | + |
| 12 | + - 命令行输出 |
| 13 | + - 文件输出 |
| 14 | + - 缓存输出 |
| 15 | + - 支持log rotate |
| 16 | + - SMTP邮件 |
| 17 | + |
| 18 | +上面只列举了部分特性,seelog是一个特别强大的日志处理系统,详细的内容请参看官方wiki。接下来我将简要介绍一下如何在项目中使用它: |
| 19 | + |
| 20 | +首先安装seelog |
| 21 | + |
| 22 | + go get -u github.com/cihub/seelog |
| 23 | + |
| 24 | +然后我们来看一个简单的例子: |
| 25 | + |
| 26 | + package main |
| 27 | + |
| 28 | + import log "github.com/cihub/seelog" |
| 29 | + |
| 30 | + func main() { |
| 31 | + defer log.Flush() |
| 32 | + log.Info("Hello from Seelog!") |
| 33 | + } |
| 34 | + |
| 35 | +编译后运行如果出现了`Hello from seelog`,说明seelog日志系统已经成功安装并且可以正常运行了。 |
| 36 | + |
| 37 | +## 基于seelog的自定义日志处理 |
| 38 | +seelog支持自定义日志处理,下面是我基于它自定义的日志处理包的部分内容: |
| 39 | + |
| 40 | + package logs |
| 41 | + |
| 42 | + import ( |
| 43 | + "errors" |
| 44 | + "fmt" |
| 45 | + seelog "github.com/cihub/seelog" |
| 46 | + "io" |
| 47 | + ) |
| 48 | + |
| 49 | + var Logger seelog.LoggerInterface |
| 50 | + |
| 51 | + func loadAppConfig() { |
| 52 | + appConfig := ` |
| 53 | + <seelog minlevel="warn"> |
| 54 | + <outputs formatid="common"> |
| 55 | + <rollingfile type="size" filename="/data/logs/roll.log" maxsize="100000" maxrolls="5"/> |
| 56 | + <filter levels="critical"> |
| 57 | + <file path="/data/logs/critical.log" formatid="critical"/> |
| 58 | + <smtp formatid="criticalemail" senderaddress="[email protected]" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword"> |
| 59 | + <recipient address="[email protected]"/> |
| 60 | + </smtp> |
| 61 | + </filter> |
| 62 | + </outputs> |
| 63 | + <formats> |
| 64 | + <format id="common" format="%Date/%Time [%LEV] %Msg%n" /> |
| 65 | + <format id="critical" format="%File %FullPath %Func %Msg%n" /> |
| 66 | + <format id="criticalemail" format="Critical error on our server!\n %Time %Date %RelFile %Func %Msg \nSent by Seelog"/> |
| 67 | + </formats> |
| 68 | + </seelog> |
| 69 | + ` |
| 70 | + logger, err := seelog.LoggerFromConfigAsBytes([]byte(appConfig)) |
| 71 | + if err != nil { |
| 72 | + fmt.Println(err) |
| 73 | + return |
| 74 | + } |
| 75 | + UseLogger(logger) |
| 76 | + } |
| 77 | + |
| 78 | + func init() { |
| 79 | + DisableLog() |
| 80 | + loadAppConfig() |
| 81 | + } |
| 82 | + |
| 83 | + // DisableLog disables all library log output |
| 84 | + func DisableLog() { |
| 85 | + Logger = seelog.Disabled |
| 86 | + } |
| 87 | + |
| 88 | + // UseLogger uses a specified seelog.LoggerInterface to output library log. |
| 89 | + // Use this func if you are using Seelog logging system in your app. |
| 90 | + func UseLogger(newLogger seelog.LoggerInterface) { |
| 91 | + Logger = newLogger |
| 92 | + } |
| 93 | + |
| 94 | +上面主要实现了三个函数, |
| 95 | + |
| 96 | +- `DisableLog` |
| 97 | + |
| 98 | + 初始化全局变量Logger为seelog的禁用状态,主要为了防止Logger被多次初始化 |
| 99 | +- `loadAppConfig` |
| 100 | + |
| 101 | + 根据配置文件初始化seelog的配置信息,这里我们把配置文件通过字符串读取设置好了,当然也可以通过读取XML文件。里面的配置说明如下: |
| 102 | + |
| 103 | + - seelog |
| 104 | + |
| 105 | + minlevel参数可选,如果被配置,高于或等于此级别的日志会被记录,同理maxlevel。 |
| 106 | + - outputs |
| 107 | + |
| 108 | + 输出信息的目的地,这里分成了两份数据,一份记录到log rotate文件里面。另一份设置了filter,如果这个错误级别是critical,那么将发送报警邮件。 |
| 109 | + |
| 110 | + - formats |
| 111 | + |
| 112 | + 定义了各种日志的格式 |
| 113 | + |
| 114 | +- `UseLogger` |
| 115 | + |
| 116 | + 设置当前的日志器为相应的日志处理 |
| 117 | + |
| 118 | +上面我们定义了一个自定义的日志处理包,下面就是使用示例: |
| 119 | + |
| 120 | + package main |
| 121 | + |
| 122 | + import ( |
| 123 | + "net/http" |
| 124 | + "project/logs" |
| 125 | + "project/configs" |
| 126 | + "project/routes" |
| 127 | + ) |
| 128 | + |
| 129 | + func main() { |
| 130 | + addr, _ := configs.MainConfig.String("server", "addr") |
| 131 | + logs.Logger.Info("Start server at:%v", addr) |
| 132 | + err := http.ListenAndServe(addr, routes.NewMux()) |
| 133 | + logs.Logger.Critical("Server err:%v", err) |
| 134 | + } |
| 135 | + |
| 136 | +## 发生错误发送邮件 |
| 137 | +上面的例子解释了如何设置发送邮件,我们通过如下的smtp配置用来发送邮件: |
| 138 | + |
| 139 | + <smtp formatid="criticalemail" senderaddress="[email protected]" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword"> |
| 140 | + <recipient address="[email protected]"/> |
| 141 | + </smtp> |
| 142 | + |
| 143 | +邮件的格式通过criticalemail配置,然后通过其他的配置发送邮件服务器的配置,通过recipient配置接收邮件的用户,如果有多个用户可以再添加一行。 |
| 144 | + |
| 145 | +要测试这个代码是否正常工作,可以在代码中增加类似下面的一个假消息。不过记住过后要把它删除,否则上线之后就会收到很多垃圾邮件。 |
| 146 | + |
| 147 | + logs.Logger.Critical("test Critical message") |
| 148 | + |
| 149 | +现在,只要我们的应用在线上记录一个Critical的信息,你的邮箱就会收到一个Email,这样一旦线上的系统出现问题,你就能立马通过邮件获知,就能及时的进行处理。 |
| 150 | +## 使用应用日志 |
| 151 | +对于应用日志,每个人的应用场景可能会各不相同,有些人利用应用日志来做数据分析,有些人利用应用日志来做性能分析,有些人来做用户行为分析,还有些就是纯粹的记录,以方便应用出现问题的时候辅助查找问题。 |
| 152 | + |
| 153 | +举一个例子,我们需要跟踪用户尝试登陆系统的操作。这里会把成功与不成功的尝试都记录下来。记录成功的使用"Info"日志级别,而不成功的使用"warn"级别。如果想查找所有不成功的登陆,我们可以利用linux的grep之类的命令工具,如下: |
| 154 | + |
| 155 | + # cat /data/logs/roll.log | grep "failed login" |
| 156 | + 2012-12-11 11:12:00 WARN : failed login attempt from 11.22.33.44 username password |
| 157 | + |
| 158 | +通过这种方式我们就可以很方便的查找相应的信息,这样有利于我们针对应用日志做一些统计和分析。另外我们还需要考虑日志的大小,对于一个高流量的Web应用来说,日志的增长是相当可怕的,所以我们在seelog的配置文件里面设置了logrotate,这样就能保证日志文件不会因为不断变大而导致我们的磁盘空间不够引起问题。 |
| 159 | + |
| 160 | +## 小结 |
| 161 | +通过上面对seelog系统及如何基于它进行自定义日志系统的学习,现在我们可以很轻松的随需构建一个合适的功能强大的日志处理系统了。日志处理系统为数据分析提供了可靠的数据源,比如通过对日志的分析,我们可以进一步优化系统,或者应用出现问题时方便查找定位问题,另外seelog也提供了日志分级功能,通过对minlevel的配置,我们可以很方便的测试或发布版本的输出消息。 |
| 162 | + |
| 163 | +## links |
| 164 | + * [目录](<preface.md>) |
| 165 | + * 上一章: [部署与维护](<12.md>) |
165 | 166 | * 下一节: [网站错误处理](<12.2.md>) |
0 commit comments