美文网首页
spring-cloud微服务项目实战(8)-log4j2集成s

spring-cloud微服务项目实战(8)-log4j2集成s

作者: 爱编程的凯哥 | 来源:发表于2019-02-15 06:49 被阅读24次

目的

  1. 在log4j2的基础上集成sleuth,进行日志调用链跟踪,进行日志分析
  2. 改造项目接口,将原有/task/id,改成通过gateway-->client-->server的链子,方便测试,并同时改造原有gateway(参考上篇文章zuul实战)的验签方式

简介

在Peter Deutsch的《The Eight Fallacies of Distributed Computing》中指出八个分布式计算的误区:

  • 网络可靠
  • 延迟为零
  • 带宽无限
  • 网络绝对安全
  • 网络拓扑不会变
  • 必须有一个管理员
  • 传输成本为零
  • 网络同质化

总结下上述问题,重点出在网路问题。网络常常十分脆弱,而我们部署了微服务,系统变多,网络传输增多,对我们排查问题提出了挑战。sleuth的作用就是解决这个问题,进行调用跟踪,形成调用链,方便快速找出问题所在。
sleuth有几个专业术语:

  1. span(跨度):一次调用链每个应用的唯一id
  2. trace (跟踪):一次调用链所有应用共享的唯一id
  3. annotation (标注):记录事件,定义请求为止:
    • CS 客户端发送请求
    • SR 服务端收到请求
    • SS 服务处理完请求,发送返回信息
    • CR 客户端收到请求

开工

  1. 添加sleuth依赖
     <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
     </dependency>
  1. log4j2配置文件中添加sleuth配置,暂时还用的STDOUT模式,打印到控制台,方便测试,通过自定义sleuth参数[%X{X-B3-TraceId},%X{X-B3-SpanId},%X{X-B3-ParentSpanId},%X{X-Span-Export}]进行打印,其中TraceId为此次调用链共享id,SpanId本应用唯一id,ParentSpanId为上级应用唯一id,X-Span-Export是否是发送给Zipkin(后边我们将会用到,本章不讨论)
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">

    <Appenders>
        <File name="FileAppender" fileName="./log/logFile.log" append="true">
            <PatternLayout pattern="%d %-5p %c:%L [%t] - %m%n" />
        </File>

        <Console name="STDOUT" target="SYSTEM_OUT">
          //重点----自定义sleuth参数
             <PatternLayout pattern="%d [%X{X-B3-TraceId},%X{X-B3-SpanId},%X{X-B3-ParentSpanId},%X{X-Span-Export}] %-5p %c:%L [%t] - %m%n" />
        </Console>

        <RollingFile name="RollingFileInfo" fileName="./log/bee-client.log"
                     filePattern="./log/bee-client-gz/$${date:yyyy-MM}/bee-client-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <PatternLayout pattern="%d %-5p %c:%L [%t] - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="200 M"/>
            </Policies>
        </RollingFile>

    </Appenders>


    <Loggers>
        <Logger name="com.opensymphony.xwork2.ognl.OgnlValueStack" level="ERROR" />
        <Logger name="open.template" level="DEBUG" />
        <Logger name="org.springframework.cloud.netflix" level="DEBUG" />
        <Logger name="com.alisoft.xplatform.asf" level="WARN" />
        <Logger name="com.mbi" level="ERROR" />
        <Logger name="net.mlw" level="INFO" />
        <Logger name="java.sql" level="INFO" />
        <Logger name="org.hibernate.type" level="ERROR" />
        <Logger name="com.opensymphony.webwork" level="ERROR" />
        <Logger name="org.apache" level="INFO" />
        <Logger name="org.jgroups" level="WARN" />
        <Logger name="org.jboss.axis" level="INFO" />
        <Logger name="org.jboss.management" level="INFO" />
        <Logger name="org.apache.commons.httpclient" level="ERROR" />
        <Logger name="com.alibaba.dubbo" level="WARN" />
        <Logger name="com.mchange.v2.resourcepool" level="ERROR" />
        <Logger name="org.mybatis.spring" level="ERROR" />
        <Logger name="org.apache.ibatis" level="ERROR" />



        <Root level="INFO"><!-- 缺省日志级别,如果package有定制级别,则按package的定制级别走,即使package级别更低 -->
            <AppenderRef ref="STDOUT" />
            <!--<AppenderRef ref="FileAppender" />-->
            <!--<AppenderRef ref="RollingFileInfo" />-->
        </Root>

    </Loggers>
</Configuration>

  1. 改造gateway、udm-client、udm-server服务,同样的方法,集成sleuth,改造日志配置,在gateway路由规则中添加udm-client配置,进行链式测试
