-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
449 lines (303 loc) · 57.6 KB
/
index.html
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hexo</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta property="og:type" content="website">
<meta property="og:title" content="Hexo">
<meta property="og:url" content="http://example.com/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="John Doe">
<meta name="twitter:card" content="summary">
<link rel="alternate" href="/atom.xml" title="Hexo" type="application/atom+xml">
<link rel="icon" href="/favicon.png">
<link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="/css/style.css">
<meta name="generator" content="Hexo 5.2.0"></head>
<body>
<div id="container">
<div id="wrap">
<header id="header">
<div id="banner"></div>
<div id="header-outer" class="outer">
<div id="header-title" class="inner">
<h1 id="logo-wrap">
<a href="/" id="logo">Hexo</a>
</h1>
</div>
<div id="header-inner" class="inner">
<nav id="main-nav">
<a id="main-nav-toggle" class="nav-icon"></a>
<a class="main-nav-link" href="/">Home</a>
<a class="main-nav-link" href="/archives">Archives</a>
</nav>
<nav id="sub-nav">
<a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
<a id="nav-search-btn" class="nav-icon" title="Search"></a>
</nav>
<div id="search-form-wrap">
<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit"></button><input type="hidden" name="sitesearch" value="http://example.com"></form>
</div>
</div>
</div>
</header>
<div class="outer">
<section id="main">
<article id="post-Golang日志库对比" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2020/10/22/Golang%E6%97%A5%E5%BF%97%E5%BA%93%E5%AF%B9%E6%AF%94/" class="article-date">
<time datetime="2020-10-22T06:13:02.000Z" itemprop="datePublished">2020-10-22</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2020/10/22/Golang%E6%97%A5%E5%BF%97%E5%BA%93%E5%AF%B9%E6%AF%94/">Golang日志库对比</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<h2 id="一、Golang-Built-In-log-package"><a href="#一、Golang-Built-In-log-package" class="headerlink" title="一、Golang Built-In log package"></a>一、Golang Built-In log package</h2><p>Go标准库log提供了最基础的日志功能。没有提供日志级别,但是它为用户提供了构建日志策略所需的最基本的属性。</p>
<h3 id="简单使用"><a href="#简单使用" class="headerlink" title="简单使用"></a>简单使用</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">"log"</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"> <span class="comment">// 向标准输出打印,日志信息包含日期和时间(可以通过日期过滤日志信息)</span></span><br><span class="line"> log.Println(<span class="string">"Hello world!"</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2020/09/28 10:36:32 Hello world! 控制台打印信息</span></span><br></pre></td></tr></table></figure>
<p>默认情况下,log package将日志信息打印到标准输出中,但是可以配置输出到任意实现了<code>io.Writer</code>接口的位置中,例如输出到文件中。</p>
<h3 id="日志输出到文件中"><a href="#日志输出到文件中" class="headerlink" title="日志输出到文件中"></a>日志输出到文件中</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"> <span class="string">"log"</span></span><br><span class="line"> <span class="string">"os"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"> <span class="comment">// if the file doesn't exist, create it or append to the file</span></span><br><span class="line"> file, err := os.OpenFile(<span class="string">"log.txt"</span>, os.O_APPEND|os.O_CREATE|os.O_WRONLY, <span class="number">0666</span>)</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> log.Fatal(err)</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> log.SetOutput(file) <span class="comment">// 将日志信息输出到文件中</span></span><br><span class="line"> </span><br><span class="line"> log.Println(<span class="string">"Hello world!"</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2020/09/28 10:36:32 Hello world! 输出到文件中的日志信息</span></span><br></pre></td></tr></table></figure>
<h3 id="基于log标准库,构建自定义logger"><a href="#基于log标准库,构建自定义logger" class="headerlink" title="基于log标准库,构建自定义logger"></a>基于log标准库,构建自定义logger</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"> <span class="string">"log"</span></span><br><span class="line"> <span class="string">"os"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> (</span><br><span class="line"> <span class="comment">// 定义不同级别的日志类型</span></span><br><span class="line"> WarningLogger *log.Logger</span><br><span class="line"> InfoLogger *log.Logger</span><br><span class="line"> ErrorLogger *log.Logger</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">init</span><span class="params">()</span></span> {</span><br><span class="line"> file, err := os.OpenFile(<span class="string">"log.txt"</span>, os.O_APPEND|os.O_CREATE|os.O_WRONLY, <span class="number">0666</span>)</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> log.Fatal(err)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 为每种日志类型定义输出格式:输出位置,日志前缀信息,提示信息:日期 | 时间 | src文件位置及行号</span></span><br><span class="line"> <span class="comment">// 报告文件位置及行号,调用runtime.Caller()性能消耗大</span></span><br><span class="line"> InfoLogger = log.New(file, <span class="string">"INFO: "</span>, log.Ldate|log.Ltime|log.Llongfile) <span class="comment">// 可以将不同级别的日志输出不同文件中</span></span><br><span class="line"> WarningLogger = log.New(file, <span class="string">"WARNING"</span>, log.Ldate|log.Ltime|log.Lshortfile)</span><br><span class="line"> ErrorLogger = log.New(file, <span class="string">"ERROR"</span>, log.Ldate|log.Ltime|log.Lshortfile)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"> InfoLogger.Println(<span class="string">"Starting the application..."</span>)</span><br><span class="line"> InfoLogger.Println(<span class="string">"Something noteworthy happened"</span>)</span><br><span class="line"> WarningLogger.Println(<span class="string">"There is something you should know about"</span>)</span><br><span class="line"> ErrorLogger.Println(<span class="string">"Something went wrong"</span>)</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>新构建的Info,warning,error三种级别的日志类型;对日志格式设置了前缀信息,时间,行号等附加信息。以上代码的日志输出如下:</p>
<figure class="highlight zsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">INFO: 2020/09/28 10:36:32 main.go:26: Starting the application...</span><br><span class="line">INFO: 2020/09/28 10:36:32 main.go:27: Something noteworthy happened</span><br><span class="line">WARNING2020/09/28 10:36:32 main.go:28: There is something you should know about</span><br><span class="line">ERROR2020/09/28 10:36:32 main.go:29: Something went wrong</span><br></pre></td></tr></table></figure>
<h3 id="性能消耗"><a href="#性能消耗" class="headerlink" title="性能消耗"></a>性能消耗</h3><p>runtime.Caller()能够拿到当前执行的文件名和行号,这个方法几乎所有的日志组件都有使用。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Caller reports file and line number information about function invocations on</span></span><br><span class="line"><span class="comment">// the calling goroutine's stack. The argument skip is the number of stack frames</span></span><br><span class="line"><span class="comment">// to ascend, with 0 identifying the caller of Caller. (For historical reasons the</span></span><br><span class="line"><span class="comment">// meaning of skip differs between Caller and Callers.) The return values report the</span></span><br><span class="line"><span class="comment">// program counter, file name, and line number within the file of the corresponding</span></span><br><span class="line"><span class="comment">// call. The boolean ok is false if it was not possible to recover the information.</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Caller</span><span class="params">(skip <span class="keyword">int</span>)</span> <span class="params">(pc <span class="keyword">uintptr</span>, file <span class="keyword">string</span>, line <span class="keyword">int</span>, ok <span class="keyword">bool</span>)</span></span> {</span><br><span class="line"> rpc := <span class="built_in">make</span>([]<span class="keyword">uintptr</span>, <span class="number">1</span>)</span><br><span class="line"> n := callers(skip+<span class="number">1</span>, rpc[:])</span><br><span class="line"> <span class="keyword">if</span> n < <span class="number">1</span> {</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"> }</span><br><span class="line"> frame, _ := CallersFrames(rpc).Next()</span><br><span class="line"> <span class="keyword">return</span> frame.PC, frame.File, frame.Line, frame.PC != <span class="number">0</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这个函数开销很大。主要通过不停的迭代来跟踪到执行文件及行号,迭代过程单次消耗时间可以忽略不计,但是对于日志量巨大的服务而言影响还是很大的。</p>
<h2 id="二、Google-Glog"><a href="#二、Google-Glog" class="headerlink" title="二、Google/Glog"></a>二、Google/Glog</h2><p>Google/glog是C++版本google/glog的Go版本实现,实现了分级执行日志。 在kubernetes中,glog是默认的日志库。</p>
<h3 id="Overview"><a href="#Overview" class="headerlink" title="Overview"></a>Overview</h3><ul>
<li><p>glog将日志级别分为四种,分别是:INFO、WARNING、ERROR、FATAL,打印完日志后程序将会推出(os.Exit())。</p>
</li>
<li><p>每个日志等级对应一个日志文件,低等级的日志文件除了包含该等级的日志,还会包含高等级的日志。</p>
</li>
<li><p>日志文件可以根据大小切割,但不能根据日期切割。</p>
</li>
<li><p>日志文件名称格式:program.host.username.log.log_level.date-time.pid,不可自定义。</p>
</li>
<li><p>固定日志输出格式:Lmmdd hh:mm:ss.uuuuuu pid file:line] msg,不可自定义。</p>
</li>
</ul>
<h3 id="简单使用-1"><a href="#简单使用-1" class="headerlink" title="简单使用"></a>简单使用</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"> <span class="string">"flag"</span></span><br><span class="line"> <span class="string">"github.com/golang/glog"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"> flag.Parse()</span><br><span class="line"> <span class="keyword">defer</span> glog.Flush() <span class="comment">// flush all pending log I/O</span></span><br><span class="line"></span><br><span class="line"> glog.Infoln(<span class="string">"This is info message"</span>)</span><br><span class="line"> glog.Infof(<span class="string">"This is info message: %+v"</span>, <span class="number">12345</span>)</span><br><span class="line"></span><br><span class="line"> glog.Warningln(<span class="string">"This is warning message"</span>)</span><br><span class="line"> glog.Warningf(<span class="string">"This is warning message: %+v"</span>, <span class="number">12345</span>)</span><br><span class="line"></span><br><span class="line"> glog.Errorln(<span class="string">"This is error message"</span>)</span><br><span class="line"> glog.Errorf(<span class="string">"This is error message: %+v"</span>, <span class="number">12345</span>)</span><br><span class="line"></span><br><span class="line"> glog.Fatal(<span class="string">"This is fatal error"</span>)</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>运行程序:</p>
<figure class="highlight zsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ mkdir -p <span class="built_in">log</span> && go run main.go -log_dir=<span class="built_in">log</span> -alsologtostderr</span><br></pre></td></tr></table></figure>
<p>以上打印日志将会同时打印在<code>log/</code>目录和标准错误输出中(<code>-alsologtostderr</code>)</p>
<h2 id="三、结构化日志框架Logrus"><a href="#三、结构化日志框架Logrus" class="headerlink" title="三、结构化日志框架Logrus"></a>三、结构化日志框架Logrus</h2><h3 id="Overview-1"><a href="#Overview-1" class="headerlink" title="Overview"></a>Overview</h3><ul>
<li>完全兼容Golang标准库日志模块,因此对于使用<code>log</code>标准库的项目,可以使用<code>log "github.com/sirupsen/logrus"</code>直接替换即可。</li>
<li>logrus拥有七种日志级别:trace、debug、info、warn、error、fatal、panic,相当于标准库<code>log</code>的超集。</li>
<li>可扩展的Hook机制“允许使用者通过hook的方式将日志分发到任意地方,如本地文件系统、标准输出、logstash、elasticsearch或者mq等;或者通过hook定义日志内容和格式等。</li>
<li>可选的日志输出格式:logrus内置了两种日志格式。JSONFormatter和TextFormatter,如果这两个格式都不满足要求,可以通过实现Formatter接口,自定义日志格式。目前logrus支持的第三方日志格式也比较多,如FluentdFormatter、GELF、logstash等。</li>
<li>Field机制:logrus鼓励通过Field机制进行精细化的、结构化的日志记录,而不是通过冗长的消息来记录日志。</li>
</ul>
<h3 id="简单使用-2"><a href="#简单使用-2" class="headerlink" title="简单使用"></a>简单使用</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"> log <span class="string">"github.com/sirupsen/logrus"</span></span><br><span class="line"> <span class="string">"os"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">init</span><span class="params">()</span></span> {</span><br><span class="line"> log.SetFormatter(&log.JSONFormatter{}) <span class="comment">// 日志格式</span></span><br><span class="line"></span><br><span class="line"> log.SetOutput(os.Stdout) <span class="comment">// 重定向输出</span></span><br><span class="line"></span><br><span class="line"> log.SetLevel(log.TraceLevel) <span class="comment">// 日志显示级别</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 报告被调用位置(文件及行号)!!! 开启此功能对性能开销大</span></span><br><span class="line"> <span class="comment">// 考虑通过Hook的方式定制需要此功能的日志级别;比如对ERROR级别及以上的日志报告文件名及行号</span></span><br><span class="line"> log.SetReportCaller(<span class="literal">true</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"></span><br><span class="line"> log.Traceln(<span class="string">"Trace message"</span>)</span><br><span class="line"></span><br><span class="line"> log.Debugln(<span class="string">"Debug message"</span>)</span><br><span class="line"></span><br><span class="line"> log.Println(<span class="string">"Info message by Print func"</span>)</span><br><span class="line"> log.Infoln(<span class="string">"Info message by Info func"</span>)</span><br><span class="line"></span><br><span class="line"> log.Warningln(<span class="string">"Warning message"</span>)</span><br><span class="line"></span><br><span class="line"> log.Errorln(<span class="string">"Error message"</span>)</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>TextFormatter和JSONFormatter标准错误输出分别如下:</p>
<figure class="highlight zsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">TRAC[0000]/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-logrus/main.go:12 main.main() Trace message</span><br><span class="line">DEBU[0000]/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-logrus/main.go:14 main.main() Debug message</span><br><span class="line">INFO[0000]/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-logrus/main.go:16 main.main() Info message by Print func</span><br><span class="line">INFO[0000]/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-logrus/main.go:17 main.main() Info message by Info func</span><br><span class="line">WARN[0000]/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-logrus/main.go:19 main.main() Warning message</span><br><span class="line">ERRO[0000]/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-logrus/main.go:21 main.main() Error message</span><br></pre></td></tr></table></figure>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">{<span class="attr">"file"</span>:<span class="string">"/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-logrus/main.go:13"</span>,<span class="attr">"func"</span>:<span class="string">"main.main"</span>,<span class="attr">"level"</span>:<span class="string">"trace"</span>,<span class="attr">"msg"</span>:<span class="string">"Trace message"</span>,<span class="attr">"time"</span>:<span class="string">"2020-09-28T15:22:39+08:00"</span>}</span><br><span class="line">{<span class="attr">"file"</span>:<span class="string">"/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-logrus/main.go:15"</span>,<span class="attr">"func"</span>:<span class="string">"main.main"</span>,<span class="attr">"level"</span>:<span class="string">"debug"</span>,<span class="attr">"msg"</span>:<span class="string">"Debug message"</span>,<span class="attr">"time"</span>:<span class="string">"2020-09-28T15:22:39+08:00"</span>}</span><br><span class="line">{<span class="attr">"file"</span>:<span class="string">"/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-logrus/main.go:17"</span>,<span class="attr">"func"</span>:<span class="string">"main.main"</span>,<span class="attr">"level"</span>:<span class="string">"info"</span>,<span class="attr">"msg"</span>:<span class="string">"Info message by Print func"</span>,<span class="attr">"time"</span>:<span class="string">"2020-09-28T15:22:39+08:00"</span>}</span><br><span class="line">{<span class="attr">"file"</span>:<span class="string">"/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-logrus/main.go:18"</span>,<span class="attr">"func"</span>:<span class="string">"main.main"</span>,<span class="attr">"level"</span>:<span class="string">"info"</span>,<span class="attr">"msg"</span>:<span class="string">"Info message by Info func"</span>,<span class="attr">"time"</span>:<span class="string">"2020-09-28T15:22:39+08:00"</span>}</span><br><span class="line">{<span class="attr">"file"</span>:<span class="string">"/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-logrus/main.go:20"</span>,<span class="attr">"func"</span>:<span class="string">"main.main"</span>,<span class="attr">"level"</span>:<span class="string">"warning"</span>,<span class="attr">"msg"</span>:<span class="string">"Warning message"</span>,<span class="attr">"time"</span>:<span class="string">"2020-09-28T15:22:39+08:00"</span>}</span><br><span class="line">{<span class="attr">"file"</span>:<span class="string">"/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-logrus/main.go:22"</span>,<span class="attr">"func"</span>:<span class="string">"main.main"</span>,<span class="attr">"level"</span>:<span class="string">"error"</span>,<span class="attr">"msg"</span>:<span class="string">"Error message"</span>,<span class="attr">"time"</span>:<span class="string">"2020-09-28T15:22:39+08:00"</span>}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="FieldS用法"><a href="#FieldS用法" class="headerlink" title="FieldS用法"></a>FieldS用法</h3><p>logrus不推荐使用冗长的消息来记录运行信息,它推荐使用Fields来进行精细化的、结构化的信息记录。</p>
<p>例如下面的记录日志的方式:</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">log.Errorf(<span class="string">"Failed to send event %s to topic %s with key %d"</span>, event, topic, key)</span><br></pre></td></tr></table></figure>
<p>在logrus中鼓励使用以下方式替代:</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">log.WithFields(log.Fields{</span><br><span class="line"> <span class="string">"event"</span>: event,</span><br><span class="line"> <span class="string">"topic"</span>: topic,</span><br><span class="line"> <span class="string">"key"</span>: key,</span><br><span class="line">}).Errorf(<span class="string">"Failed to send event"</span>)</span><br></pre></td></tr></table></figure>
<p>通常,在一个应用中、或者应用的一部分中,都有一些固定的Field。比如在处理用户http请求时,上下文中,所有的日志都会有request_id和user_ip。为了避免每次记录日志都要使用log.WithFields(log.Fields{“request_id”: request_id, “user_ip”: user_ip}),我们可以创建一个logrus.Entry实例,为这个实例设置默认Fields,在上下文中使用这个logrus.Entry实例记录日志即可。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">logEntry := log.WithFields(log.Fields{<span class="string">"request_id"</span>: requestID, <span class="string">"user_ip"</span>: userIP})</span><br><span class="line">logEntry.Infoln(<span class="string">"Something happened on that request"</span>)</span><br></pre></td></tr></table></figure>
<h2 id="四、结构化日志框架Uber-Zap"><a href="#四、结构化日志框架Uber-Zap" class="headerlink" title="四、结构化日志框架Uber/Zap"></a>四、结构化日志框架Uber/Zap</h2><h3 id="Overview-2"><a href="#Overview-2" class="headerlink" title="Overview"></a>Overview</h3><p>Blazing fast, structure, leveled logging in Go</p>
<p>根据Uber-go Zap的文档,它的性能比类似的结构化日志库更好,也比标准库更快。可参看<a target="_blank" rel="noopener" href="https://github.com/uber-go/zap">基准测试的对比表</a>。</p>
<h3 id="简单使用-3"><a href="#简单使用-3" class="headerlink" title="简单使用"></a>简单使用</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"> <span class="string">"go.uber.org/zap"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> log *zap.Logger</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">init</span><span class="params">()</span></span> {</span><br><span class="line"> <span class="comment">// zap提供了三种默认配置,分别对应NewExample() / NewDevelopment() / NewProduction()三个方法</span></span><br><span class="line"> log = zap.NewExample()</span><br><span class="line"> <span class="comment">// log, _ = zap.NewDevelopment()</span></span><br><span class="line"> <span class="comment">// log, _ = zap.NewProduction()</span></span><br><span class="line"> <span class="keyword">defer</span> log.Sync() <span class="comment">// flush buffers</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"></span><br><span class="line"> log.Debug(<span class="string">"Debug message"</span>)</span><br><span class="line"> log.Info(<span class="string">"Info message"</span>)</span><br><span class="line"> log.Warn(<span class="string">"Warning message"</span>)</span><br><span class="line"> log.Error(<span class="string">"Error message"</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment">//log.Panic("Panic message")</span></span><br><span class="line"> <span class="comment">//log.Fatal("Fatal message")</span></span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>标准输出日志如下:</p>
<figure class="highlight zsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># NewExample()对应配置的输出</span></span><br><span class="line">{<span class="string">"level"</span>:<span class="string">"debug"</span>,<span class="string">"msg"</span>:<span class="string">"Debug message"</span>}</span><br><span class="line">{<span class="string">"level"</span>:<span class="string">"info"</span>,<span class="string">"msg"</span>:<span class="string">"Info message"</span>}</span><br><span class="line">{<span class="string">"level"</span>:<span class="string">"warn"</span>,<span class="string">"msg"</span>:<span class="string">"Warning message"</span>}</span><br><span class="line">{<span class="string">"level"</span>:<span class="string">"error"</span>,<span class="string">"msg"</span>:<span class="string">"Error message"</span>}</span><br></pre></td></tr></table></figure>
<figure class="highlight zsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># NewDevelopment()对应配置的输出</span></span><br><span class="line">2020-09-28T17:49:26.098+0800 DEBUG go-zap/main.go:19 Debug message</span><br><span class="line">2020-09-28T17:49:26.099+0800 INFO go-zap/main.go:20 Info message</span><br><span class="line">2020-09-28T17:49:26.099+0800 WARN go-zap/main.go:21 Warning message</span><br><span class="line">main.main</span><br><span class="line"> /Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-zap/main.go:21</span><br><span class="line">runtime.main</span><br><span class="line"> /usr/<span class="built_in">local</span>/go/src/runtime/proc.go:204</span><br><span class="line">2020-09-28T17:49:26.099+0800 ERROR go-zap/main.go:22 Error message</span><br><span class="line">main.main</span><br><span class="line"> /Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-zap/main.go:22</span><br><span class="line">runtime.main</span><br><span class="line"> /usr/<span class="built_in">local</span>/go/src/runtime/proc.go:204</span><br></pre></td></tr></table></figure>
<figure class="highlight zsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># NewProduction()对应配置的输出</span></span><br><span class="line">{<span class="string">"level"</span>:<span class="string">"info"</span>,<span class="string">"ts"</span>:1601286676.22206,<span class="string">"caller"</span>:<span class="string">"go-zap/main.go:20"</span>,<span class="string">"msg"</span>:<span class="string">"Info message"</span>}</span><br><span class="line">{<span class="string">"level"</span>:<span class="string">"warn"</span>,<span class="string">"ts"</span>:1601286676.22211,<span class="string">"caller"</span>:<span class="string">"go-zap/main.go:21"</span>,<span class="string">"msg"</span>:<span class="string">"Warning message"</span>}</span><br><span class="line">{<span class="string">"level"</span>:<span class="string">"error"</span>,<span class="string">"ts"</span>:1601286676.222116,<span class="string">"caller"</span>:<span class="string">"go-zap/main.go:22"</span>,<span class="string">"msg"</span>:<span class="string">"Error message"</span>,<span class="string">"stacktrace"</span>:<span class="string">"main.main\n\t/Users/penglin/gopath/src/github.com/Niclausse/golang-log-study/go-zap/main.go:22\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:204"</span>}</span><br></pre></td></tr></table></figure>
<p>除了使用zap提供的默认配置,用户也可以自定义配置,定制Logger。</p>
<h3 id="Fields用法"><a href="#Fields用法" class="headerlink" title="Fields用法"></a>Fields用法</h3><p>由于<code>fmt.Printf</code>之类的方法大量使用<code>interface{}</code>和反射,会有不少性能损失,并且增加了内存分配的频次。<code>zap</code>为了提高性能、减少内存分配次数,没有使用反射,而且默认的<code>Logger</code>只支持强类型的、结构化的日志。必须使用<code>zap</code>提供的方法记录字段。<code>zap</code>为 Go 语言中所有的基本类型和其他常见类型都提供了方法。也有任意类型的字段:<code>zap.Any()</code>、<code>zap.Binary()</code>等。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">log.Error(<span class="string">"Failed to send event"</span>,</span><br><span class="line"> zap.String(<span class="string">"request_id"</span>, requestID),</span><br><span class="line"> zap.String(<span class="string">"user_ip"</span>, userIP),</span><br><span class="line"> zap.Int64(<span class="string">"index"</span>, index),</span><br><span class="line"> zap.Duration(<span class="string">"request_time"</span>, time.Second),</span><br><span class="line">)</span><br></pre></td></tr></table></figure>
<p>为每个字段都用方法包一层用起来比较繁琐。zap也提供了便捷的方法SugarLogger,可以使用<code>printf</code>格式符的方式。调用<code>logger.Sugar()</code>创建<code>SugaredLogger</code></p>
<p>。<code>SugaredLogger</code>的使用比<code>Logger</code>简单,只是性能要低50%左右,可以用在<strong>非热点函数</strong>中。</p>
<h3 id="记录层级关系"><a href="#记录层级关系" class="headerlink" title="记录层级关系"></a>记录层级关系</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 记录层级关系</span></span><br><span class="line"><span class="comment">// 方式1</span></span><br><span class="line">log.Info(<span class="string">"tracked some metrics"</span>,</span><br><span class="line"> zap.Namespace(<span class="string">"metrics"</span>),</span><br><span class="line"> zap.Int64(<span class="string">"counter"</span>, <span class="number">1</span>),</span><br><span class="line"> zap.String(<span class="string">"name"</span>, <span class="string">"m1"</span>),</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 方式2</span></span><br><span class="line">logger := log.With(</span><br><span class="line"> zap.Namespace(<span class="string">"metrics"</span>),</span><br><span class="line"> zap.Int(<span class="string">"counter"</span>, <span class="number">1</span>),</span><br><span class="line"> zap.String(<span class="string">"name"</span>, <span class="string">"m2"</span>),</span><br><span class="line">)</span><br><span class="line">logger.Info(<span class="string">"tracked some metrics"</span>)</span><br></pre></td></tr></table></figure>
<p>日志输出如下:</p>
<figure class="highlight zsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">{<span class="string">"level"</span>:<span class="string">"info"</span>,<span class="string">"msg"</span>:<span class="string">"tracked some metrics"</span>,<span class="string">"metrics"</span>:{<span class="string">"counter"</span>:1,<span class="string">"name"</span>:<span class="string">"m1"</span>}}</span><br><span class="line">{<span class="string">"level"</span>:<span class="string">"info"</span>,<span class="string">"msg"</span>:<span class="string">"tracked some metrics"</span>,<span class="string">"metrics"</span>:{<span class="string">"counter"</span>:1,<span class="string">"name"</span>:<span class="string">"m2"</span>}}</span><br></pre></td></tr></table></figure>
<h2 id="五、Iris框架中使用的日志库-→golog"><a href="#五、Iris框架中使用的日志库-→golog" class="headerlink" title="五、Iris框架中使用的日志库 →golog"></a>五、Iris框架中使用的日志库 →golog</h2><p>与glog类似,golog也是实现了日志分级的简单高效的日志库,不需要任何依赖。支持的日志级别如下:</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Method</th>
<th>Text</th>
</tr>
</thead>
<tbody><tr>
<td>debug</td>
<td>Debug, Debugf</td>
<td>[DEBUG]</td>
</tr>
<tr>
<td>info</td>
<td>Info, Infof</td>
<td>[INFO]</td>
</tr>
<tr>
<td>warn</td>
<td>Warn, Warnf, Warningf</td>
<td>[WARN]</td>
</tr>
<tr>
<td>error</td>
<td>Error, Errorf</td>
<td>[ERROR]</td>
</tr>
<tr>
<td>fatal</td>
<td>Fatal, Fatalf</td>
<td>[FATAL]</td>
</tr>
</tbody></table>
<h3 id="简单使用-4"><a href="#简单使用-4" class="headerlink" title="简单使用"></a>简单使用</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"> log <span class="string">"github.com/kataras/golog"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"> log.SetLevel(<span class="string">"debug"</span>)</span><br><span class="line"></span><br><span class="line"> log.Println(<span class="string">"Println message, no levels, no colors"</span>) <span class="comment">// 不会打印日志级别</span></span><br><span class="line"> log.Debug(<span class="string">"Debug message"</span>)</span><br><span class="line"> log.Info(<span class="string">"Info message"</span>)</span><br><span class="line"> log.Warn(<span class="string">"Warning message"</span>)</span><br><span class="line"> log.Error(<span class="string">"Error message"</span>)</span><br><span class="line"> log.Fatal(<span class="string">"Fatal message"</span>)</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight zsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">2020/09/28 19:22 Println message, no levels, no colors</span><br><span class="line">[DBUG] 2020/09/28 19:22 Debug message</span><br><span class="line">[INFO] 2020/09/28 19:22 Info message</span><br><span class="line">[WARN] 2020/09/28 19:22 Warning message</span><br><span class="line">[ERRO] 2020/09/28 19:22 Error message</span><br><span class="line">[FTAL] 2020/09/28 19:22 Fatal message</span><br><span class="line"><span class="built_in">exit</span> status 1</span><br></pre></td></tr></table></figure>
<h3 id="集成Level-based标准Logger"><a href="#集成Level-based标准Logger" class="headerlink" title="集成Level-based标准Logger"></a>集成Level-based标准Logger</h3><p>使用<code>Install</code>和<code>InstallStd</code>方法可以将<code>golog</code>包裹在其它日志库logger之上。(任何实现了<a target="_blank" rel="noopener" href="https://pkg.go.dev/github.com/kataras/golog#ExternalLogger">ExternalLogger</a>接口的Logger都可以适配)</p>
<p>例如:</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Simulate a logrus logger preparation</span></span><br><span class="line">logrus.SetLevel(logrus.InfoLevel)</span><br><span class="line">logrus.SetFormatter(&logrus.JSONFormatter{})</span><br><span class="line">logrus.SetReportCaller(<span class="literal">true</span>)</span><br><span class="line"></span><br><span class="line">log.Install(logrus.StandardLogger())</span><br><span class="line"></span><br><span class="line">log.Debugf(<span class="string">"Failed to send message: %s"</span>, <span class="string">"hello world!"</span>)</span><br><span class="line">log.Infof(<span class="string">"Failed to send message: %s"</span>, <span class="string">"hello world!"</span>)</span><br></pre></td></tr></table></figure>
<figure class="highlight zsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">{<span class="string">"file"</span>:<span class="string">"/Users/penglin/gopath/pkg/mod/github.com/kataras/[email protected]/integration.go:28"</span>,<span class="string">"func"</span>:<span class="string">"github.com/kataras/golog.integrateExternalLogger.func1"</span>,<span class="string">"level"</span>:<span class="string">"info"</span>,<span class="string">"msg"</span>:<span class="string">"Failed to send message: hello world!"</span>,<span class="string">"time"</span>:<span class="string">"2020-09-28T19:56:26+08:00"</span>}</span><br></pre></td></tr></table></figure>
<h2 id="六、特性对比"><a href="#六、特性对比" class="headerlink" title="六、特性对比"></a>六、特性对比</h2><table>
<thead>
<tr>
<th></th>
<th>日志分级</th>
<th>ReportCaller报告文件及行号</th>
<th>输出格式</th>
<th>日志切割</th>
<th>典型应用</th>
</tr>
</thead>
<tbody><tr>
<td>log</td>
<td>不支持</td>
<td>不支持</td>
<td>text</td>
<td>不支持,需自定义</td>
<td></td>
</tr>
<tr>
<td>kataras/golog</td>
<td>支持</td>
<td>不支持</td>
<td>text</td>
<td>不支持,需自定义</td>
<td>Iris</td>
</tr>
<tr>
<td>google/glog</td>
<td>支持(无DEBUG)</td>
<td>支持</td>
<td>text</td>
<td>只能根据日志文件大小切割,不能根据日期切割</td>
<td>k8s</td>
</tr>
<tr>
<td>logrus</td>
<td>支持</td>
<td>支持</td>
<td>支持结构化输出。支持第三方日志格式(如Fluentd, logstash, elastic search、mq等),也可通过Hook自定义logging formaater</td>
<td>不支持,需配合第三方库,如file-rotatelogs</td>
<td>Docker, Prometheus</td>
</tr>
<tr>
<td>Uber/zap</td>
<td>支持</td>
<td>支持</td>
<td>支持结构化输出</td>
<td>不支持,需配合第三方库,如lumberjack</td>
<td>Uber,Bilibili部分应用</td>
</tr>
</tbody></table>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2020/10/22/Golang%E6%97%A5%E5%BF%97%E5%BA%93%E5%AF%B9%E6%AF%94/" data-id="ckgkfzngu0001do07106t7v84" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Golang/" rel="tag">Golang</a></li></ul>
</footer>
</div>
</article>
<article id="post-hello-world" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2020/10/22/hello-world/" class="article-date">
<time datetime="2020-10-22T05:49:55.986Z" itemprop="datePublished">2020-10-22</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2020/10/22/hello-world/">Hello World</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>Welcome to <a target="_blank" rel="noopener" href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a target="_blank" rel="noopener" href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a target="_blank" rel="noopener" href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a target="_blank" rel="noopener" href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure>
<p>More info: <a target="_blank" rel="noopener" href="https://hexo.io/docs/writing.html">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>
<p>More info: <a target="_blank" rel="noopener" href="https://hexo.io/docs/server.html">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>
<p>More info: <a target="_blank" rel="noopener" href="https://hexo.io/docs/generating.html">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>
<p>More info: <a target="_blank" rel="noopener" href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2020/10/22/hello-world/" data-id="ckgkfzngh0000do078u2e6he5" class="article-share-link">Share</a>
</footer>
</div>
</article>
</section>
<aside id="sidebar">
<div class="widget-wrap">
<h3 class="widget-title">Tags</h3>
<div class="widget">
<ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/tags/Golang/" rel="tag">Golang</a></li></ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">Tag Cloud</h3>
<div class="widget tagcloud">
<a href="/tags/Golang/" style="font-size: 10px;">Golang</a>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">Archives</h3>
<div class="widget">
<ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/10/">October 2020</a></li></ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">Recent Posts</h3>
<div class="widget">
<ul>
<li>
<a href="/2020/10/22/Golang%E6%97%A5%E5%BF%97%E5%BA%93%E5%AF%B9%E6%AF%94/">Golang日志库对比</a>
</li>
<li>
<a href="/2020/10/22/hello-world/">Hello World</a>
</li>
</ul>
</div>
</div>
</aside>
</div>
<footer id="footer">
<div class="outer">
<div id="footer-info" class="inner">
© 2020 John Doe<br>
Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
</div>
</div>
</footer>
</div>
<nav id="mobile-nav">
<a href="/" class="mobile-nav-link">Home</a>
<a href="/archives" class="mobile-nav-link">Archives</a>
</nav>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<link rel="stylesheet" href="/fancybox/jquery.fancybox.css">
<script src="/fancybox/jquery.fancybox.pack.js"></script>
<script src="/js/script.js"></script>
</div>
</body>
</html>