Go 日志封装实战示例详解

目录
  • 背景
  • Logger 封装的理解
  • 简单包封装
  • 多日志库切换
  • 使用中间件记录公共信息

背景

日志是框架中至关重要的一部分。在 Golang 只也提供了基本的日志组件,但其没有提供给比较多的功能。当然现在也有很多第三方已经封装好的库使用起来也很方便。作为成熟的开发者也应该学会封装自己的类库,以便后续在自己的个人项目中使用它。

Logger 封装的理解

Logger 库主要是一系列方法或接口,提供给应用程序代码调用然后将相关的数据记录到日志记录库中。就是在代码和底层日志库中间的一层。需要实现的功能是能够记录日志,且支持不同日志记录库的切换或添加新的记录库。

封装包,首先需要先定义一些能够描述日志方法的接口,基本的都是你的应用程序所需要的方法。比如,基本的日志接口基本的方法有 Info、Warn、 Error。然后就可以创建此接口的实现,将数据记录到记录库中。定义了接口和实现,就可以创建一个 logger 封装,并将相关的接口方法公开。

简单包封装

以下定义了五个方法:Info, Warn, Error 和 Fatal. 这些方法接口接收 2个参数,一个字符串和一个字段映射map.

type Logger interface {
	Debug(msg string, field map[string]interface{})
	Info(msg string, field map[string]interface{})
	Warn(msg string, field map[string]interface{})
	Error(msg string, field map[string]interface{})
	Fatal(msg string, field map[string]interface{})
}

接下来就是实现啦 Logger 方法,底层的实现主要是依赖使用 Logrus。首先需要创建一个 LLogger 结构体,该结构体包含 Logrus 实例。当然还需要一个 NewLLogger 方法来实例化一个 LLogger。

type LLogger struct {
	logger *logrus.Logger
	ctx    context.Context
}
func NewLLogger(ctx context.Context) *LLogger {
	logger := logrus.New()
	logger.Out = os.Stdout
	return &LLogger{logger: logger, ctx: ctx}
}
func (l *LLogger) Info(msg string, fields map[string]interface{}) {
	l.logger.WithFields(fields).Info(msg)
}
func (l *LLogger) Warn(msg string, fields map[string]interface{}) {
	l.logger.WithFields(fields).Warn(msg)
}
func (l *LLogger) Error(msg string, fields map[string]interface{}) {
	l.logger.WithFields(fields).Error(msg)
}
func (l *LLogger) Fatal(msg string, fields map[string]interface{}) {
	l.logger.WithFields(fields).Fatal(msg)
}

这样一个简单日志封装就完成了,使用时就可以直接使用。

func main() {
	ctx := ... // context 信息
	lg := NewLLogger(ctx)
	fields := map[string]interface{}{
		"userId":    "xiaoxiong",
		"ipAddress": "127.0.0.1",
	}
	lg.Info("这是测试信息", fields)
}

多日志库切换

当底层需要使用的是不同的日志库进行记录日志时,那就需要封装另外的日志,但是在实例化方法时可以增加一种日志类型参数,然后根据不同的类型实例化不同的日志。

比如使用了zap 包,那童养媳与奥实现接口的四个方法 :Info, Warn, Error and Fatal.

type ZapLog struct {
	logger *zap.Logger
	ctx    context.Context
}
func NewZapLog(ctx context.Context) *ZapLog {
	logger, _ := zap.NewProduction()
	return &ZapLog{logger: logger, ctx: ctx}
}
func (l *ZapLog) Info(msg string, fields map[string]interface{}) {
	l.logger.Info(msg, zap.Any("args", fields))
}
func (l *ZapLog) Warn(msg string, fields map[string]interface{}) {
	l.logger.Warn(msg, zap.Any("args", fields))
}
func (l *ZapLog) Error(msg string, fields map[string]interface{}) {
	l.logger.Error(msg, zap.Any("args", fields))
}
func (l *ZapLog) Fatal(msg string, fields map[string]interface{}) {
	l.logger.Fatal(msg, zap.Any("args", fields))
}

定义其他日志库的方法后就只需对这个两个日志库进行封装,根据不同的类型初始化出不同的日志,然后使用日志时候就使用相应的包进行处理。

