Golang:将日志以Json格式输出到Kafka1

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Golang:将日志以Json格式输出到Kafka1

在上一篇文章中我实现了一个支持Debug、Info、Error等多个级别的日志库,并将日志写到了磁盘文件中,代码比较简单,适合练手。有兴趣的可以通过这个链接前往:github.com/bosima/ylog…

工程实践中,我们往往还需要对日志进行采集,将日志归集到一起,然后用于各种处理分析,比如生产环境上的错误分析、异常告警等等。在日志消息系统领域,Kafka久负盛名,这篇文章就以将日志发送到Kafka来实现日志的采集;同时考虑到日志分析时对结构化数据的需求,这篇文章还会提供一种输出Json格式日志的方法。

这个升级版的日志库还要保持向前兼容,即还能够使用普通文本格式,以及写日志到磁盘文件,这两个特性和要新增的两个功能分别属于同类处理,因此我这里对它们进行抽象,形成两个接口:格式化接口、写日志接口。

格式化接口

所谓格式化,就是日志的格式处理。这个日志库目前要支持两种格式:普通文本和Json。

为了在不同格式之上提供一个统一的抽象,ylog中定义 logEntry 来代表一条日志:


type logEntry struct {
  Ts    time.Time `json:"ts"`
  File  string    `json:"file"`
  Line  int       `json:"line"`
  Level LogLevel  `json:"level"`
  Msg   string    `json:"msg"`
}

格式化接口的能力就是将日志从logEntry格式转化为其它某种数据格式。ylog中对它的定义是:

type LoggerFormatter interface {
  Format(*logEntry, *[]byte) error
}

第1个参数是一个logEntry实例,也就是要被格式化的日志,第2个参数是日志格式化之后要写入的容器。

普通文本格式化器

其实现是这样的:

type textFormatter struct {
}
func NewTextFormatter() *textFormatter {
  return &textFormatter{}
}
func (f *textFormatter) Format(entry *logEntry, buf *[]byte) error {
  formatTime(buf, entry.Ts)
  *buf = append(*buf, ' ')
  file := toShort(entry.File)
  *buf = append(*buf, file...)
  *buf = append(*buf, ':')
  itoa(buf, entry.Line, -1)
  *buf = append(*buf, ' ')
  *buf = append(*buf, levelNames[entry.Level]...)
  *buf = append(*buf, ' ')
  *buf = append(*buf, entry.Msg...)
  return nil
}

可以看到它的主要功能就是将logEntry中的各个字段按照某种顺序平铺开来,中间用空格分隔。

其中的很多数据处理方法参考了Golang标准日志库中的数据格式化处理代码,有兴趣的可以去Github中详细查看。

这里对日期时间格式化为字符串做了特别的优化,在标准日志库中为了将年、月、日、时、分、秒、毫秒、微秒等格式化指定长度的字符串,使用了一个函数:

func itoa(buf *[]byte, i int, wid int) {
  // Assemble decimal in reverse order.
  var b [20]byte
  bp := len(b) - 1
  for i >= 10 || wid > 1 {
    wid--
    q := i / 10
    b[bp] = byte('0' + i - q*10)
    bp--
    i = q
  }
  // i < 10
  b[bp] = byte('0' + i)
  *buf = append(*buf, b[bp:]...)
}

其逻辑大概就是将数字中的每一位转换为字符并存入byte中,注意这里初始化byte数组的时候是20位,这是int64最大的数字位数。

其实时间字符串中的每个部分位数都是固定的,比如年是4位、月日时分秒都是2位,根本不需要20位,所以这个空间可以节省;还有这里用了循环,这对于CPU的分支预测可能有那么点影响,所以我这里分别对不同位数写了专门的格式化方法,以2位数为例:

func itoa2(buf *[]byte, i int) {
  q := i / 10
  s := byte('0' + i - q*10)
  f := byte('0' + q)
  *buf = append(*buf, f, s)
}

Json文本格式化器

其实现是这样的:

