Пользовательский перехватчик журналов Dubbo

задняя часть

предисловие

предыдущий пост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Полное имя пакета перехватчика.

Наконец, добавьте конфигурацию в файл конфигурации поставщика услуг, чтобы перехватчик заработал:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      ...省略部分代码">

    <!--服务提供方应用信息,用于计算依赖关系-->
    <dubbo:application name="easywits-upms-rpc-service"/>

    <!--用dubbo协议在20881端口暴露服务-->
    <dubbo:protocol name="dubbo" port="20881" payload="52428800"/>

    <!--自定义服务层过滤器,值为上述步骤文本文件中的键-->
    <dubbo:provider filter="dubboServiceFilter"/>
    
    ....省略部分服务配置
</beans>

Результаты проверки

Возьмите некоторую информацию журнала в нашем бизнесе, чтобы увидеть эффект, как показано ниже:

ясно видноDubboИнформация о параметрах запроса вызова интерфейса службы и информация об окончательном результате ответа удобны для обнаружения онлайн-проблем.

Справочная документация:http://dubbo.apache.org/zh-cn/docs/dev/impls/filter.html

Наконец

Запишите относительно простую конкретную практическую сцену и время от времени обновляйте более практические сцены в будущем Добро пожаловать, чтобы обратить внимание на общедоступный аккаунт [Чжан Шаолинь]!