前言

最近在尝试阅读字节开源RPC框架Kitex的源码,看到日志库klog部分,果不其然在Go原生的log库的基础上增加了自己的设计,大体包括增加了一些格式化的输出增加一些常用的日志级别等。

一番了解后,发现有不少开源的日志库也做了类似的事情,以补充原生log库的不足。因为Go原生的log库本身也比较简单,这篇文章先分析一下它的实现,为后续阅读Kitex的日志库klog做一下铺垫。

本次分析基于:GO SDK 1.18.1 /src/log/log.go的源码。

log库的使用

结果如下:

第三个日志因为第二个日志打印之后,调用panic()函数,且没有调用recover(),导致程序终止。如果注释掉第二行日志即可打印出第三个日志的结果如下:

log.xxx能直接打印日志的原因

通过观察源码,log包log.go文件中,提供了9个函数可以直接使用,3个一套,分别针对print型日志输出、panic型日志输出(可以recover)、fatal型日志输出(直接终止程序)。

并且这9个函数中频繁使用到了一个std实例,只要我们引入了log包std就会完成初始化,并且作为默认使用的log实例。

Logger结构

既然std是默认的Logger实例,这里先看一下Logger的结构:

  • mu:互斥锁,用于原子写入操作。
  • prefix:日志前缀/后缀。
  • flag:控制需要展示的日志内容。
  • out:描述输出。
  • buf:缓冲区。

关于flag的使用,Go定义了如下的常量:

iota是常量计数器,从0开始自增,可以配合表达式使用,且在一系列常量声明时,可以只指定第一个位置,后续会默认初始化,这里依次初始化为1、2、4...

  • Ldata:输出当地日期,如2009/01/23。
  • Ltime:输出当地时间,如01:23:23。
  • Lmicroseconds:时间精确到微妙,如01:23:23.123123,兼并Ltime。
  • Llongfile:输出文件名全路径 + 调用行号,如/a/b/c/d.go:23。
  • Lshortfile:输出最终文件的名称 + 调用行号,如d.go:23,覆盖Llongfile
  • LUTC:如果设置了LdataLtime,则将输出UTC时间,而不是本地时区。
  • Lmsgprefix:将prefix信息从当前日志行首部移动到message之前。
  • LstdFlagsstd实例的默认值,表示Ldata | Ltime = 3

官方的注释中给出了一些介绍flag用法的例子,这里介绍一个:

如果:std.flag == Ldate | Ltime | Lmicroseconds | Llongfile == 15

则日志行输出结果为:2009/01/23 01:23:23.123123 /a/b/c/d.go:23: messagemessage为具体的日志内容。

std.Output()