type LoggerWrapper struct {
	logger Logger
}
func NewLoggerWrapper(loggerType string, ctx context.Context) *LoggerWrapper {
	var logger Logger
	switch loggerType {
	case "logrus":
		logger = NewLLogger(ctx)
	case "zap":
		logger = NewZapLog(ctx)
	default:
		logger = NewLLogger(ctx)
	}
	return &LoggerWrapper{logger: logger}
}

使用中间件记录公共信息

封装中增加了 Context 上下文的内容,主要是为了记录一些公共属性。就像经常在链路追踪时可需要请求ID ,请求IP 等相关的信息。但是日志实例都是在程序启动时进行初始化的,在每次的请求时可能请求ID或者IP 都是不一样,所以要记录这部分信息,可以使用中间件将上下文的信息添加到日志消息中。

以上就是Go 日志封装实战示例详解的详细内容,更多关于Go 日志封装的资料请关注我们其它相关文章!

(0)

相关推荐

  • uber go zap 日志框架支持异步日志输出

    目录 事件背景 心智负担 前置知识 解决思路 uber-go/zap 代码分析 上手开发 测试代码 同步输出日志 异步输出日志 不输出日志 总结 事件背景 过年在家正好闲得没有太多事情,想起年前一个研发项目负责人反馈的问题:“老李啊,我们组一直在使用你这边的 gin 封装的 webservice 框架开发,我们需要一套标准的异步日志输出模块.现在组内和其他使用 gin 的小伙伴实现的‘各有千秋’不统一,没有一个组或者部门对这部分的代码负责和长期维护.你能不能想想办法.” 这一看就是掉头发的事情,

  • Go语言LeetCode题解937重新排列日志文件

    目录 一 题目描述 二 分析 三 答案 一 题目描述 937. 重新排列日志文件 - 力扣(LeetCode) (leetcode-cn.com) 给你一个日志数组 logs.每条日志都是以空格分隔的字串,其第一个字为字母与数字混合的 标识符 . 有两种不同类型的日志: 字母日志:除标识符之外,所有字均由小写字母组成 数字日志:除标识符之外,所有字均由数字组成 请按下述规则将日志重新排序: 所有 字母日志 都排在 数字日志 之前. 字母日志 在内容不同时,忽略标识符后,按内容字母顺序排序:在内容

  • mongodb driver使用代码详解

    MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的. 0 前言 全是干货的技术殿堂 文章收录在我的 GitHub 仓库,欢迎Star/fork: Java-Interview-Tutorial https://github.com/Wasabi1234/Java-Interview-Tutorial mongo

  • go zero微服务框架logx日志组件剖析

    目录 addTenant api 和 rpc 的实现 logx 日志组件剖析 Go-zero 中 logx 是如何使用的? Logx 基本的数据结构 Logx 的默认接口实现 Logx 自定义存储日志位置 和 实现自定义接口的方式 自定义存储日志位置 实现自定义接口 addTenant api 和 rpc 的实现 上一篇我们说到咱们还剩下 addTenant 功能还未实现,不知道有没有兄弟感兴趣去实验一波的,本篇文章进行简要补充 根据上一篇文章分析,其实我们只需要执行如下几步即可: 编写 ten

  • go单体日志采集zincsearch方案实现

    目录 前言 一 构架 二 zinsearch 安装 二 logbeat 三 zincsearch 使用经验 1 关于删除 2 关于日期date类型 3 关于检索中时间选项 结语 前言 微服务中的日志采集方案ELK(EFK)已经是基本事实标准了,但是单体服务中却没有像ELK这样的成熟采集方案,这与单体性质有关,单体毕竟涉及到服务少,而ELK又是很耗费资源的,单体要是上ELK,可能需要的服务器资源比业务服务器还多,所以单体没有上ELK的. 但是单体也有日志采集需要,毕竟出了问题都要查日志的,如果没有

  • Redhat持久化日志实战示例详解

    目录 持久化日志 实战练习:收集信息 持久化日志 默认情况下,Red Hat Enterprise Linux 7将系统日志存储在/run/log/journal中,该日志存储在tmpfs(临时文件系统)上.这意味着在重新启动时,所有存储的信息都将丢失.如果目录/var/log/journal存在,日志将存储在那里,从而在重新引导后启用持久日志. 可以通过使用以下步骤来启用持久性日志: mkdir/var/log/journal chown root:systemd-journal /var/l

  • golang gorm更新日志执行SQL示例详解

    目录 1. 更新日志 1.1. v1.0 1.1.1. 破坏性变更 gorm执行sql 1. 更新日志 1.1. v1.0 1.1.1. 破坏性变更 gorm.Open返回类型为*gorm.DB而不是gorm.DB 更新只会更新更改的字段 大多数应用程序不会受到影响,只有当您更改回调中的更新值(如BeforeSave,BeforeUpdate)时,应该使用scope.SetColumn,例如: func (user *User) BeforeUpdate(scope *gorm.Scope) {

  • Vue3中Vuex状态管理学习实战示例详解

    目录 引言 一.目录结构 二.版本依赖 三.配置Vuex 四.使用Vuex 引言 Vuex 是 Vue 全家桶重要组成之一,专为 Vue.js 应用程序开发的 状态管理模式 + 库 ,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 一.目录结构 demo/ package.json vite.config.js index.html public/ src/ api/ assets/ common/ components/ store/ index.

  • JavaScript函数封装的示例详解

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,

  • Composition API思想封装NProgress示例详解

    目录 正文 安装和基本使用 自己实现一个 正文 最近在用vue3封装一套后台管理模版,自然会用到NProgress.如果你没有用过,你可以看一下instagram,youtube这些网站,它们都有一个顶部加载条,这也是现在最流行的网页加载条. 于是我发现了@vueuse/integrations中的useNProgress,我们先看一下Anthony Fu大神如何去封装的,然后咱们再去试着自己实现一下. 安装和基本使用 npm i nprogress @vueuse/integrations 基

  • Awaitility同步异步工具实战示例详解

    目录 引言 1. awaitility入门 1.1 静态导入 1.2 简单例子 2. awaitility在RocketMQ中的实战 3. 总结 引言 在编写测试用例的时候遇到有异步或者队列处理的时候经常会用到 Thread.sleep() 等待来进行测试.例如:DLedger 测试选举的过程.当DLedger Leader下线.此时DLedger会重新发起选举,这个选举的过程是需要一定时间.很多时候在测试代码中就会使用 Thread.sleep . 由于选举需要的时间多少不确定所以sleep时

  • vue实现前端展示后端实时日志带颜色示例详解

    目录 vue实现前端展示后端带颜色的日志 需求 操作 采用innerHTML例子 需求: 解决 效果 vue实现前端展示后端带颜色的日志 需求 通过loki获取项目产生的日志,并且在前端显示出来,一开始在没有经过处理的数据会显示一些乱码,并没有将字符转换 经过一番查询后,发现可以使用ansi_up来对日志进行操作颜色代码进行转化. 操作 ansi_up 能够装换颜色代码 GitHub地址 https://github.com/drudru/ansi_up 安装 npm install ansi_

  • Gin与Mysql实现简单Restful风格API实战示例详解

    目录 It works main.go 编译运行 数据库 CURD 增删改查 增 查 查询列表 Query 查询单条记录 QueryRow 改 删 组织代码 封装模型方法 Handler函数 组织项目 数据库处理 数据model封装 handler 路由 分组路由 app入口 总结 我们已经了解了Golang的Gin框架.对于Webservice服务,restful风格几乎一统天下.Gin也天然的支持restful.下面就使用gin写一个简单的服务,麻雀虽小,五脏俱全.我们先以一个单文件开始,然

  • iOS中捕获日志与异常示例详解

    前言 在平时自己调试的时候,可以直接连接电脑,直接在窗口中查看结果.但是在测试人员测试,或者灰度测试的时候,怎么才能拿到日志呢?最先想到的肯定是输出到本地文件,然后在需要的时候进行上传. 分享一段之前找到的方法,下面的代码提供了两个主要功能: – 把日志输出到文件中 – 捕捉异常信息 [解析都写在注释中了] 示例代码 - (void)redirectNSLogToDocumentFolder { //如果已经连接Xcode调试则不输出到文件 //该函数用于检测输出 (STDOUT_FILENO)

  • Spring Boot中slf4j日志依赖关系示例详解

    前言 SpringBoot底层使用的是slf4j+logback来进行日志记录 把其他common-logging.log4j.java.util.logging转换为slf4j 下面这篇文章主要给大家介绍了关于Spring Boot slf4j日志依赖关系的相关内容,下面话不多说了,来一起看看详细的介绍吧 底层依赖关系 关系如何转化 底层通过偷梁换柱的方法,用jcl.jul.log4j中间转换包进行转化 如果要引入其他框架,必须将其中默认日志依赖剔除 SpringBoot从maven依赖中剔除

随机推荐