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

news2024/9/28 13:28:49

addTenant api 和 rpc 的实现

上一篇我们说到咱们还剩下 addTenant 功能还未实现,不知道有没有兄弟感兴趣去实验一波的,本篇文章进行简要补充

根据上一篇文章分析,其实我们只需要执行如下几步即可:

  1. 编写 tenant.api,提供外部 addTenant 的 http 接口
  • 编写 tenant.api

提供一个 POST http 的接口 / api /tenant/addtenant

type (
        AddTenantReq {
                Name string `json:"name"`
                Addr string `json:"addr"`
        }
        AddTenantRsp {
                Id string `json:"id"`
        }
)
service tenant {
        @handler addTenant
        post /api/tenant/addtenant(AddTenantReq) returns (AddTenantRsp)
  • goctl 生成 api 代码
goctl api go -api tenant.api  -dir .
  1. 修改 api 的配置和逻辑层,让 api 层去调用之前写好的 rpc 接口 即可

对于配置可以模仿上一篇文章 order.api 的配置进行修改,另外只需要调整 addTenant 的 logic 层即可

func (l *AddTenantLogic) AddTenant(req *types.AddTenantReq) (*types.AddTenantRsp, error) {
   // todo: add your logic here and delete this line
   rsp,err :=l.svcCtx.TenantRpc.AddTenant(l.ctx, &tenant.AddTenantReq{
      Name: req.Name,
      Addr: req.Addr,
   })
   if err !=nil{
      return nil,err
   }
   return &types.AddTenantRsp{Id: rsp.Id},nil
}

具体的代码案例可以访问地址:https://github.com/qingconglaixueit/my_test_Demo

下面我们来看是 go-zero 中 日志组件 logx 的剖析

logx 日志组件剖析

对于 logx 日志组件,分别从如下几个方面来聊一聊我的理解,如果描述有不当的地方,还请多加评论多加交流

  • Go-zero 中 logx 是如何使用的?
  • Logx 基本的数据结构
  • Logx 的默认接口实现
  • Logx 日志存储位置,以及自定义存储日志位置的实现
  • Logx 实现自定义接口的方式

Go-zero 中 logx 是如何使用的?

我们以之前的 demo ,关于 tenant 的 rpc 部分作为例子,追踪一下代码,是如何走到日志部分的逻辑的

可以看到在 tenant.go 的文件中,做的是服务的启动

zrpc.MustNewServer 实际上是调用 go-zero 的 zrpc 包 的 NewServer 函数,传入的参数是

  • c RpcServerConf , 我们 rpc 服务的配置,就是咱们项目中的 etc/tenant.yaml

今天不聊关于 RpcServerConf 的结构,咱们重点说说 logx

  • register internal.RegisterFn 注册服务的回调函数

NewServer 函数做了如下几件事情:

  • RpcServerConf 配置数据的有效性检查
  • 初始化 metrics 的 options
  • 设置服务名,注册 etcd 服务,服务名就是上述配置文件中的 Name 字段
  • c.SetUp() 启动整个服务

对于 logx 日志组件的启动就是在 c.SetUp() 中完成

Logx 基本的数据结构

继续看到 logx.SetUp() 中的具体实现 , 函数需要传入的数据结构是这样的 LogConf

type LogConf struct {
   ServiceName         string `json:",optional"`
   Mode                string `json:",default=console,options=[console,file,volume]"`
   Encoding            string `json:",default=json,options=[json,plain]"`
   TimeFormat          string `json:",optional"`
   Path                string `json:",default=logs"`
   Level               string `json:",default=info,options=[info,error,severe]"`
   Compress            bool   `json:",optional"`
   KeepDays            int    `json:",optional"`
   StackCooldownMillis int    `json:",default=100"`
}
  • ServiceName:设置服务名称,可选。在 volume 模式下,该名称用于生成日志文件。在 rest/zrpc 服务中,名称将被自动设置为 restzrpc 的名称。
  • Mode:输出日志的模式,默认是 console

    • console 模式将日志写到 stdout/stderr
    • file 模式将日志写到 Path 指定目录的文件中
    • volume 模式在 docker 中使用,将日志写入挂载的卷中
  • Encoding: 指示如何对日志进行编码,默认是 json

    • json模式以 json 格式写日志
    • plain模式用纯文本写日志,并带有终端颜色显示
  • TimeFormat:自定义时间格式,可选。默认是 2006-01-02T15:04:05.000Z07:00
  • Path:设置日志路径,默认为 logs
  • Level: 用于过滤日志的日志级别。默认为 info

    • info,所有日志都被写入
    • error, info 的日志被丢弃
    • severe, infoerror 日志被丢弃,只有 severe 日志被写入
  • Compress: 是否压缩日志文件,只在 file 模式下工作
  • KeepDays:日志文件被保留多少天,在给定的天数之后,过期的文件将被自动删除。对 console 模式没有影响
  • StackCooldownMillis:多少毫秒后再次写入堆栈跟踪。用来避免堆栈跟踪日志过多

另外对于 SetUp 函数做了如下几件事:

  • 设定日志等级
  • 初始化时间格式
  • 根据编码方式初始化存储日志编码类型
  • 根据设定的模式来初始化 Writer 句柄

Logx 的默认接口实现

对于 logx 打印日志的具体接口定义在:logx 包的 logger.go 文件中

对于上述接口,根据需要传递的参数我们可以分为如下几类:

  • Error, Info, Slow: 将任何类型的信息写进日志,使用 fmt.Sprint(...) 来转换为 string
  • Errorf, Infof, Slowf: 将指定格式的信息写入日志
  • Errorv, Infov, Slowv: 将任何类型的信息写入日志,用 json marshal 编码
  • Errorw, Infow, Sloww: 写日志,并带上给定的 key:value 字段
  • WithContext:将给定的 ctx 注入日志信息,例如用于记录 trace-idspan-id
  • WithDuration: 将指定的时间写入日志信息中,字段名为 duration

例如接口名后缀带有 w 的,是需要咱们传入 key:value 的,例如传入的结构是这样的:

实际上我们可以看到在 logx 源码中,其实有很多文件都已经根据自己的使用情况去实现了上述 Logger 接口

举一个 traceLogger 的例子

实际上我们可以直接看到,我们之前实现的 GetTenant rpc 方法

我们可以看到当调用了NewGetTenantLogic 方法之后,实际上是会调用 logx.WithContext(ctx) 初始化一个 traceLogger 的句柄

traceLogger 实现了上述 Logger 接口, 因此,当我们需要在 rpc 中打印日志的时候,我们可以这样来使用

这个时候,实际上是调用的 traceLogger 对应的实现代码

我们可以看到,打印出来的日志,是我们所期望的信息

此处的字段对应含义是这样的:

  • Timestamp

时间戳

  • Level

日志等级

  • Duration

时间间隔

  • Caller

日志调用者

  • Content

具体的日志信息

仔细查看上述日志,我们可以发现还有 trace 和 span 字段也打印出来了,但是 logEntry 为什么没有定义呢

咱们稍微追一下代码,不难看出,是 traceLogger 内部的 info 函数进行日志信息的拼接

Logx 自定义存储日志位置 和 实现自定义接口的方式

Logx 自定义存储日志位置 和 实现自定义接口的方式其实我在这里就不需要过多的解释了,简单说明一下实现手段就可以了,有必要的话咱们可以查看 go-zero 官方文档 https://go-zero.dev/cn/docs/component/logx/

自定义存储日志位置

对于咱们需要修改日志的输出位置,实际上我们可以仔细思考一下,对于日志的数据,go-zero 还是使用的 golang io 包中的 Writer 接口

咱们只需要定义对象,去实现 Writer 接口 中的 Write(p []byte) (n int, err error) 方法就可以了

官网也给了我们例子,例如咱们实现输出的日志往 kafka 里面吐,我们就可以这样

实现自定义接口

实现自定义接口,咱们其实刚才看 traceLogger 的实现方式,我们就能领悟到, traceLogger 去实现 Logger 接口中的方法,并且加入自己自定义的逻辑,例如加上了 trace 和 span

那么对于我们自定义接口,其实也是非常容易的,照葫芦画瓢即可了

\

感谢阅读,欢迎交流,点个赞,关注一波 再走吧

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~
可以进入地址进行体验和学习:https://xxetb.xet.tech/s/3lucCI

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/933937.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3.0极速入门 - 登录demo

Talk is cheap, Show the code 在完成npm和vue的环境安装,并了解了基本的目录和文件结构以后,直接写一个带登录和首页的demo做示例,快速了解一个vue工程的创建和基本的页面跳转 第一步创建工程 1、选择手动模式创建工程 npm create app-…

工地扬尘自动监测识别算法

工地扬尘自动监测识别系统通过yolov7python网络模型深度学习算法模型,扬尘自动监测识别算法能够全天候、全方位地观测扬尘情况。YOLOv7 的策略是使用组卷积来扩展计算块的通道和基数。研究者将对计算层的所有计算块应用相同的组参数和通道乘数。然后,每个…

prometheus + grafana进行服务器资源监控

在性能测试中,服务器资源是值得关注一项内容,目前,市面上已经有很多的服务器资 源监控方法和各种不同的监控工具,方便在各个项目中使用。 但是,在性能测试中,究竟哪些指标值得被关注呢? 监控有…

SQL语法与DDL语句的使用

文章目录 前言一、SQL通用语法二、DDL语句1、DDL功能介绍2、DDL语句对数据库操作(1)查询所有数据库(2)查询当前数据库(3)创建数据库(4)删除数据库(5)切换数据…

【Linux-Day8- 进程替换和信号】

进程替换和信号 问题引入 我们发现 终端输入的任意命令的父进程都是bash,这是因为Linux系统是用fork()复制出子进程,然后在子进程中调用替换函数进行进程替换,实现相关命令。 (1) exec 系列替换过程:pcb 使用以前的只…

开源项目的资金来源:捐赠、赞助与商业模式

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

C语言(第三十一天)

6. 调试举例1 求1!2!3!4!...10!的和&#xff0c;请看下面的代码&#xff1a; #include <stdio.h> //写一个代码求n的阶乘 int main() {int n 0;scanf("%d", &n);int i 1;int ret 1;for(i1; i<n; i){ret * i;}printf("%d\n", ret);return …

delphi7创建DLL步骤方法

delphi7创建DLL步骤方法1.打开delphi7,点击File/New/Other...,如下图&#xff1a; 2.选择New/DLL Wizard,如下图&#xff1a; 3.起一个项目名称&#xff0c;然后点击File/SaveAll,这里以TestDll为例&#xff0c;如下图&#xff1a; 4.新建一个单元文件File/New/Unit,保存…

Vue2向Vue3过度核心技术插槽

目录 1 插槽-默认插槽1.作用2.需求3.问题4.插槽的基本语法5.代码示例6.总结 2 插槽-后备内容&#xff08;默认值&#xff09;1.问题2.插槽的后备内容3.语法4.效果5.代码示例 3 插槽-具名插槽1.需求2.具名插槽语法3.v-slot的简写4.总结 4 作用域插槽1.插槽分类2.作用3.场景4.使用…

C语言(第三十二天)

1. 递归是什么&#xff1f; 递归是学习C语言函数绕不开的一个话题&#xff0c;那什么是递归呢&#xff1f; 递归其实是一种解决问题的方法&#xff0c;在C语言中&#xff0c;递归就是函数自己调用自己。 写一个史上最简单的C语言递归代码&#xff1a; #include <stdio.h>…

拼多多anti-token分析

前言&#xff1a;拼多多charles抓包分析发现跟商品相关的请求头里都带了一个anti-token的字段且每次都不一样,那么下面的操作就从分析anti-token开始了 1.jadx反编译直接搜索 选中跟http相关的类对这个方法进行打印堆栈 结合堆栈方法调用的情况找到具体anti-token是由拦截器类f…

wazuh环境配置和漏洞复现

1.wazuh配置 虚拟机 &#xff08;OVA&#xff09; - 替代安装 (wazuh.com)在官方网页安装ova文件 打开VMware选择打开虚拟机&#xff0c;把下载好的ova文件放入在设置网络改为NAT模式 账号:wazuh-user 密码:wazuh ip a 查看ip 启动小皮 远程连接 账号admin …

Vue2向Vue3过度Vuex核心概念getters

目录 1 核心概念 - getters1.定义getters2.使用getters2.1原始方式-$store2.2辅助函数 - mapGetters 2 使用小结 1 核心概念 - getters 除了state之外&#xff0c;有时我们还需要从state中筛选出符合条件的一些数据&#xff0c;这些数据是依赖state的&#xff0c;此时会用到get…

数据结构(Java实现)-二叉树(下)

获取二叉树的高度 检测值为value的元素是否存在(前序遍历) 层序遍历 判断一棵树是不是完全二叉树 获取节点的路径 二叉树的最近公共祖先

小研究 - JAVA 虚拟机内存使用优化研究与应用

Java 虚拟机在运行 Java 应用程序的查询操作时&#xff0c;存在由于查询结果数据量大和查询并发性高而出现系统不稳定的问题。提出了一种 JVM 内存使用优化方案&#xff1a;恒定使用 JVM 内存&#xff0c;能够在不提高硬件成本的情况下&#xff0c;保证系统连续稳定地运行。 目…

c++的分文件编写

前言 在C中&#xff0c;你可以将代码分割成多个文件来提高可维护性和组织性。分割文件有助于将代码模块化&#xff0c;使大型项目更易于管理。以下是C中关于分文件的一些规则和概念&#xff1a; 理论知识 头文件&#xff08;Header Files&#xff09;&#xff1a; 头文件通常…

深入理解 C++ 中的 std::cref、std::ref 和 std::reference_wrapper

深入理解 C 中的 std::cref、std::ref 和 std::reference_wrapper 在 C 编程中&#xff0c;有时候我们需要在不进行拷贝的情况下传递引用&#xff0c;或者在需要引用的地方使用常量对象。为了解决这些问题&#xff0c;C 标准库提供了三个有用的工具&#xff1a;std::cref、std:…

2023年 Java 面试八股文下(20w字)

目录 1.1 面试过程最关键的是什么&#xff1f; 1.2 面试时该怎么说&#xff1f; 1.3 面试技巧 1.3.1 六个常见问题 1.3.2 两个注意事项 1.3.3 自我介绍&#xff08;控制在4分半以内&#xff0c;不超过5分钟&#xff09; 手写代码 2.1 冒泡排序&#xff08;Bubble Sort&…

Spring Boot整合RabbitMQ之路由模式(Direct)

RabbitMQ中的路由模式&#xff08;Direct模式&#xff09;应该是在实际工作中运用的比较多的一种模式了&#xff0c;这个模式和发布与订阅模式的区别在于路由模式需要有一个routingKey&#xff0c;在配置上&#xff0c;交换机类型需要注入DirectExchange类型的交换机bean对象。…

自动化测试 —— Pytest测试框架

01 | 简介 Pytest是一个非常成熟的全功能的Python测试框架&#xff0c;主要有以下特点&#xff1a; 简单灵活&#xff0c;容易上手&#xff0c;文档丰富 支持参数化&#xff0c;可以细粒度地控制测试用例 支持简单的单元测试与复杂的功能测试&#xff0c;还可以用来做Seleni…