回到上面9个函数打印日志,都通过调用std.Output()实现日志的输出,是log库的核心函数,看一下代码:

  • 通过l.mu.Lock(),确保日志内容的写入是原子的。
  • 检查l.flag是否包括Lshortfile或者Llongfile标志位,如果有则需要获取文件名行数,且这一步先释放了锁,因为Caller方法的调用比较耗时(expensive),确保锁住的临界区尽可能小。
  • calldepth:0表示获取调用runtime.Caller(calldepth)的文件名和行数,1表示调用std.Output()的文件名和函数,2表示调用log.Println()的文件名和行数,3则已经用不到了,Go原生log库获取行信息用的都是2。

  • 清空缓冲区l.buf,并格式化日志头部信息(日期、文件名、行数),将其append入`buf。
  • 最后将具体的日志信息s添加入buf,会补全末尾换行符,并调用l.out.Write(),将日志写入事先注册的输出文件。

定制自己的Logger

log库默认使用的std实例是事先初始化好的,那么借助New方法,我们也可以定制自己的logger:

这里指定了日志输出到文件log.txt中,并且定义了一些flag,结果如下:

小结

通过分析,我们发现log是一个很简洁的日志库,它有三种日志输出方式printpanicfatal,且可以自己定制日志的输出格式。但是熟悉其他语言开发的同学可能会对日志级别有更多的需求,且log的格式化用起来比较复杂。

因此会衍生出很多基于log的二次封装的日志库,下一篇文章将讲解字节跳动RPC框架Kitex的日志库klog的实现。

GO的日志库log竟然这么简单!的更多相关文章

  1. 字节开源RPC框架Kitex的日志库klog源码解读

    前言 这篇文章将着重于分析字节跳动开源的RPC框架Kitex的日志库klog的源码,通过对比Go原生日志库log的实现,探究其作出的改进. 为了平滑学习曲线,我写下了这篇分析Go原生log库的文章,希 ...

  2. easylog -- Linux 下的简单日志库

    之前使用 log4c 或者 log4cpp 的时候, 总需要配置一些文件和链接库之类复杂的配置. 虽然越复杂越说明这个软件支持的功能多.可选择性强, 但是对于一个小的项目,或者要研究他人的代码而加点儿 ...

  3. C/C++log日志库比较

    事实上,在C的世界里面没有特别好的日志函数库(就像Java里面的的log4j,或者C++的log4cxx).C程序员都喜欢用自己的轮子.printf就是个挺好的轮子,但没办法通过配置改变日志的格式或者 ...

  4. SQLServer某个库log日志过大,无法收缩日志文件 ,因为该文件结尾的逻辑日志文件正在使用

    问题描述: 今天看到user库日志备份方面很久,然后查看到user库这个log日志很大 图片是我已经解决了,然后现在可以收缩的大小 解决方法: 1.先备份user库日志,因为很大,所以要等很久,这个只 ...

  5. C++ 日志库 boost::log 以及 glog 的对比

    日志能方便地诊断程序原因.统计程序运行数据,是大型软件系统必不可少的组件之一.本文将从设计上和功能上对比 C++ 语言常见的两款日志库: boost::log 和 google-glog . 设计 b ...

  6. 爆料喽!!!开源日志库Logger的剖析分析

    导读 Logger类提供了多种方法来处理日志活动.上一篇介绍了开源日志库Logger的使用,今天我主要来分析Logger实现的原理. 库的整体架构图 详细剖析 我们从使用的角度来对Logger库抽茧剥 ...

  7. 爆料喽!!!开源日志库Logger的使用秘籍

    日志对于开发来说是非常重要的,不管是调试数据查看.bug问题追踪定位.数据信息收集统计,日常工作运行维护等等,都大量的使用到.今天介绍著名开源日志库Logger的使用,库的地址:https://git ...

  8. GitHub开源库排名一百的简单介绍,值得收藏!

    GitHub Android Libraries Top 100 简介 本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据 GitHub ...

  9. 开源日志库log4cplus+VS2008使用

    一.简介     log4cplus是C++编写的开源的日志系统,功能非常全面.本文介绍如何在Windows+VS2008中使用该日志库.   二.下载     可从网站[url]http://log ...

随机推荐

  1. 【uniapp 开发】智能温控开关 (环状图)

    index.vue <template> <view> <view class="qiun-columns"> <uCharts id=& ...

  2. PAT B1091 N-自守数

    输入样例: 3 92 5 233   输出样例: 3 25392 1 25 No '解题思路:判断的时候将结果转换成字符串,判断后面几位数字和输入数字是否相同,掉进了N是从1到10的坑,而不是1到9 ...

  3. IDEA中 Debug 调试工具(图文详解)

    DEBUG调试工具 一. Debug 调试工具 1. Debug的作用 2. Debug的使用步骤 3. IDEA中Debug按钮详解 总结 参考博文:https://blog.csdn.net/qq ...

  4. java语言和jdk、jre基础

    Java语言平台 * J2SE(Java 2 Platform Standard Edition)标准版  * 是为开发普通桌面和商务应用程序提供的解决方案,该技术体系是其他两者的基础,可以完成一些桌 ...

  5. 解决关于ARM_MATH数学库宏定义的报错

    昨天在建立新工程的时候发现加入含有ARM_MATH库的时候出现了宏定义报错. #error directive:"Define according the used Cortex core ...

  6. 如何利用PowerShell完成的Windows服务器系统安全加固实践和基线检测

    0x00 前言简述 最近单位在做等保测评,由本人从事安全运维方面的工作(PS:曾经做过等保等方面的安全服务),所以自然而然的与信安的测评人员一起对接相关业务系统的检查,在做主机系统测评检查时发现了系统 ...

  7. Java学习day34

    注解(Annotation):是从JDK5.0开始引入的新技术: 作用:不是程序本身,可以对程序作出解释:可以被其他程序(比如编译器等)读取 格式:注解是以"@注释名"在代码中存在 ...

  8. SSL及GMVPN握手协议详解

    之前写过一篇文章搞懂密码学基础及SSL/TLS协议,主要介绍了加密学的基础,并从整体上对SSL协议做了介绍.由于篇幅原因,SSL握手的详细流程没有深入介绍.本文将拆解握手流程,在消息级别对握手进行详细 ...

  9. js 修改页面样式的两种方式

    1.  element.style       行内样式操作 代码示例 : <!DOCTYPE html> <html lang="en"> <hea ...

  10. python基础练习题(暂停一秒输出,并格式化当前时间)

    day5 --------------------------------------------------------------- 实例010:给人看的时间 题目 暂停一秒输出,并格式化当前时间 ...