zuul:
#配置zuul统一前缀
  prefix: /api
#禁止所有eureka服务通过服务名直接访问
  ignored-services:
    "*"
  routes:
#将微服务需要暴露服务进行路由映射
    udm-server: /udm/**
    udm-client: /udc/**
  1. 改造gateway验签,暂时替换为md5方式,首先在commons中添加md5工具类
public class Md5Sign {

    public static String sign(String s) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(s.getBytes("utf-8"));
            return toHex(bytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    private static String toHex(byte[] bytes) {
        final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
        StringBuilder ret = new StringBuilder(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
            ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
        }
        return ret.toString();
    }

   public static void main(String[] args) {
        StringBuffer stringBuffer=new StringBuffer();
        stringBuffer.append("ddd");
        stringBuffer.append("sdfadflakjsfd;aljfda;dkfja;dfk");
        String sign = sign(stringBuffer.toString());
        System.out.println(sign);
    }
}

然后修改gateway项目中添加feign依赖,用于调用获取用户信息方法,添加对应service

//添加pom依赖
  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
  </dependency>
......
//启动类添加feign扫包
@SpringBootApplication
@EnableZuulProxy
@EnableFeignClients(basePackages = "open.template.work.gateway.service")
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }

}
......
//添加接口service
@FeignClient(name = CloudServerDirectory.UDM_SERVER)
public interface AuthorizationService {

    /**
     * 调用获取用户密钥
     * @param appKey
     * @return
     */
    @RequestMapping("/user/key")
    String getUserKey(String appKey);

}

最后在AuthorizationFilter中注入此AuthorizationService,并修改run方法

   @Override
    public Object run() {
        RequestContext currentContext = RequestContext.getCurrentContext(); // 获取当前请求的上下文
        Map<String, Object> params = null;
        try {
            //1.获取请求参数,支持json格式数据,通过inputstream解析数据
            try {
                params = HttpParser.requestJsonParser(currentContext.getRequest().getInputStream());

            } catch (IOException e) {
                throw new BaseTemplateException(ExceptionCodeEnum.Z88888);
            }

            LOGGER.info("获取授权参数data={}", params);

            //2.通过md5验签,生产环境可以根据需求调整更复杂的算法,为了测试简单暂时通过客户端的treemap进行排序,将所有参数生成字符串,然后拼接用户密钥
            //生成md5作为签名
            if (params.get("appKey") != null) {
                String key = authorizationService.getUserKey(params.get("appKey").toString());
                if (StringUtils.isEmpty(key)) {
                    throw new BaseTemplateException(ExceptionCodeEnum.Z88887);
                }

                Object sign = params.get("sign");
                if (sign == null) {
                    throw new BaseTemplateException(ExceptionCodeEnum.Z88888);
                }

                StringBuffer stringBuffer = new StringBuffer();
                Set<String> paramsSet = params.keySet();
                for (String param : paramsSet) {
                    if (!param.equals("sign")) {
                        stringBuffer.append(params.get(param));
                    }
                }
                //本地加签
                String localSign = Md5Sign.sign(stringBuffer.append(key).toString());
                if (!localSign.equals(sign)) {
                    throw new BaseTemplateException(ExceptionCodeEnum.Z88888);
                }

            }
        } catch (BaseTemplateException e) {
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseStatusCode(200);
            currentContext.setResponseBody("{\"result \":\""+e.getMessage()+"\"}");
            currentContext.getResponse().setContentType("text/html;charset=UTF-8");
        }

        return null;

    }
  1. udm-server添加模拟获取用户密钥信息接口
@RestController
public class UserApi {

    /**
     * 根据appKey获取用户密钥
     * @param appKey
     * @return
     */
    @RequestMapping("/user/key")
    public String getUserKey(String appKey){
        return "sdfadflakjsfd;aljfda;dkfja;dfk";
    }
}
  1. 重启相应服务,通过curl模拟json格式post请求(因为参数中有对象参数,索所以需要requestBody注解,必须post的请求,其中sign参数通过md5多工具类生成),查看日志
    curl -H "Content-Type:application/json" -X POST --data '{"appKey":"ddd","sign":"6CBC57C961FCA12D89FB724400E87326"}' http://localhost:8061/api/udm/task/get
1.gateway日志 2. udm-server获取用户信息日志 3.udm-client调用日志 4. udm-server接受udm-client请求日志

完工!

相关文章

网友评论

      本文标题:spring-cloud微服务项目实战(8)-log4j2集成s

      本文链接:https://www.haomeiwen.com/subject/lucmsqtx.html