log4go 的 4.0.2 版本(https://github.com/ccpaging/log4go/tree/4.0.2)发布以后,

看了看别的 go 语言日志文件设计。发现了一篇好文:

log4go 和 logrus 的对比与分析

https://www.doraemonext.com/archives/783.html

顺藤摸瓜,找了一窝关于日志的设计。链接如下(含老的链接):

  1. https://github.com/alecthomas/log4go/

    这是log4go项目的“鼻祖”
  2. https://github.com/ngmoco/timber

    实现了结构化,写文件缓冲,热配置等。把log4go重构的面目全非
  3. https://github.com/siddontang/go/tree/master/log
  4. https://github.com/sirupsen/logrus
  5. https://github.com/YoungPioneers/blog4go
  6. https://github.com/YoungPioneers/blog4go-benchmark 各种 go log 的benchmark对比
  7. https://github.com/cihub/seelog

异步写入日志

log4go 的特点之一是异步写入。格式化日志记录、写入文件、转储日志等,都会消耗 CPU 的时间,并可能因为错误处理而阻塞主线程。

但日志系统仅仅是一个辅助功能,所以,保证主线程的高效运行是首先要达到的设计要求。异步写入是可行的方案之一。

自扩展日志接口

其实,log4go 是支持类似 logrus 的扩展特性的。

正好纠结于 color text term log 的设计如何处理的问题……因为这个功能使用了第三方包。放在log4go里增加了它的依赖性。但这确实又是我特别特别喜欢的一个功能。

不如把 color text term log 做成扩展日志接口。说干就干……

先搞清楚 log4go 中可用的扩展接口:

type LogWriter interface {
LogWrite(rec *LogRecord) // This should clean up anything lingering about the LogWriter, as it is called before
// the LogWriter is removed. LogWrite should not be called after Close.
Close()
} type Filter struct {
Level Level
rec chan *LogRecord // write queue
closed bool // true if Socket was closed at API level
LogWriter
} type Logger map[string]*Filter func (log Logger) AddFilter(name string, lvl Level, writer LogWriter) Logger {
log[name] = NewFilter(lvl, writer)
return log
}

扩展程序只要做:

  1. NewXXXLogWrite,初始化扩展要使用的资源。
  2. LogWrite(rec *LogRecord),输出日志记录
  3. Close()中关闭或释放资源
  4. 在应用程序中调用 AddFilter 把新的日志扩展加入到log4go日志结构中

大功告成了。

其中,Add filter name 是 Logger map 的索引关键字,log4go 使用了:

"stdout", "file", "syslog"

如果新加的 Filter 的关键字已存在,log4go(4.0.2以后的版本)将自动关闭原来的,再增加新的。代码如下:

func (log Logger) AddFilter(name string, lvl Level, writer LogWriter) Logger {
if filt, isExist := log[name]; isExist {
filt.Close()
delete(log, name)
}
log[name] = NewFilter(lvl, writer)
return log
}

借助扩展接口,log4go的日志记录可以采用任何你希望的封装格式,例如 xml 和 json,这是已经实现的。

以后还可以扩展csv(使日志文件导入到Excel中)或者json封装的message。

可扩展的日志接口包括:

  • Send error messages as a mail

  • Make TCP/UDP server and let client pull the messages

  • websocket

  • nanomsg pub/sub

  • Store log messages in MySQL

自扩展日志配置接口

log4go 4.0.2 支持 xml 和 json 配置。日志文件的配置有三种方式:

  1. 在应用程序中配置
  2. 单独的配置文件
  3. 存于主程序配置文件中

日志系统作为一个辅助功能,常常面临的是第三种情况。而配置文件的格式多种多样。例如:

windows ini, linux config, json, xml ...

郁闷。log4go 不应当去支持所有的配置文件格式,而是提供接口,让用户可以根据自己的主程序的设计需要,自行扩展。

也许应该把 xml 和 json 配置文件支持都以扩展配置文件接口的方式实现,而不是跟 log4go 的主程序捆绑在一起。

文件日志的写缓冲

已经测试了两层缓冲写文件。

第一层是格式化日志记录,一个单独的go routine,另一个写文件,边格式化记录边写文件,消耗降低了40%。

第二层是用bufio。达到一定的缓冲数量如4k、8k,一次写文件。消耗降低了80%。

通过判断Channel中的记录长度来决定系统何时空闲。当长度为0时,后续没有新的日志记录,做一次Flush()。

这种方案简单。

另外加上 rotate 的优化,效率提高了5倍。

BenchmarkFileLog-4                        200000             10675 ns/op
BenchmarkFileNotLogged-4 20000000 106 ns/op
BenchmarkFileUtilLog-4 200000 10660 ns/op
BenchmarkFileUtilNotLog-4 5000000 239 ns/op
BenchmarkCacheFileLog-4 1000000 2191 ns/op
BenchmarkCacheFileNotLogged-4 20000000 106 ns/op
BenchmarkCacheFileUtilLog-4 500000 3680 ns/op
BenchmarkCacheFileUtilNotLog-4 5000000 240 ns/op

Rotate 的改进设想

log4go 自带 rotate。

linux 系统本来是有 logrotate 的,用 cron 定时执行。非常棒的设计。

简单说,就是写日志文件归写日志文件,不要去做任何转储的判断。程序员可根据系统的实际运行情况,

自行设置转储的时间间隔。转储时:

  • 加锁。使 log4go 暂时停止写日志,这可能是在 linux 系统中 log4go 没有使用 logrotate 的原因之一。

  • 当前日志文件进行处理。

  • 解锁。尽快恢复 log4go,继续写日志到当前日志文件。

  • 另开 go routine 对历史日志文件进行处理。


好吧。暂时就想到这么多了。很多有趣的工作正在进行……

再次感谢 doraemonext@gmail.com 童鞋的好文:log4go 和 logrus 的对比与分析

请关注:

https://github.com/ccpaging/log4go

log4go的一些改进设想的更多相关文章

  1. log4go的日志滚动处理——适应生产环境的需要

    日志处理有三类使用环境,开发环境DE,测试环境TE,生产环境PE. 前两类可以看成是一类,重要的是屏幕显示--termlog.生产环境中主要用的是socklog 和 filelog,即网络传输日志和文 ...

  2. log4go的日志滚动处理——生产环境的适配

    日志处理有三类使用环境,开发环境DE,测试环境TE,生产环境PE. 前两类可以看成是一类,重要的是屏幕显示--termlog.生产环境中主要用的是socklog 和 filelog,即网络传输日志和文 ...

  3. 改进log4go的一些设想

    log4go 的 4.0.2 版本(https://github.com/ccpaging/log4go/tree/4.0.2)发布以后, 看了看别的 go 语言日志文件设计.发现了一篇好文: log ...

  4. unity 人工智能AI,装备解锁临时笔记

    A*算法的一种改进设想:1.如何让角色到达目标点的过程中更加平滑:获取一串到达目标点的网格串之后,就实时用带形状的物理射线检测能否直接到达下一个目标点的再下一个目标点,如果能到达,那么直接朝该方向运动 ...

  5. Windows Server 2003 下实现网络负载均衡(2) (转)

    四.测试 在第一台机器上,关闭网络负载平衡管理器后,用鼠标右键单击“网络负载平衡群集”,从出现的菜单中选择“连接到现存的”,将会弹出“连接”界面.输入第一台计算机的名称或IP地址,点击“连接”按钮,在 ...

  6. 计算机二级考试Access教程

    本教程对编程语言各种要点进行详细的讲解介绍,从基础知识到实用技术功能,内容涵盖了从数组,类等基本概念到多态.模板等高级概念.教程本着实用的原则,每一小节都结合了可以笔试.面试的常见程序实例,以便从第一 ...

  7. homework_06 围棋程序改进

    1) 把程序编译通过, 跑起来. 读懂程序,在你觉得比较难懂的地方加上一些注释,这样大家就能比较容易地了解这些程序在干什么. 把正确的 playPrev(GoMove) 的方法给实现了. 注释见Git ...

  8. 企业级应用架构(三)三层架构之数据访问层的改进以及测试DOM的发布

    在上一篇我们在宏观概要上对DAL层进行了封装与抽象.我们的目的主要有两个:第一,解除BLL层对DAL层的依赖,这一点我们通过定义接口做到了:第二,使我们的DAL层能够支持一切数据访问技术,如Ado.n ...

  9. 数据访问层的改进以及测试DOM的发布

    数据访问层的改进以及测试DOM的发布 在上一篇我们在宏观概要上对DAL层进行了封装与抽象.我们的目的主要有两个:第一,解除BLL层对DAL层的依赖,这一点我们通过定义接口做到了:第二,使我们的DAL层 ...

随机推荐

  1. PHP验证身份信息

    $code = 'code'; $patt = "/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(10|11|12))([012](\d|(30|31)))\d{3}[ ...

  2. Web Worker 案例

    什么是 Web Worker? 当在 HTML 页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成. web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性 ...

  3. 【Python】小括号过滤后的盲注

    0x00   环境搭建 sqli-labs第八关,简单修改下源代码,加入下面一行代码 $id=preg_replace('/\(|\)/', "",$id); //过滤小括号 0x ...

  4. postgreSQL 常用命令 二

    本次测试基与PostgreSQL 10.x版本 创建用户 [postgres@rtm2 data]$ /opt/pgsql-10/bin/createuser rentaomin [postgres@ ...

  5. http请求报文和响应报文(2)

    接上篇: 3.回应报文 理解回应报文,首先要弄清回应报文中的状态码. 相比于请求报文,对于响应报文,个人觉得还蛮有趣的. 主要由三部分组成:协议版本.状态码.状态码描述 3.1状态码 **常见的状态码 ...

  6. windows下dubbo-admin的安装

    本来以为十分钟就能搞定的东西结果搞了一个小时,也是菜到抠脚,赶紧记录一下. 下载dubbo源码,下载地址:https://download.csdn.net/download/huangzhang_/ ...

  7. MySQL搭建Amoeba_读写分离

    一.背景知识 Amoeba(变形虫)项目,专注 分布式数据库 proxy 开发.座落与Client.DB Server(s)之间.对客户端透明.具有负载均衡.高可用性.sql过滤.读写分离.可路由相关 ...

  8. AtCoder Grand Contest 023 C - Painting Machines

    Description 一个长度为 \(n\) 的序列,初始都为 \(0\),你需要求出一个长度为 \(n-1\) 的排列 \(P\), 按照 \(1\) 到 \(n\) 的顺序,每次把 \(P_i\ ...

  9. rabbitmq 命令&& rabbitmq教程(一)

    先来个官方教程 http://www.rabbitmq.com 在windows 下 命名 去掉sudo 我是在windows下测试 用net调用 常用命令 控制台命令:sudo rabbitmqct ...

  10. javascript: iframe switchSysBar 左欄打開關閉,兼容各瀏覽器操作

    <html> <head> <meta content="text/html; charset=utf-8" http-equiv="Con ...