type jsonFormatter struct {
}
func NewJsonFormatter() *jsonFormatter {
  return &jsonFormatter{}
}
func (f *jsonFormatter) Format(entry *logEntry, buf *[]byte) (err error) {
  entry.File = toShortFile(entry.File)
  jsonBuf, err := json.Marshal(entry)
  *buf = append(*buf, jsonBuf...)
  return
}

代码也很简单,使用标准库的json序列化方法将logEntry实例转化为Json格式的数据。

对于Json格式,后续考虑支持用户自定义Json字段,这里暂时先简单处理。

写日志接口

写日志就是将日志输出到别的目标,比如ylog要支持的输出到磁盘文件、输出到Kafka等。

前边格式化接口将格式化后的数据封装到了 []byte 中,写日志接口就是将格式化处理的输出 []byte 写到某种输出目标中。参考Golang中各种Writer的定义,ylog中对它的定义是:

type LoggerWriter interface {
  Ensure(*logEntry) error
  Write([]byte) error
  Sync() error
  Close() error
}

这里有4个方法:

  • Ensure 确保输出目标已经准备好接收数据,比如打开要写入的文件、创建Kafka连接等等。
  • Write 向输出目标写数据。
  • Sync 要求输出目标将缓存持久化,比如写数据到磁盘时,操作系统会有缓存,通过这个方法要求缓存数据写入磁盘。
  • Close 写日志结束,关闭输出目标。


相关文章
|
24天前
|
运维 监控 Cloud Native
一行代码都不改,Golang 应用链路指标日志全知道
本文将通过阿里云开源的 Golang Agent,帮助用户实现“一行代码都不改”就能获取到应用产生的各种观测数据,同时提升运维团队和研发团队的幸福感。
|
5月前
|
消息中间件 存储 Kafka
Kafka日志处理:深入了解偏移量查找与切分文件
**摘要:** 本文介绍了如何在Kafka中查找偏移量为23的消息,涉及ConcurrentSkipListMap的查询、索引文件的二分查找及日志分段的物理位置搜索。还探讨了Kafka日志分段的切分策略,包括大小、时间、索引大小和偏移量达到特定阈值时的切分条件。理解这些对于优化Kafka的性能和管理日志至关重要。
211 2
|
2月前
|
存储 消息中间件 大数据
大数据-69 Kafka 高级特性 物理存储 实机查看分析 日志存储一篇详解
大数据-69 Kafka 高级特性 物理存储 实机查看分析 日志存储一篇详解
50 4
|
2月前
|
存储 消息中间件 大数据
大数据-70 Kafka 高级特性 物理存储 日志存储 日志清理: 日志删除与日志压缩
大数据-70 Kafka 高级特性 物理存储 日志存储 日志清理: 日志删除与日志压缩
52 1
|
2月前
|
存储 消息中间件 大数据
大数据-68 Kafka 高级特性 物理存储 日志存储概述
大数据-68 Kafka 高级特性 物理存储 日志存储概述
33 1
|
3月前
|
Prometheus Cloud Native Go
Golang语言之Prometheus的日志模块使用案例
这篇文章是关于如何在Golang语言项目中使用Prometheus的日志模块的案例,包括源代码编写、编译和测试步骤。
80 3
Golang语言之Prometheus的日志模块使用案例
|
3月前
|
消息中间件 Kafka API
python之kafka日志
python之kafka日志
39 3
|
3月前
|
消息中间件 存储 监控
Kafka的logs目录下的文件都是什么日志?
Kafka的logs目录下的文件都是什么日志?
218 11
|
3月前
|
JSON Go 数据格式
Golang语言结构体链式编程与JSON序列化
这篇文章是关于Go语言中结构体链式编程与JSON序列化的教程,详细介绍了JSON格式的基本概念、结构体的序列化与反序列化、结构体标签的使用以及如何实现链式编程。
47 4
|
4月前
|
消息中间件 监控 Kafka
Filebeat+Kafka+Logstash+Elasticsearch+Kibana 构建日志分析系统
【8月更文挑战第13天】Filebeat+Kafka+Logstash+Elasticsearch+Kibana 构建日志分析系统
244 3