MyCat - 日志模块 - 微服务通过 AOP 记录日志 | 学习笔记

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 快速学习 MyCat - 日志模块 - 微服务通过 AOP 记录日志

开发者学堂课程【全面讲解开源数据库中间件 MyCat 使用及原理(四):MyCat - 日志模块 - 微服务通过 AOP 记录日志】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/758/detail/13324


MyCat - 日志模块 - 微服务通过 AOP 记录日志

内容介绍:

一、AOP 记录日志

二、测试

 

上节开发完成了记录日志的接口,要去记录各个微服务中的信息,还需要各个微服务中通过 AOP 拦截用户的请求然后记录(组装)日志,然后通过 Feign 调用微服务中的接口来记录日志。接下来我们将完成这一步的操作。

 

一、AOP 记录日志

1.自定义注解

通过 AOP 来记录日志,对于该部分的操作,先要自定义一个注解,需要在微服务中执行,这里以 goods 为例。

比如要记录 goods 商品该日志服务中的信息,则需要在 cn.itcast.goods 中增加 AOP 日志的代码。

声明一个包 aop,然后在该包中要引入一个自定义注解。

代码如下:

@Inherited

@Documented

@Tar get (ElementType .METHOD)

@Retention(RetentionPolicy. RUNTIME)

public interface operatelog {

}

该自定义注解的作用是标识作用方法,如果被该注解标识的方法代表当前该方法需要记录日志。哪些方法需要记录日志则只需要在该方法上加 OperateLog。

比如,在之前的 DemoController 中,要想记录该日志只需在该类的方法前加注解 @ OperateLog,如果不想记录该方法的日志不加该注解即可。(哪个方法加了该注解哪个方法的所有操作日志都会被记录)

2.AOP 通知类

有了自定义注解后,还需有一个解析该注解的地方,解析注解会通过 AOP 对其进行解析。

这里需要定义一个 AOP 的新类(对于当前项目来说,目的是使用 MyCat 进行数据库的分库分表),这里不再写(已写好),部分代码如下:

image.png

根据提示导入需要导入的包。

但是还有 OperateLogFeign 客户端,在之前的操作流程中提到在各个流程中组装日志数据,最终要通过 Feign 调用日志微服务中的接口(记录日志属于日志微服务),既然要用到 Feign ,则我们要声明一个 Feign 远程调用的接口,所以接下来声明该远程接口。

该接口应该在 v_feign_api (管理调用的远程接口)中,先创建一个包 cn.itcast.feign.client,在该包中声明一个接口,叫 OperateLogFeign,然后在该接口中声明一个注解 FeignClient,通过该 FeignClient 指定微服务名称 log,再声明一个接口方法(这里参考 OperateLogController 中的方法),但是还需要改路径,在其前面添加 /operateLog(因为要通过 Feign 来指定哪个微服务中的哪个方法,调用该接口就知道要找的是哪个微服务,这里是 log 微服务,log 是微服务的名字,然后调用微服务中的哪个接口是通过路径得知的,这里的路径是 /operateLog/add)

代码如下:

import org.springframework.cloud.openfeign.Feignclient;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestBody;

@Feignclient ( "log")

