Golang glog使用详解
golang/glog 是 C++ 版本 google/glog 的 Go 版本实现,基本实现了原生 glog 的日志格式。在 Kuberntes 中,glog 是默认日志库。
glog 的使用与特性
通用功能
glog 将日志级别分为 4 种,分别是:
- INFO:普通日志;
- WARNING:告警日志;
- ERROR:错误日志;
-
FATAL:严重错误日志,打印完日志后程序将会推出(
os.Exit()
)
glog 的使用很简单,可参考下面这个例子:
package main
import (
"flag"
"github.com/golang/glog"
)
func main() {
flag.Parse()
defer glog.Flush()
glog.Info("This is info message")
glog.Infof("This is info message: %v", 12345)
glog.InfoDepth(1, "This is info message", 12345)
glog.Warning("This is warning message")
glog.Warningf("This is warning message: %v", 12345)
glog.WarningDepth(1, "This is warning message", 12345)
glog.Error("This is error message")
glog.Errorf("This is error message: %v", 12345)
glog.ErrorDepth(1, "This is error message", 12345)
glog.Fatal("This is fatal message")
glog.Fatalf("This is fatal message: %v", 12345)
glog.FatalDepth(1, "This is fatal message", 12345)
}
当我们运行:
$ mkdir -p log && go run main.go -log_dir=log -alsologtostderr
以上打印日志将会同时打印在 log/
目录和标准错误输出中(-alsologtostderr
)。
其中在 log/
中将会产生如下日志文件:
main.INFO -> main.ut1.test.log.INFO.20180715-130428.27339
main.WARNING -> main.ut1.test.log.WARNING.20180715-130428.27339
main.ERROR -> main.ut1.test.log.ERROR.20180715-130428.27339
main.FATAL -> main.ut1.test.log.FATAL.20180715-130428.27339
main.ut1.test.log.ERROR.20180715-130428.27339
main.ut1.test.log.FATAL.20180715-130428.27339
main.ut1.test.log.INFO.20180715-130428.27339
main.ut1.test.log.WARNING.20180715-130428.27339
其中 main.INFO
这类文件表示的是 INFO
日志对应的符号链接。当单个日志文件达到一定大小时,glog 将会有 rotate 的动作:即关闭已经满量的文件,新建日志文件。
vmodule 功能
glog 最常用的就是 V level 的功能,如下所示:
func main() {
flag.Parse()
defer glog.Flush()
glog.V(3).Info("LEVEL 3 message") // 使用日志级别 3
glog.V(4).Info("LEVEL 4 message") // 使用日志级别 4
glog.V(5).Info("LEVEL 5 message") // 使用日志级别 5
glog.V(8).Info("LEVEL 8 message") // 使用日志级别 8
}
当我们重新运行:
$ go run main.go -log_dir=log -alsologtostderr
将不会看到任何输出,因为日志级别不够,我们通过指定日志级别(-v
,log level):
$ go run main.go -v=4 -log_dir=log -alsologtostderr
此时,日志级别小于或等于 4 的日志将被打印出来:
I0715 13:15:41.380611 29471 main.go:13] LEVEL 3 message
I0715 13:15:41.388777 29471 main.go:14] LEVEL 4 message
如果我们想对不同的文件实行不同的日志级别,可以用 vmodule 功能,如下代码:
func main() {
flag.Parse()
defer glog.Flush()
bar()
glog.V(3).Info("LEVEL 3 message")
glog.V(4).Info("LEVEL 4 message")
glog.V(5).Info("LEVEL 5 message")
glog.V(8).Info("LEVEL 8 message")
}
其中 bar()
的实现在 bar.go
:
func bar() {
glog.V(4).Info("LEVEL 4: level 4 message in bar.go")
}
当我们执行:
$ go run main.go bar.go -v=3 -log_dir=log -alsologtostderr -vmodule=bar=5
对所有文件的日志级别设定为 3 (-v=3
),但是对 bar.go
(-vmodule
的输入参数省去 .go
后缀,且必须以 -vmodule=recordio=2,file=1,gfs*=3
的语法格式)的日志级别设定为 5,此时会输出:
I0715 13:20:28.381611 30447 bar.go:6] LEVEL 4: level 4 message in bar.go
I0715 13:20:28.383866 30447 main.go:14] LEVEL 3 message
通过该功能,可以对指定模块采用不同日志级别的输出,可有效提升调试效率。
traceLocation 功能
traceLocation 的命令格式为 -log_backtrace_at=gopherflakes.go:234
,当运行到指定代码处时,将把该代码的栈信息打印出来,延续上面的代码,我们运行:
$ go run main.go bar.go -v=3 -log_dir=log -alsologtostderr -vmodule=bar=5 -log_backtrace_at=bar.go:6
可见如下输出:
I0715 13:28:17.915837 31920 bar.go:6] LEVEL 4: level 4 message in bar.go
... 打印 backtrace,此处省略 ...
I0715 13:28:17.923715 31920 main.go:14] LEVEL 3 message
日志格式
从上面的例子可以看出,glog 打印的日志基本格式为:
<header>] <message>
header 和 message 之间用 ]
分隔。其中 header 的格式为:
Lmmdd hh:mm:ss.uuuuuu threadid file:line
这里要注意的是 L
,它代表了 glog 原本的日志级别:
I -> INFO
W -> WARNING
E -> ERROR
F -> FATAL
后面几个字段分别代表的是时间信息。在 C++ 中,threadid
表示的是线程信息,但在 Go 版本实现中,threadid
是进程 PID,即 os.Getpid()
的调用结果。
这部分详细代码可参考:glog.go
中的 formatHeader()
函数。
glog 的实现
其实,用 Go 实现一个日志库并不困难,其本质就是:在 buffer 中写入格式化的内容并定期刷入文件中。glog 的基本实现逻辑也是如此。
参考
- rpc框架之avro 学习 1 - hello world
- 探讨Android中的内置浏览器和Chrome
- java并发编程学习: 阻塞队列 使用 及 实现原理
- CSS魔法堂:说说Float那个被埋没的志向
- Netbeans配置Xdebug
- rpc框架: thrift/avro/protobuf 之maven插件生成java类
- WebComponent魔法堂:深究Custom Element 之 从过去看现在
- 数据可视化-EChart2.0使用总结1
- JavaScript事件概览
- gradle项目与maven项目相互转化
- rpc框架之gRPC 学习 - hello world
- Angular Service入门
- spring:如何用代码动态向容器中添加或移除Bean ?
- WebComponent魔法堂:深究Custom Element 之 标准构建
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Thread和goroutine两种方式实现共享变量按序输出
- 浙大版《C语言程序设计(第3版)》题目集 练习2-13 求N分之一序列前N项和
- 浙大版《C语言程序设计(第3版)》题目集 练习2-14 求奇数分之一序列前N项和
- dotnet 双缓存数据结构设计 下载库的文件写入缓存框架
- 浙大版《C语言程序设计(第3版)》题目集 练习2-15 求简单交错序列前N项和
- 浙大版《C语言程序设计(第3版)》题目集 练习2-17 生成3的乘方表
- WPF 漂亮的现代化控件 新 ModernWPF 界面库
- 浙大版《C语言程序设计(第3版)》题目集 练习2-18 求组合数
- 浙大版《C语言程序设计(第3版)》题目集 习题2-1 求整数均值
- PHP 正则表达式 获取富文本中的 img标签的src属性
- 浙大版《C语言程序设计(第3版)》题目集 习题2-2 阶梯电价
- 浙大版《C语言程序设计(第3版)》题目集 习题2-3 求平方与倒数序列的部分和
- 浙大版《C语言程序设计(第3版)》题目集 习题2-4 求交错序列前N项和
- 二十五块DIY 带屏幕可远程的温湿度传感器
- 浙大版《C语言程序设计(第3版)》题目集 习题2-5 求平方根序列前N项和