你用Go写过中间件吗?带你用Go实现【操作日志中间件】

本文涉及的产品
云原生网关 MSE Higress,422元/月
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 管理后台所有修改,添加,删除的操作都要记录;操作日志的统计不影响主程序的性能

需求说明


  1. 管理后台所有修改,添加,删除的操作都要记录
  2. 操作日志的统计不影响主程序的性能


需求分析


  1. 把相关代码封装成中间件,独立使用
  2. 合理使用goroutine,不影响主线程的性能


文档说明


  1. 基于golang语言开发
  2. 基于gin网络框架开发
  3. 基于MySQL5.8开发
  4. 把操作日志部分封装成中间件,在rourter文件中引用
  5. 非核心代码已省略,用3个竖着排列的点号.表示


数据库表结构设置


操作日志表


微信图片_20221111180814.jpg


代码


中间件代码


代码分析


  1. 我们可以通过context直接获得请求方式和请求的url
  2. 无法直接获得返回信息,我们可以借助"ResponseWriter",运用拦截器的思想,把返回信息先截取到,再向下继续传递
  3. 像获得客户端ip这类方法封装到util中,方便灵活调用
  4. 我们无法将adminLogs()方法整体设置为goroutine,因为这样会将context的事件传递在新的协程中进行,无法正常传递。
  5. 所以我们再c.Next()事件传递之后,把json解析成结构体,以及保存操作日志到数据库的操作设置为使用goroutine协程操作
  6. 操作日志是没有比较记录查询操作的,所以我们把请求方式为GET的过滤掉


package middleware
//amdin操作日志
import (
    .
    .
    .
  "bytes"
  "encoding/json"
  "fmt"
  "github.com/gin-gonic/gin"
  "strings"
)
type bodyLogWriter struct {
  gin.ResponseWriter
  bodyBuf *bytes.Buffer
}
func (w bodyLogWriter) Write(b []byte) (int, error) {
  w.bodyBuf.Write(b)
  return w.ResponseWriter.Write(b)
}
var CommonLogInterceptor = commonLogInterceptor()
/*
1 使用goroutine和channel实现操作日志的入库保存,尽可能的不影响主程序
2 goroutine协程,提高并发量
3 channel通道
*/
func commonLogInterceptor() gin.HandlerFunc {
  return func(c *gin.Context) {
    adminLogs(c)
  }
}
//获得每次请求返回的code和message
func adminLogs(c *gin.Context) {
  if admin, _ := c.Get("admin"); admin != nil {
    method := c.Request.Method
    url := c.Request.URL.Path
    strBody := ""
    var blw bodyLogWriter
    blw = bodyLogWriter{bodyBuf: bytes.NewBufferString(""), ResponseWriter: c.Writer}
    c.Writer = blw
    c.Next()
    if method != "GET" {
      strBody = strings.Trim(blw.bodyBuf.String(), "\n")
      go func(strBody string) {
        var returnJson api.ReturnJson
        json.Unmarshal([]byte(strBody), &returnJson)
        message := fmt.Sprintf("%v", returnJson.Message)
        adminInfo := admin.(**service.RunningClaims)
        adminId := (*adminInfo).ID
        adminName := (*adminInfo).Account
        var log = model.AdminLog{
          AdminId:   adminId,
          AdminName: adminName,
          Method:    method,
          Url:       url,
          Ip:        util.RemoteIP(c.Request),
          Code:      returnJson.Code,
          Message:   message,
        }
        model.CreateLog(log)
      }(strBody)
    }
  }
}

model层代码


package model
type AdminLog struct {
  ID int `json:"id"`
  AdminId uint `json:"admin_id"`
  AdminName string `json:"admin_name"`
  Method string `json:"method"`
  Ip string `json:"ip"`
  Url string `json:"url"`
  Code int `json:"code"`
  Message string `json:"message"`
}
func CreateLog(log AdminLog)  {
  DB.Create(&log)
}
复制代码


路由代码


package server
import (
  .
  .
  .
  "os"
  "github.com/gin-gonic/gin"
)
// NewRouter 路由配置
func NewRouter() *gin.Engine {
  r := gin.Default()
  // 其他中间件
  .
  .
  .
  // 路由
  v1 := r.Group("/api/v1")
  {
    v1.POST("login", api.Login)
    auth := v1.Group("")
    //登录校验中间件
    auth.Use(middleware.AuthRequired())
    //关键代码:权限角色校验
    auth.Use(middleware.AuthCheckMiddleware)
    //操作日志
    auth.Use(middleware.CommonLogInterceptor)
    {
            .
            .
            .
      // 获取所有学校
      {
        auth.GET("/school/", api.GetSchoolInfo)
      }
      .
      .
      .
    }
  }
  return r
}
复制代码


总结


  1. 以上则是我的实现思路
  2. 还有另外一种思路,计划已消息队列的方式实现,发送通知进行日志的报错


公众号:程序员升级打怪之旅

微信号:wangzhongyang1993

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
8天前
|
安全 Go
用 Zap 轻松搞定 Go 语言中的结构化日志
在现代应用程序开发中,日志记录至关重要。Go 语言中有许多日志库,而 Zap 因其高性能和灵活性脱颖而出。本文详细介绍如何在 Go 项目中使用 Zap 进行结构化日志记录,并展示如何定制日志输出,满足生产环境需求。通过基础示例、SugaredLogger 的便捷使用以及自定义日志配置,帮助你在实际开发中高效管理日志。
25 1
|
3月前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
130 1
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
3月前
|
存储 JSON 前端开发
一文搞懂 Go 1.21 的日志标准库 - slog
一文搞懂 Go 1.21 的日志标准库 - slog
106 2
|
3月前
|
中间件 Go 数据库
slog 简介:用于 Go 的结构化日志
slog 简介:用于 Go 的结构化日志
|
3月前
|
监控 Go 开发者
掌握Go语言中的日志管理
【8月更文挑战第31天】
34 0
|
4月前
|
消息中间件 缓存 中间件
中间件本地事务执行操作
【7月更文挑战第17天】
29 2
|
4月前
|
分布式计算 大数据 Go
MaxCompute操作报错合集之使用go sdk调用GetTunnelEndpoint出现报错:InvalidAction.NotFoundSpecified api is not found,该如何解决
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
|
4月前
|
运维 Devops API
阿里云云效操作报错合集之直接用API调用可以使用,但是本地用Go代码调用失败,是什么导致的?
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
4月前
|
监控 搜索推荐 Go
万字详解!在 Go 语言中操作 ElasticSearch
本文档通过示例代码详细介绍了如何在Go应用中使用`olivere/elastic`库,涵盖了从连接到Elasticsearch、管理索引到执行复杂查询的整个流程。
99 0
|
5月前
|
SQL Go 数据库
Go语言之GORM框架(二) ——GORM的单表操作
Go语言之GORM框架(二) ——GORM的单表操作