public interface operateLogFeign {

@PostMapping (“/operateLog/add")

public Result add (@RequestBody Tboperatelog operatelog);

}

到此,将 Feign 接口声明完成,然后在 OperateAdvice.java 中引入即可。

引入后,对于当前的通知类就编写完成了。

3.简单解读该通知类:

@Around(“execution(*cn.itcast.goods.controller.*.*(..))&&@annotation(operateLog)”)

指定要拦截的是哪一个包,通过该切入点表达式进行指定(这里要拦截的是 cn.itcast.goods.controller),*.*代表拦截该包下所有类的所有方法,并且该方法上的注解 operateLog(如果该方法上没有该注解则不会拦截)。

image.png

方法内部逻辑:

拦截到该方法后,在该方法中组装日志信息,首先组装当前操作时间及哪个用户操作(由于没有做认证环节,这里直接写 10000),当前操作的是哪个类(类名通过 ProceedingJoinPoint 得到),指定操作的是哪个方法。然后通过 pjp.getArgs 可以得到该参数。

// 表示放行,通过 pjp 的proceed 方法(放行)

Object object =pjp.proceed();

例如,用户需要根据 id 查询 sku 的信息,通过拦截后可以得到参数然后放行(放行指执行原始方法),原始方法执行完成后,可以得到返回值,然后记录结束时间(部分代码如下图)

image.png

得到开始时间和结束时间就可以得到原始方法执行的耗时,然后将耗时也记录下来,得到 Object 意味得到了返回值(返回值类型,返回值),然后通过 Feign 去调用远程的微服务中的接口。

4.完整代码为:

@Around("execution ( cn.itcast.goods . controller.*.*(..)〉 && @annotation (operateLiog)")

public Object insertLogAround(ProceedingToinPoint pjp ,OperateLog operatsLog) throws Throwable {

System.out.println (“***********************************记录日志[start]*************************************”)

Tboperatelog op = new Tboperatelog();

DateFormatsdf=new SimpleDateFormat( pattern:"yyy-MM-dd HH : mm : ss"〕;

op.setOperateTire ( sdf.format ( new Date ()));

op-setOperateUser ( "10000") ;

op.setOperateclass(pjp.getTarget().getClass() .getName());

op.setOperateMethod(pjp-getSignature ().getName (  ) ;

string paramAndValue = "";

object [] args = pip.getArgs( );

if(aras != nul1){

for(Object arg:args){

if(arg instanceof String ||arg instanceof Integr=er||arg instanceof Long){

paramAndValue+=arg+”,”;

}else{

paramAndValue+= JSON.toJSONString(arg)+”,”;

}

}

op.setParamAndValue(paramAndValue);

}

long start_time=System.currentTimeMillis();

//旅行

Object object =pjp.proceed();

long end_time=System.currentTimeMillis();

op.setCostTime(end_time-start_time);

if(object!=null){

op.setReturnClass(object.getClass().getName());

op.setReturnValue(object.toString());

}else{

op.setReturnClass(“java.lang.Object”);

op.setReturnValue(“void”);

}

operatLogFeign.add(op); //插入日志

system. out.println ( "******************************************

记录日志[end]****************************************”)

return object;

System.out.println(“”)

}

}

 

二、测试

在测试之前,因为用到了 Feign 的远程调用,需要在当前微服务中开启 Feign 这一块的支持,所以需要在 GoodsApplication.java 中加注解 ,如下:

@EnableFeignClients(basePackages=”cn.itcase.feign.client”)

接下来即可进行测试:

1.先启动 Eureka ,然后启动 log,最后启动 goods

log 和 goods 启动完成后,刷新 Eureka:

image.png

2.然后对日志记录流程进行测试:

(1)(绕过网关,网关没有启动)访问 DemoController

DemoController 代码:

@RestController

@RequestMapping ( " / demo")

public class DemoController {

@RequestMapping ( " / show")

@OperateLog

public string show ( ) {

return "OK";

}

}

由于在其中加了 OperateLog 注解,所以可以直接访问

(2)访问 goods 微服务,端口号为 9001

image.png

有断点出现,先放行,查看是否可以记录对应的日志信息

刷新数据库:

image.png

结果说明可以记录对应的日志信息。

(3)通过 Debugger 的形式跟踪具体流程:

在 Tboperatelog op = new Tboperatelog();

和 operatLogFeign.add(op); 处设置断点。

访问根据 id 查询 sku

找到根据 id 查询 sku 的链接然后执行

一访问就进入 op 的断点中:

image.png

向下运行,可以得到操作时间、操作类、操作方法以及操作的请求参

数。

Operatelog 目前参数的请求信息为:

image.png

当执行 ProceedingJoinPoint 方法时,会请求原始方法,放行让原始方法执行完。

原始方法执行完后,在 object 中封装了结果:
image.png

上面的结果就是原始方法返回的结果,得到该结果后就能得到运行耗时的时间以及返回值的类型、返回值,然后通过 Feign 去调用远程接口插入日志。

那么就得到了该日志:

image.png

image.png

至此,完成了插入日志的操作流程。

3.再测试一个:

之前得知上面的记录日志需要在方法上加 @OperateLog,只有加了才可以记录日志,但是方法 @PostMapping(" / search/ {pakge} / {size}")

没有加  @OperateLog,接下来测试该方法能否被拦截。

找到链接:

image.png

然后请求:

image.png

查看日志:

image.png

没有新增,说明被拦截,并没有记录日志。

所以想要记录日志只需要在方法上加注解 @OperateLog。

以同样的方式可以对 order 中的记录进行改造,如果 order 这个微服务想要记录日志。第一步是将 aop 的包直接拷贝,将包名改为 order。然后想要在引导类上加注解,该注解是:

@Mapperscan (basePackages = "cn . itcast.goods.mapper")

@EnableFeignclients(basePackages = "cn.itcast.feign.client")

开启 Feign 远程的调用,并且指定包扫描。

指定完后,我们的基本操作完成,如果想要去记录某一块日志,则只需要在方法前加 @OperateLog 这个注解即可正常的记录日志。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
1月前
|
存储 运维 数据可视化
如何为微服务实现分布式日志记录
如何为微服务实现分布式日志记录
67 1
|
3月前
|
PyTorch 算法框架/工具
Pytorch学习笔记(七):F.softmax()和F.log_softmax函数详解
本文介绍了PyTorch中的F.softmax()和F.log_softmax()函数的语法、参数和使用示例,解释了它们在进行归一化处理时的作用和区别。
537 1
Pytorch学习笔记(七):F.softmax()和F.log_softmax函数详解
|
2月前
|
消息中间件 存储 监控
微服务日志监控的挑战及应对方案
【10月更文挑战第23天】微服务化带来模块独立与快速扩展,但也使得日志监控复杂。日志作用包括业务记录、异常追踪和性能定位。
|
4月前
|
Prometheus Cloud Native Go
Golang语言之Prometheus的日志模块使用案例
这篇文章是关于如何在Golang语言项目中使用Prometheus的日志模块的案例,包括源代码编写、编译和测试步骤。
83 3
Golang语言之Prometheus的日志模块使用案例
|
5月前
|
jenkins 持续交付
jenkins学习笔记之三:使用jenkins共享库实现日志格式化输出
jenkins学习笔记之三:使用jenkins共享库实现日志格式化输出
jenkins学习笔记之三:使用jenkins共享库实现日志格式化输出
|
3月前
|
数据可视化
Tensorboard可视化学习笔记(一):如何可视化通过网页查看log日志
关于如何使用TensorBoard进行数据可视化的教程,包括TensorBoard的安装、配置环境变量、将数据写入TensorBoard、启动TensorBoard以及如何通过网页查看日志文件。
308 0
|
4月前
|
Shell Python
salt自定义模块内使用日志例子
salt自定义模块内使用日志例子
logging 日志 模块
logging 日志 模块
|
5月前
|
Go 开发者
【应用服务 App Service】App Service发生错误请求时,如何查看IIS Freb日志,从中得知错误所发生的模块,请求中所携带的Header信息
【应用服务 App Service】App Service发生错误请求时,如何查看IIS Freb日志,从中得知错误所发生的模块,请求中所携带的Header信息
|
5月前
|
数据挖掘 语音技术
3D-Speaker说话人任务的开源项目问题之语义说话人信息模块在说话人日志系统中的问题如何解决
3D-Speaker说话人任务的开源项目问题之语义说话人信息模块在说话人日志系统中的问题如何解决