首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[系列] - go-gin-api 路由中间件 - 捕获异常(四)

[系列] - go-gin-api 路由中间件 - 捕获异常(四)

作者头像
新亮
发布于 2019-09-17 02:45:04
发布于 2019-09-17 02:45:04
1.1K00
代码可运行
举报
文章被收录于专栏:新亮笔记新亮笔记
运行总次数:0
代码可运行

概述

首先同步下项目概况:

上篇文章分享了,路由中间件 - 日志记录,这篇文章咱们分享:路由中间件 - 捕获异常。

当系统发生异常时,提示 “系统异常,请联系管理员!”,并发送 panic 告警邮件。

什么是异常?

在 Go 中异常就是 panic,它是在程序运行的时候抛出的,当 panic 抛出之后,如果在程序里没有添加任何保护措施的话,控制台就会在打印出 panic 的详细情况,然后终止运行。

我们可以将 panic 分为两种:

一种是有意抛出的,比如,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
panic("自定义的 panic 信息")

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2019/09/10 20:25:27 http: panic serving [::1]:61547: 自定义的 panic 信息goroutine 8 [running]:...

一种是无意抛出的,写程序马虎造成,比如,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var slice = [] int {1, 2, 3, 4, 5}
slice[6] = 6

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2019/09/10 15:27:05 http: panic serving [::1]:61616: runtime error: index out of rangegoroutine 6 [running]:...

想象一下,如果在线上环境出现了 panic,命令行输出的,因为咱们无法捕获就无法定位问题呀,想想都可怕,那么问题来了,怎么捕获异常?

怎么捕获异常?

当程序发生 panic 后,在 defer(延迟函数) 内部可以调用 recover 进行捕获。

不多说,直接上代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
defer func() {    if err := recover(); err != nil {        fmt.Println(err)    }}()

在运行一下 “无意抛出的 panic ”,输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
runtime error: index out of range

OK,错误捕获到了,这时我们可以进行做文章了。

做啥文章,大家应该都知道了吧:

  • 获取运行时的调用栈(debug.Stack())
  • 获取当时的 Request 数据
  • 组装数据,进行发邮件

那么,Go 怎么发邮件呀,有没有开源包呀?

当然有,请往下看。

封装发邮件方法

使用包:gopkg.in/gomail.v2

直接上代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func SendMail(mailTo string, subject string, body string) error {
    if config.ErrorNotifyOpen != 1 {        return nil    }
    m := gomail.NewMessage()
    //设置发件人    m.SetHeader("From", config.SystemEmailUser)
    //设置发送给多个用户    mailArrTo := strings.Split(mailTo, ",")    m.SetHeader("To", mailArrTo...)
    //设置邮件主题    m.SetHeader("Subject", subject)
    //设置邮件正文    m.SetBody("text/html", body)
    d := gomail.NewDialer(config.SystemEmailHost, config.SystemEmailPort, config.SystemEmailUser, config.SystemEmailPass)
    err := d.DialAndSend(m)    if err != nil {        fmt.Println(err)    }    return err}

在这块我加了一个开关,想开想关,您随意。

现在会发送邮件了,再整个邮件模板就完美了。

自定义邮件模板

如图:

这就是告警邮件的模板,还不错吧,大家还想记录什么,可以自定义去修改。

封装一个中间件

最后,封装一下。

直接上代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func SetUp() gin.HandlerFunc {
    return func(c *gin.Context) {        defer func() {            if err := recover(); err != nil {
                DebugStack := ""                for _, v := range strings.Split(string(debug.Stack()), "\n") {                    DebugStack += v + "<br>"                }
                subject := fmt.Sprintf("【重要错误】%s 项目出错了!", config.AppName)
                body := strings.ReplaceAll(MailTemplate, "{ErrorMsg}", fmt.Sprintf("%s", err))                body  = strings.ReplaceAll(body, "{RequestTime}", util.GetCurrentDate())                body  = strings.ReplaceAll(body, "{RequestURL}", c.Request.Method + "  " + c.Request.Host + c.Request.RequestURI)                body  = strings.ReplaceAll(body, "{RequestUA}", c.Request.UserAgent())                body  = strings.ReplaceAll(body, "{RequestIP}", c.ClientIP())                body  = strings.ReplaceAll(body, "{DebugStack}", DebugStack)
                _ = util.SendMail(config.ErrorNotifyUser, subject, body)
                utilGin := util.Gin{Ctx: c}                utilGin.Response(500, "系统异常,请联系管理员!", nil)            }        }()        c.Next()    }}

