美文网首页
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