资讯专栏INFORMATION COLUMN

Dubbo自定义日志拦截器

meteor199 / 2431人阅读

摘要:前言上一篇文章自定义注解统一记录用户行为日志记录了层中通过自定义注解配合自动记录用户行为日志的过程。那么按照分布式架构中服务层的调用过程是否也可以实现统一记录日志自定义日志拦截器可以实现这个需求。

前言

上一篇文章 Spring aop+自定义注解统一记录用户行为日志 记录了 web层中通过自定义注解配合Spring aop自动记录用户行为日志的过程。那么按照分布式架构中Dubbo服务层的调用过程是否也可以实现统一记录日志?自定义日志拦截器可以实现这个需求。

需求场景

在使用Dubbo搭建的分布式项目中,服务层代码调用是这样的:

     @GetMapping(value = "/info")
2    public BaseResult userInfo() {
3        //rpc远程调用用户服务
4        BaseResult result = mUserService.userInfo();
6        return result;
7    }

这里的用户服务位于另外一个服务进程,由服务提供者暴露出来,让web层远程调用,需要记录服务结果的调用过程,便于跟踪定位bug.

自定义日志拦截器

翻看下Dubbo官方文档,可以看到如下内容:

简要说明:

Dubbo 中所有的拦截器全部继承自org.apache.dubbo.rpc.Filter接口,我们自己也可以自行扩展,只要继承该接口即可.

用户自定义 filter 默认在内置 filter 之后执行

新增 DubboServiceFilter 拦截器如下:

public class DubboServiceFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(DubboServiceFilter.class);

    @Override
    public Result invoke(Invoker invoker, Invocation invocation) throws RpcException {
        //外部日志开关默认关闭
        String logSwitch = StringUtils.equals(RedisUtil.get(BaseConstants.CACHE_SERVICE_LOG_SWITCH), BaseConstants.YES) ? BaseConstants.YES : BaseConstants.NO;
        if (StringUtils.equals(BaseConstants.YES, logSwitch)) {
            //打印入参日志
            DubboServiceRequest serviceRequest = new DubboServiceRequest();
            serviceRequest.setInterfaceName(invocation.getInvoker().getInterface().getName());
            serviceRequest.setMethodName(invocation.getMethodName());
            serviceRequest.setArgs(invocation.getArguments());
            LOGGER.info("dubbo服务接口入参: " + JSON.toJSONString(serviceRequest));
        }
        //开始时间
        long startTime = System.currentTimeMillis();
        //执行接口调用逻辑
        Result result = invoker.invoke(invocation);
        //调用耗时
        long elapsed = System.currentTimeMillis() - startTime;
        //如果发生异常 则打印异常日志
        if (result.hasException() && invoker.getInterface() != GenericService.class) {
            LOGGER.error("dubbo执行异常: ", result.getException());
        } else {
            if (StringUtils.equals(BaseConstants.YES, logSwitch)) {
                //打印响应日志
                DubboServiceResponse serviceResponse = new DubboServiceResponse();
                serviceResponse.setMethodName(invocation.getMethodName());
                serviceResponse.setInterfaceName(invocation.getInvoker().getInterface().getName());
                serviceResponse.setArgs(invocation.getArguments());
                serviceResponse.setResult(new Object[]{result.getValue()});
                serviceResponse.setSpendTime(elapsed);
                LOGGER.info("dubbo服务响应成功,返回数据: " + JSON.toJSONString(serviceResponse));
            }
        }
        //返回结果响应结果
        return result;
    }
}

代码中对应的实体bean如下:

入参实体:

/**
 * @program: easywits
 * @description:Dubbo服务请求入参实体
 * @author: zhangshaolin
 * @create: 2019-01-08 20:35
 **/
@Data
public class DubboServiceRequest implements Serializable{
    private static final long serialVersionUID = 7127824956842786618L;

    /**
     * 接口名
     */
    private String interfaceName;

    /**
     * 方法名
     */
    private String methodName;

    /**
     * 参数
     */
    private Object[] args;
}

响应实体:

/**
 * @program: easywits
 * @description: Dubbo服务响应结果实体
 * @author: zhangshaolin
 * @create: 2019-01-08 20:36
 **/
