Gin框架入门(2)--异常捕获与日志实现

异常捕获

Go语言的异常捕获采用的是延迟处理的方法实现的,实际上就是利用defer,panic和recover三个关键字和函数来实现的。

关键字

defer关键字(函数)

这个关键字在控制语句中就有所涉及,本质上是采用一个栈的存储结构,在整个函数执行完之后,再启用这个栈,依次执行这个函数。需要注意的是以下几点:

  1. 由于是栈的结构,我们首先想到的便是先入后出,defer也是如此

    func f(){
    defer A
    defer B
    D
    defer C}
    

    执行的顺序是D,C,B,A

  2. 被defer标记的语句是放在最后执行的,所以也就衍生出defer的玩法——放在开头加一个打印语句,来判断go程的结束(原理如此,至于稍复杂的结合等待组或者响应等也大同小异)

panic函数

让程序直接崩溃的函数,用法panic("<报错信息>")

Recover

Recover只在延时函数中有效,效果是将崩溃的程序恢复过来;如果是在正常的语句中使用Recover,就会返回一个nil并且没有任何效果。

实例(没意义):

func main() {defer func() {if err := recover(); err != nil {fmt.Println("捕获异常:", err)}}()r := router.Router()r.Run(":9999")panic("雪豹毁了我的程序")}

运行结果:

服务端正常运行!

实例:

使用这个方法,使得程序不崩溃的情况下获得异常,并且保证只是使得前端无返回内容,而引起这个服务器的崩溃

改写user.go