当发生 panic 异常时,输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{    "code": 500,    "msg": "系统异常,请联系管理员!",    "data": null}

同时,还会收到一封 panic 告警邮件。

便于截图,DebugStack 删减了一些信息。

到这,就结束了。

备注

  • 发邮件的地方,可以调整为异步发送。
  • 文章中仅贴了部分代码,相关代码请查阅 github。
  • 测试发邮件时,一定要配置邮箱信息。

源码地址

https://github.com/xinliangnote/go-gin-api

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-09-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 新亮笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Groovy 元组构造函数创建
Groovy 1.8添加了@TupleConstructor注释。 通过这个注释,我们可以在编译时自动创建一个元组构造函数。 因此构造函数可以在编译的类中找到。 对于类中的每个属性,将使用默认值创建构造函数中的参数。 类中定义的属性的顺序还定义了构造函数中参数的顺序。 因为参数具有默认值,所以我们可以使用Groovy语法,并在使用构造函数时将参数留在参数列表的末尾。
白石
2019/09/18
1.4K0
Groovy 使用EqualsAndHashCode注解生成equals和hashcode方法
Groovy 1.8中有很多新的字节码生成注释。 其中一个是@EqualsAndHashCode注释。 使用此注释,为类生成equals()和hashCode()方法。 hashCode()方法是使用Groovyorg.codehaus.groovy.util.HashCodeHelper实现的(遵循书中的算法 Effective Java )。 equals()方法查看类的所有单个属性,以查看两个对象是否相同。
白石
2019/09/09
1.9K0
Groovy快速入门看这篇就够了
在前面我们学习了为什么现在要用Gradle?和Gradle入门前奏两篇文章,对Gradle也有了大概的了解,这篇文章我们接着来学习Groovy的基础,要想学好Gradle,Groovy是必须要掌握的。Groovy仅凭一篇文章是介绍不完的,这里会带大家快速的入门Groovy,讲解Groovy和Java不同的部分,想要更多了解Groovy可以查看Groovy官方文档和Groovy API文档。
用户1269200
2018/10/25
15.8K0
Groovy 使用Builder AST 转换为流式API
从Groovy 2.3开始,我们可以使用@Builder AST转换轻松地为我们的类创建一个流畅的API。 我们可以将注释应用于我们的类,结果类文件将具有支持流畅API的所有必要方法。 我们可以自定义如何使用不同的注释参数生成流畅的API。 在Groovy代码中,我们已经可以使用with方法 有一个简洁的方法来设置属性值或使用 命名的构造函数参数。 但是如果我们的类需要从Java中使用,那么为Java开发人员提供一个流畅的API来为我们的Groovy类做很好。
白石
2019/09/18
1K0
Groovy里自定义JSON输出-JsonGenerator
Groovy 2.5.0增加了通过JsonGenerator实例自定义JSON输出。 将对象转换为JSON字符串值的最简单方法是通过JsonOutput.toJson。 此方法使用默认的JsonGenerator,其JSON输出具有合理的默认值。 但是我们可以使用自定义生成器并创建JSON输出。 要创建自定义生成器,我们使用可通过JsonGenerator.Options访问的构建器。 通过流式的API,我们可以例如忽略输出中带有null值的字段,更改日期的日期格式,并按名称或值的类型忽略字段。 我们可以通过将转换的实现添加为Closure或者实现JsonGenerator.Converter接口来为类型添加自定义转换器。 要获取JSON字符串,我们只需调用生成器的toJson方法。
白石
2019/08/23
2.4K0
Groovy新手教程
简单地说,Groovy 是下一代的java语言,跟java一样,它也执行在 JVM 中。
全栈程序员站长
2022/07/12
2.2K0
25. Groovy 孵化功能-记录类record和密封sealed的学习
本篇内容为Groovy学习笔记第二十五篇。主要内容为Groovy孵化功能(incubating)的学习。
zinyan.com
2023/02/23
1.1K0
25. Groovy 孵化功能-记录类record和密封sealed的学习
Groovy 添加带注释的Map构造函数
从Groovy的早期开始,我们可以创建POGO(Plain Old Groovy Objects)类,它们将具有带有Map参数的构造函数。 Groovy在生成的类中自动添加构造函数。我们可以使用命名参数来创建POGO的实例,因为Map参数构造函数。 这只有在我们不添加自己的构造函数且属性不是最终的时才有效。从Groovy 2.5.0开始,我们可以使用@MapConstrutor AST转换注释来添加带有Map参数的构造函数。使用注释我们可以有更多选项来自定义生成的构造函数。例如,我们可以让Groovy使用Map参数生成构造函数,并添加我们自己的构造函数。 属性也可以是final,我们仍然可以使用带有Map参数的构造函数。
白石
2019/08/23
1.2K0
[Android Gradle] 搞定Groovy闭包这一篇就够了
做Android开发的同学,对Gradle肯定不陌生,我们用它配置、构建工程,可能还会开发插件来促进我们的开发,我们必须了解Gradle,而不仅限于只会当配置构建工具,我想学习它,于是就有了这一系列的文章。
Android技术干货分享
2019/03/27
1.4K0
[Android Gradle] 搞定Groovy闭包这一篇就够了
Groovy秘诀 顶
听说java世界里有个Groovy大神!java需要半天处理的事情,Groovy只需要几分钟,是的,几分钟…剩下来的时间,程序员终于有时间泡妹子了,^_^…….技术宅的兄弟,赶紧来看看吧。
白石
2019/08/23
4.8K0
Groovy 快速入门
Groovy是一门基于JVM的动态语言,很多语法和Java类似。大部分Java代码也同时是合法的Groovy代码。本文是快速入门,所以针对语法并不会做非常详细的介绍。如果需要详细语法,请直接查看Groovy官方文档。另外为了省事,本文中的大部分代码例子直接引用了Groovy文档。
乐百川
2022/05/05
1.5K0
Groovy-拾遗
许多以前使用 C++ 的开发人员会怀念操作符重载,例如 + 和 -。虽然它们很方便,但是被覆盖的操作符的多态实质会造成混淆,所以操作符重载在 Java 语言中被取消了。这个限制的好处是清晰:Java 开发人员不必猜想两个对象上的 + 是把它们加在一起还是把一个对象附加到另一个对象上。不好的地方则是丧失了一个有价值的简写形式。
白石
2019/08/23
1.7K0
19. Groovy 面向对象编程-注解学习
本篇为Groovy学习笔记第十九篇。分享关于注解的相关知识。Annotations(注解)。现在的各种开发语言可以说都有注解。
zinyan.com
2022/12/08
8560
2--Gradle入门 - Groovy简介、基本语法
Gradle 需要 Groovy 语言的支持,所以本章节主要来介绍 Groovy 的基本语法。
Devops海洋的渔夫
2023/09/01
1.4K0
2--Gradle入门 - Groovy简介、基本语法
Groovy开发工具包
本文参考自The Groovy Development Kit,一些代码直接引用了源文档。
乐百川
2022/05/05
8180
34. Groovy 语法 类型知识详解-第一篇
本篇内容开始介绍Groovy中的各种类型知识。将会分多篇文章详细介绍和学习Groovy中的有关于类型的相关知识点。
zinyan.com
2023/02/23
8670
34. Groovy 语法 类型知识详解-第一篇
36. Groovy 语法 类型知识详解-最终篇
本篇是Typing相关知识的最后一篇。介绍关于类型的闭包和类型推断关系,以及最终的类型静态编译相关知识点。
zinyan.com
2023/02/23
1K0
36. Groovy 语法 类型知识详解-最终篇
Spring学习笔记之基础、IOC、DI(1)
0.0 Spring基本特性 Spring是一个开源框架;是基于Core来架构多层JavaEE系统 1.0 IOC 控制反转:把对象的创建过程交给spring容器来做。
王小雷
2019/05/26
3500
注解的使用合集
Spring Boot 用来简化 Spring 应用程序的创建和 开发过程,采用 Spring Boot 可以非常容易和快速地创建基于 Spring 框架的应用程序,它让编 码变简单了,配置变简单了,部署变简单了,监控变简单了。正因为 Spring Boot 它化繁为简,让开发变得极其简单和快速,所以在业界备受关注。
shaoshaossm
2022/12/27
2.5K0
注解的使用合集
Gradle-Groovy语法
Groovy 是一种基于 JVM 的动态语言,他的语法和 Java 相似,最终也是要编译 .class 在JVM上运行。
佛系编码
2019/12/11
1.7K0
Gradle-Groovy语法
相关推荐
Groovy 元组构造函数创建
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档