@Data
public class DubboServiceResponse implements Serializable{
    private static final long serialVersionUID = -2531169660859647737L;

    /**
     * 接口名
     */
    private String interfaceName;

    /**
     * 方法名
     */
    private String methodName;

    /**
     * 参数
     */
    private Object[] args;

    /**
     * 返回结果
     */
    private Object result;

    /**
     * 调用耗时(毫秒)
     */
    private long spendTime;
}

/src/main/resources/META-INF/dubbo目录下新增纯文本文件org.apache.dubbo.rpc.Filter 内容为:

dubboServiceFilter=com.easywits.common.filter.DubboServiceFilter

键值对形式,键随便起个名字

值为DubboServiceFilter拦截器的完整包名.

最后在服务提供者配置文件中添加配置使拦截器生效:




    
    

    
    

    
    
    
    ....省略部分服务配置
验证结果

抓一下我们业务中的部分日志信息看下效果,如下图:

可以清楚地看到Dubbo服务接口调用的请求参数信息,以及最终的响应结果信息,便于定位线上问题。

参考文档:http://dubbo.apache.org/zh-cn/docs/dev/impls/filter.html

最后

记录一个比较简单的具体实用场景,后续会不定期更新更多的实用场景,欢迎关注公众号【张少林同学】!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72894.html

相关文章

  • Dubbo 定义异常,你是怎么处理的?

    摘要:前言记录对于自定义异常的处理方式实现目标服务层异常,直接向上层抛出,层统一捕获处理如果是系统自定义异常,则返回其中对应为错误码,对应为异常信息如果非系统自定义异常,返回未知错误,同时将异常堆栈信息输出到日志便于定位问题项目架构先来张系统架 showImg(https://segmentfault.com/img/remote/1460000017782781?w=768&h=506);...

    dingding199389 评论0 收藏0
  • 马蜂窝大交通业务监控报警系统架构设计与实现

    摘要:为了让大交通下的各业务线都能够通过报警尽早发现问题解决问题,进而提升业务系统的服务质量,我们决定构建统一的监控报警系统。本文主要介绍马蜂窝大交通业务监控报警系统的定位整体架构设计,以及我们在落地实践过程中的一些踩坑经验。 部门的业务线越来越多,任何一个线上运行的应用,都可能因为各种各样的原因出现问题:比如业务层面,订单量比上周减少了,流量突然下降了;技术层面的问题,系统出现 ERROR...

    smartlion 评论0 收藏0
  • dubbo源码解析(四十六)消费端发送请求过程

    摘要:可以参考源码解析二十四远程调用协议的八。十六的该类也是用了适配器模式,该类主要的作用就是增加了心跳功能,可以参考源码解析十远程通信层的四。二十的可以参考源码解析十七远程通信的一。 2.7大揭秘——消费端发送请求过程 目标:从源码的角度分析一个服务方法调用经历怎么样的磨难以后到达服务端。 前言 前一篇文章讲到的是引用服务的过程,引用服务无非就是创建出一个代理。供消费者调用服务的相关方法。...

    fish 评论0 收藏0
  • 聊聊Dubbo - Dubbo可扩展机制实战

    摘要:今天我想聊聊的另一个很棒的特性就是它的可扩展性。的扩展机制在的官网上,描述自己是一个高性能的框架。接下来的章节中我们会慢慢揭开扩展机制的神秘面纱。扩展扩展点的实现类。的定义在配置文件中可以看到文件中定义了个的扩展实现。 摘要: 在Dubbo的官网上,Dubbo描述自己是一个高性能的RPC框架。今天我想聊聊Dubbo的另一个很棒的特性, 就是它的可扩展性。 Dubbo的扩展机制 在Dub...

    techstay 评论0 收藏0
  • 聊聊Dubbo - Dubbo可扩展机制源码解析

    摘要:什么是类那什么样类的才是扩展机制中的类呢类是一个有复制构造函数的类,也是典型的装饰者模式。代码如下有一个参数是的复制构造函数有一个构造函数,参数是扩展点,所以它是一个扩展机制中的类。 摘要: 在Dubbo可扩展机制实战中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现,并自己实现了一个LoadBalance。是不是觉得Dubbo的扩展机制很不错呀...

    lmxdawn 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<