func (u UserController) GetList(c *gin.Context) {//ReturnError(c *gin.Context, code int, msg string)defer func() {if err := recover(); err != nil {fmt.Println("捕获异常:", err)}}()num1, num2 := 1, 0num3 := num1 / num2ReturnUserGetListError(c, 404, num3)//<common.go>//func ReturnUserGetListError(c *gin.Context, code int, msg int) {//	json := &JsonErrStruct{Code: code, Msg: msg}//	c.JSON(http.StatusOK, json)//}}

运行结果

捕获异常: runtime error: integer divide by zero
[GIN] 2024/09/22 - 20:19:09 | 200 |            0s |       127.0.0.1 | POST     "/user/list"

在这里插入图片描述

日志

日志就是记录事件的记录表,主要分为以下三种

  1. 项目的请求日志
  2. 程序出现错误日志
  3. 程序员开发的时候自己保存的日志

封装保存日志的包

  1. 首先,创建一个pkg包,这个包的用途是防止开发时需要的工具。在pkg包下面创建一个子文件夹logger,用来存放日志工具,在这个子文件夹下创建logger.go文件
  2. 之后,导入一下我们将要使用的日志工具包,在终端命令行输入go get github.com/sirupsen/logrus

文件结构

中间件logger.go内容
在这里插入图片描述

package loggerimport ("fmt""github.com/gin-gonic/gin""github.com/sirupsen/logrus""io""os""path""path/filepath""runtime/debug""time"
)// 初始化日志设置
func init() {// 设置日志的 JSON 格式logrus.SetFormatter(&logrus.JSONFormatter{TimestampFormat: "2006-01-02 15:04:05",})logrus.SetReportCaller(false)
}// 写入程序员自定义的日志
func Write(msg string, filename string) {setOutPutFile(logrus.InfoLevel, filename)logrus.Info(msg)
}// Debug 级别日志
func Debug(fields logrus.Fields, args ...interface{}) {setOutPutFile(logrus.DebugLevel, "debug")logrus.WithFields(fields).Debug(args)
}// Info 级别日志
func Info(fields logrus.Fields, args ...interface{}) {setOutPutFile(logrus.InfoLevel, "info")logrus.WithFields(fields).Info(args)
}// Warn 级别日志
func Warn(fields logrus.Fields, args ...interface{}) {setOutPutFile(logrus.WarnLevel, "warn")logrus.WithFields(fields).Warn(args)
}// Fatal 级别日志
func Fatal(fields logrus.Fields, args ...interface{}) {setOutPutFile(logrus.FatalLevel, "fatal")logrus.WithFields(fields).Fatal(args)
}// Error 级别日志
func Error(fields logrus.Fields, args ...interface{}) {setOutPutFile(logrus.ErrorLevel, "error")logrus.WithFields(fields).Error(args)
}// Panic 级别日志
func Panic(fields logrus.Fields, args ...interface{}) {setOutPutFile(logrus.PanicLevel, "panic")logrus.WithFields(fields).Panic(args)
}// Trace 级别日志
func Trace(fields logrus.Fields, args ...interface{}) {setOutPutFile(logrus.TraceLevel, "trace")logrus.WithFields(fields).Trace(args)
}// 设置日志输出文件 在各个函数方法中调用
func setOutPutFile(level logrus.Level, logName string) {// 创建日志目录logDir := "./runtime/log"if _, err := os.Stat(logDir); os.IsNotExist(err) {err = os.MkdirAll(logDir, 0777)if err != nil {panic(fmt.Errorf("create log dir '%s' error: %s", logDir, err))}}// 获取当前日期字符串timeStr := time.Now().Format("2006-01-02")fileName := filepath.Join(logDir, logName+"_"+timeStr+".log")// 打开日志文件,如果不存在则创建var err erroros.Stderr, err = os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)if err != nil {fmt.Println("open log file err:", err)}// 设置日志输出到文件logrus.SetOutput(os.Stderr)logrus.SetLevel(level)return
}// 创建了success开头的文件 在logger中以中间件的形式调用
func LoggerToFile() gin.LoggerConfig {logDir := "./runtime/log"if _, err := os.Stat(logDir); os.IsNotExist(err) {err = os.MkdirAll(logDir, 0777)if err != nil {panic(fmt.Errorf("create log dir '%s' error: %s", logDir, err))}}// 获取当前日期字符串timeStr := time.Now().Format("2006-01-02")fileName := path.Join(logDir, "success_"+timeStr+".log")os.Stdout, _ = os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)var conf = gin.LoggerConfig{Formatter: func(param gin.LogFormatterParams) string {return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",param.TimeStamp.Format(time.RFC1123),param.ClientIP,param.Method,param.Path,param.Request.Proto,param.StatusCode,param.Latency,param.Request.UserAgent(),param.ErrorMessage,)},Output: io.MultiWriter(os.Stdout, os.Stderr),}return conf
}// 将报错放在报文中返回回来 在logger中以中间件的形式调用
func Recover(c *gin.Context) {defer func() {if err := recover(); err != nil {if _, errDir := os.Stat("./runtime/log"); os.IsNotExist(errDir) {errDir := os.MkdirAll("./runtime/log", 0777)if errDir != nil {panic(fmt.Errorf("create log dir '%s' error: %s", "./runtime/log", err))}}timeStr := time.Now().Format("2006-01-02")//文件名fileName := path.Join("./runtime/log", timeStr+".log")f, errFile := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)if errFile != nil {fmt.Println(errFile)}timeFileStr := time.Now().Format("2006-01-02 15:04:05")//写入信息f.WriteString("panic error tome:" + timeFileStr + "\n")f.WriteString(fmt.Sprintf("%v", err) + "\n")f.WriteString("stacktrace from panic" + string(debug.Stack()) + "\n")f.Close()c.JSON(200, gin.H{"code": 500,"msg":  fmt.Sprintf("%v", err),})//终止后续接口调用,不加入recover到异常之后,还会继续执行接口中的后续代码c.Abort()}}()c.Next()
}

可以结合注释简单了解以下,然后cv使用即可

调用方式

对于前两种:项目的请求日志(LoggerToFile)和 程序出现错误日志(Recover)而言,调用的方式是在路由(router.go)的函数中以中间件的方式调用

//日志r.Use(gin.LoggerWithConfig(logger.LoggerToFile()))r.Use(logger.Recover)

而对于 程序员开发的时候自己保存的日志(setOutPutFile),则是以方法的形式在想要记录的函数(方法)中调用logger.Write("日志信息", "user")

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

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

相关文章

时钟的配置

在使用51单片机时&#xff0c;系统使用的时钟源是一个外部晶体振荡器&#xff0c;频率为12M。由于51单片机每个指令周期都是12分频的&#xff0c;所以实际工作频率仅为1M。2440作为一种性能远高于51的Soc&#xff0c;主频肯定要远远高于51&#xff0c;因此2440有着比51单片机复…

yolov8模型在Xray图像中关键点检测识别中的应用【代码+数据集+python环境+GUI系统】

yolov8模型在X yolov8模型在Xray图像中关键点检测识别中的应用【代码数据集python环境GUI系统】 1.背景意义 X射线是一种波长极短、穿透能力极强的电磁波。当X射线穿透物体时&#xff0c;不同密度和厚度的物质会吸收不同程度的X射线&#xff0c;从而在接收端产生不同强度的信号…

pycharm加载虚拟环境及运行代码

pycharm加载虚拟环境及运行代码 pycharm下载地址&#xff1a; https://www.jetbrains.com/pycharm/download/ 1.加载虚拟环境 选择pycharm图标&#xff0c;点击启动。 选择OPEN, 选择工程文件夹&#xff1a; 选择File->setting 选择python 解释器&#xff1a; Project--…

扫码挪车是怎么实现的呢?一篇文章带你了解一下!扫码挪车小程序基础版上线了!!!

挪车小程序系统源码的功能特点 快速定位与挪车请求&#xff1a;车主通过小程序可以快速定位车辆位置&#xff0c;并发送挪车请求。系统会自动将请求发送给附近的车主&#xff0c;提醒其尽快挪车。实时通信与交互&#xff1a;小程序支持实时通信功能&#xff0c;车主之间可以通…

【C++笔记】C++编译器拷贝优化和内存管理

【C笔记】C编译器拷贝优化和内存管理 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】C编译器拷贝优化和内存管理前言一.对象拷贝时的编译器优化二.C/C内存管理2.1练习2.2 C内存管理方式2.3 operator new与operator…

tornado

Tornado通过使用非阻塞网络1/0&#xff0c;可以扩展到数以万计的开放链接&#xff0c;非常适合 长时间轮询&#xff0c;WebSockets和其他需要与每个用户建立长期连接的应用程序。 特点 注重性能优越&#xff0c;速度快解决高并发异步非阻塞websockets 长连接内嵌了HTTP服务器…

十一、 JDK17 新特性梳理

文章目录 为什么是JDK17语法层面新特性1、文本块2 、Switch 表达式增强3、instanceof的模式匹配4、var 局部变量推导 模块化及类封装1、记录类 record2 、隐藏类 Hidden Classes3 、密封类 Sealed Classes4、模块化 Module System1 、什么是模块化2、声明一个module3 、require…

“智能密钥管家”IKE

IKE的出现 上一篇通过IPSec实现了BJ到CS的业务互通&#xff0c;但是是通过手工方式把加密和验证密钥手动配置&#xff0c;为了保障安全性&#xff0c;就需要经常去修改这些密钥&#xff0c;小型场景还好&#xff0c;来来回回就这2个点&#xff0c; 修改起来不算麻烦&#xff…

[Redis] 渐进式遍历+使用jedis操作Redis+使用Spring操作Redis

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

解决SVN蓝色问号的问题

桌面或文件夹右键&#xff0c;选择TortoiseSVN->Settings打开设置对话框&#xff0c;选择Icon Overlays->Overlay Handlers->取消钩选Unversioned。确定&#xff0c;重启系统即可

CodeGeeX4:程序员的高效助手,多语言代码生成神器!

你是否曾在编写代码时&#xff0c;为复杂的语法、逻辑错误而绞尽脑汁&#xff1f;或是在面对多个编程语言的切换时&#xff0c;感觉脑子快要爆炸&#xff1f;别担心&#xff01;一款全新的多语言代码生成神器——CodeGeeX4&#xff0c;正悄然成为程序员们的“救命稻草”。它不仅…

【工具变量】地市环保法庭试点城市DID数据集(2005-2023年)

数据简介&#xff1a;环保法庭是中国司法体系中专门处理环境资源案件的审判机构&#xff0c;其主要职责包括审理涉及自然环境污染、矿产资源保护、自然资源环境开发等环境资源民事纠纷案件&#xff0c;对不服下级人民法院生效裁判的环境资源民事案件进行审查&#xff0c;以及对…

如何在Chrome最新浏览器中调用ActiveX控件?

小编最近登陆工商银行网上银行&#xff0c;发现工商银行的个人网银网页&#xff0c;由于使用了ActiveX安全控件&#xff0c;导致不能用高版本Chrome浏览器打开&#xff0c;目前只有使用IE或基于IE内核的浏览器才能正常登录网上银行&#xff0c;而IE已经彻底停止更新了&#xff…

C++:类和对象OJ题

目录 一、求123...n 二、计算日期到天数的转换 三、日期差值 四、打印日期 一、求123...n 这里先把题目链接放在这里求123.....n 描述&#xff1a; 求123...n&#xff0c;要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句&#xff08;A?B:C…

介绍 2款 Oracle 开发工具

准备工作 Oracle SQL Developer 下载&#xff08;免费&#xff09; Oracle 的官方网站下载 Oracle SQL Developer。以下是下载的步骤&#xff1a; 访问 Oracle SQL Developer 官方下载页面。点击页面上的“下载”链接。选择适合你操作系统的版本&#xff08;Windows、macO…

第十五章:使用html、css、js编程制作一个网页版的下雪场景动画

背景:这是一个充满诗意的下雪场景代码。打开网页时,雪花轻轻飘落,覆盖住你的屏幕,仿佛置身于冬日的夜空下。背景音乐《我期待的不是雪》缓缓响起,伴随着雪花的飘动,仿佛心中的那份爱与温柔悄然绽放。 雪花的飘落是梦境般的存在,每一片雪花都是轻盈的告白,旋转着从天际…

百度营销转化追踪(网页JS布码)

引言&#xff1a;使用百度营销api配置网站上各个模块组件的转化追踪&#xff0c;统计网站上的各组件模块点击等信息。 一、选择接入方式&#xff08;本文选择的是网页JS布码&#xff09; 参考文档&#xff1a;百度营销-商业开发者中心百度开发者中心是一个面向开发者的知识分享…

『功能项目』QFrameWork制作背包界面UGUI【72】

本章项目成果展示 我们打开上一篇71QFrameWork更新道具图片UGUI的项目&#xff0c; 本章要做的事情是制作背包UI界面&#xff0c;实现道具栏与背包道具的互通 首先将以下资源图片放进Art文件夹 将UICanvas的UISlot对象复制一份放在Image下 创建Scrollbar View 设置Scrollbar V…

Resolving and Binding

1 Semantic Analysis中的变量绑定解析 背景&#xff1a;当一个变量在一个循环里赋值100次。那么这个变量会被赋值100次。当右侧是函数时&#xff0c;这非常没必要。这个可以通过静态的分析来避免这个问题。这个分析就是Sematic Analysis中的一个例子。 具体做的事情叫 2 把定…

10.解析解方法推导线性回归——不容小觑的线性回归算法

引言 线性回归是许多复杂机器学习模型的基础。作为一种基本的机器学习方法&#xff0c;线性回归提供了清晰的思路和工具&#xff0c;通过理解其推导过程&#xff0c;可以更好地掌握机器学习的基本原理和模型设计。 通过阅读本篇博客&#xff0c;你可以&#xff1a; 1.学会如…