框架改造之添加请求链路到请求头

726 阅读3分钟

如题,也许有人觉得做这个有点多此一举,但是个人感觉这个的必要性还是有的。不为别的就为了省那么几秒中的查找时间。总体对微服务开发调试上就会有一些微小的提升那也是方便开发小伙伴的一种优化,好的框架就是这么一点一滴的优化过来的。废话不多说,先谈谈总体思路最后给个实现。 1、首先要对头部进行操作我们可以在拦截器或者过滤器中动手脚 2、需要获取到skywalking的服务地址以及traceId 思路就是这两步看着就很简单

show your code maven依赖,包头请随意

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>omsa-all</artifactId>
        <groupId>com.qimo</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.qimo.trace</groupId>
    <artifactId>omsa-trace</artifactId>
    <packaging>jar</packaging>
    <dependencies>
    	<!-- trace相关包 -->
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-trace</artifactId>
            <version>8.2.0</version>
        </dependency>
        <!-- trace和logback整合的包-->
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-logback-1.x</artifactId>
            <version>8.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.5.RELEASE</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>
        <!--配置提示生成包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <version>2.1.3.RELEASE</version>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

定义属性oap_ui的地址skywalkingUrl

package com.qimo.trace;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @Description TODO
 * @Author 姚仲杰#80998699
 * @Date 2021/6/20 23:51
 */
@ConfigurationProperties(prefix = "omsa.trace")
public class OmsaTraceProperties {
    
    private String skywalkingUrl="http://";
    
    public String getSkywalkingUrl() {
        return skywalkingUrl;
    }
    
    public void setSkywalkingUrl(String skywalkingUrl) {
        this.skywalkingUrl = skywalkingUrl;
    }
}

定义拦截器往头部塞traceId和skywalkingUrl拼接的地址最后效果是这样http://127.0.0.1:10800/trace?traceId=0a0cb455e8bf44718a70589e5818d5f9.66.16242401437190001

package com.qimo.trace;

import com.qimo.trace.configuration.OmsaTraceConst;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
 * @Description TODO
 * @Author 姚仲杰#80998699
 * @Date 2021/6/20 23:36
 */
public class OmsaTraceHeaderInterceptor extends HandlerInterceptorAdapter {
    
    @Autowired
    OmsaTraceProperties omsaTraceProperties;
    
    public OmsaTraceHeaderInterceptor() {
        super();
    }
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
        Object handler) throws Exception {
        String traceId=TraceContext.traceId();
        if (StringUtils.isEmpty(traceId)){
            traceId=OmsaTraceConst.NULL_TRACE_ID;
        }
        response.setHeader(OmsaTraceConst.OMSA_TRACE_VISIT_URL_KEY, omsaTraceProperties.getSkywalkingUrl().replace("@{traceId}",traceId));
        return true;
    }
    
}

以上代码已经将功能完整写完了,剩下就是bean的加载了 我们这里使用一个@Enable*加载这个包的功能 1、声明注解

package com.qimo.trace.annotation;

import com.qimo.trace.OmsaTraceProperties;
import com.qimo.trace.configuration.OmsaTraceConfigurationImportSelector;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Import;

/**
 * @Description TODO
 * @Author 姚仲杰#80998699
 * @Date 2021/6/21 0:20
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableOmsaTrace {
    
    String[] includePatterns() default {"/**/**"};
    
    String[] excludePatterns() default {"/**/*.js", "/**/*.css", "/**/*.html"};

    
}

2、编写registrar配置bean

package com.qimo.trace.configuration;

import com.qimo.trace.annotation.EnableOmsaTrace;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.web.servlet.handler.MappedInterceptor;

/**
 * @Description TODO
 * @Author 姚仲杰#80998699
 * @Date 2021/6/21 0:23
 */
public class OmsaTraceBeanRegistrar implements ImportBeanDefinitionRegistrar {
    
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        String[] includePatterns = getAnnotationAttributesValue(importingClassMetadata, "includePatterns");
        String[] excludePatterns = getAnnotationAttributesValue(importingClassMetadata, "excludePatterns");
    
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(MappedInterceptor.class);
    
        beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, includePatterns);
        beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(1, excludePatterns);
        beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(2, new RuntimeBeanReference(
            OmsaTraceConst.OMSA_TRACE_HEADER_INTERCEPTOR_BEAN_NAME));
        BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
    }
    
    private String[] getAnnotationAttributesValue(AnnotationMetadata metadata, String attribute) {
        
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
            metadata.getAnnotationAttributes(EnableOmsaTrace.class.getName()));
        
        String[] basePackages = attributes.getStringArray(attribute);
        
        return basePackages;
    }
}

3、编写Configuration配置bean

package com.qimo.trace.configuration;

import com.qimo.trace.OmsaTraceHeaderInterceptor;
import org.springframework.context.annotation.Bean;

/**
 * @Description TODO
 * @Author 姚仲杰#80998699
 * @Date 2021/6/20 23:57
 */
public class OmsaTraceConfiguration {
    
    @Bean(OmsaTraceConst.OMSA_TRACE_HEADER_INTERCEPTOR_BEAN_NAME)
    public OmsaTraceHeaderInterceptor omsaTraceHeaderInterceptor(){
        return new OmsaTraceHeaderInterceptor();
    }
}

4、编写selectort收集需要加载的bean

package com.qimo.trace.configuration;

import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @Description TODO
 * @Author 姚仲杰#80998699
 * @Date 2021/6/21 0:22
 */
public class OmsaTraceConfigurationImportSelector implements ImportSelector {
    
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        List<String> importList=new ArrayList<String>();
        importList.add(OmsaTraceConfiguration.class.getName());
        importList.add(OmsaTraceBeanRegistrar.class.getName());
        return importList.toArray(new String[importList.size()]);
    }
}

修改注解导入selector和properties

package com.qimo.trace.annotation;

import com.qimo.trace.OmsaTraceProperties;
import com.qimo.trace.configuration.OmsaTraceConfigurationImportSelector;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Import;

/**
 * @Description TODO
 * @Author 姚仲杰#80998699
 * @Date 2021/6/21 0:20
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@EnableConfigurationProperties(OmsaTraceProperties.class)
@Import(OmsaTraceConfigurationImportSelector.class)
@Documented
public @interface EnableOmsaTrace {
    
    String[] includePatterns() default {"/**/**"};
   	
    String[] excludePatterns() default {"/**/*.js", "/**/*.css", "/**/*.html"};

    
}

打包发布,然后建个相关demo项目,当然同时你还得具备skywalking服务端和agent,很简单直接从dockerhub拉取一个,以上包用的版本是8.2.0那我直接拉取一个8.2.0的服务端,直接使用docker-compose吧。

version: "3.1"
services:
  oap:
    image: apache/skywalking-oap-server:8.2.0-es7
    restart: always
    ports:
      - 11800:11800
      - 12800:12800
  oap_ui:
    image: apache/skywalking-ui:8.2.0
    restart: always
    environment:
      SW_OAP_ADDRESS: "oap:12800"
    ports:
      - 10800:8080

再起个springboot-demo项目引入当前包,在启动类上注解个@EnableOmsaTrace 试试看

@SpringBootApplication
@EnableOmsaTrace
public class OmsaDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(OmsaDemoApplication.class,args);
    }

当然还需要配置logback因为我们这里只做了logback,你如果要用其它日志框架需要将最上面的依赖包换层相关的框架依赖 logback-spring配置如下:随便摘抄了一份。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <jmxConfigurator/>
    <property name="log_pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS Z} [%tid] [%thread] %-5level %logger{50}:%line %msg%n"></property>
    <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
        <!--编码-->
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <!--展示格式-->
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <pattern>${log_pattern}</pattern>
            </layout>
        </encoder>
    </appender>
    <appender name="fileLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--编码-->
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <!--展示格式-->
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <pattern>${log_pattern}</pattern>
            </layout>
        </encoder>
        <!--滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--路径 -->
            <fileNamePattern>log/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!--超过100M分文件-->
            <maxFileSize>100MB</maxFileSize>
        </rollingPolicy>
    </appender>
    <!--指定最基础的日志输出级别-->
    <root level="info">
        <appender-ref ref="consoleLog"/>
        <appender-ref ref="fileLog"/>
    </root>
</configuration>

写个简单controller

package com.qimo.omsa.demo.trace;

import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Description TODO
 * @Author 姚仲杰#80998699
 * @Date 2021/6/21 1:18
 */
@RestController
public class TraceTestController {
    Logger log= LoggerFactory.getLogger(TraceTestController.class);
    
    @GetMapping("/trace")
    public String trace(){
        log.info(TraceContext.traceId());
        return TraceContext.traceId();
    }
}

application.properties中配置上你的skywalking地址

server.port=7777
logging.level.root=info
omsa.trace.skywalking-url=http://127.0.0.1:10800/trace?traceId=@{traceId}

访问效果如下 在这里插入图片描述 复制链接直接访问 在这里插入图片描述