apache / skywalking

APM, Application Performance Monitoring System
https://skywalking.apache.org/
Apache License 2.0
23.72k stars 6.5k forks source link

spring-cloud-gateway traceid does not transmit #3411

Closed csullh closed 5 years ago

csullh commented 5 years ago

Please answer these questions before submitting your issue.

Bug

wu-sheng commented 5 years ago

@zhaoyuguang any idea why?

zhaoyuguang commented 5 years ago

Please answer these questions before submitting your issue.

  • Why do you submit this issue? Bug

Bug

  • Which version of SkyWalking, OS and JRE? SkyWalking 6.4.0-SNAPSHOT jdk1.8
  • What happen? when i compile the master branch code ,use the agent and the plugin(apm-spring-cloud-gateway-2.x-plugin-6.4.0-SNAPSHOT), the gateway traceid does not transmit. the gateway generated traceid like 521.95.15675761632140001,but the service generated traceid like 522.59.15675761646250001.

Hi @csullh Can you provide a demo, order to recreate the scene.

csullh commented 5 years ago

how provide a demo?

csullh commented 5 years ago

this is my gateway demo code : package cn.swt;

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient @SpringBootApplication public class GatewayApplication {

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

}

this is my demo pom.xml <?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">

4.0.0
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.4.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.swt</groupId>
<artifactId>gw-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
    <java.version>1.8</java.version>
    <!--<spring-cloud.version>Greenwich</spring-cloud.version>-->
    <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
    <spring-cloud-alibaba.version>0.2.2.RELEASE</spring-cloud-alibaba.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>

    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>

    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>

    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.springframework.cloud spring-cloud-alibaba-dependencies ${spring-cloud-alibaba.version} pom import org.springframework.boot spring-boot-dependencies 2.1.4.RELEASE pom import
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

csullh commented 5 years ago

<?xml version="1.0" encoding="UTF-8"?>

4.0.0
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.4.RELEASE</version>
</parent>
<groupId>cn.swt</groupId>
<artifactId>gw-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
    <spring-cloud-alibaba.version>0.2.2.RELEASE</spring-cloud-alibaba.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>

    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>

    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>

    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.springframework.cloud spring-cloud-alibaba-dependencies ${spring-cloud-alibaba.version} pom import org.springframework.boot spring-boot-dependencies 2.1.4.RELEASE pom import
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

csullh commented 5 years ago

the same demo ,i use 6.3.0 agent ,the traceid can transmit,when i use the compiled new version( 6.4.0-SNAPSHOT),the gateway generated traceid and do not transmit,the service generated new traceid.

zhaoyuguang commented 5 years ago

@csullh Thank you for using and testing the master branch code. Can you use pull the master code, compiled and test again. At the same time, debug at NettyRoutingFilter::filter

csullh commented 5 years ago

@zhaoyuguang ,I have already pull the master code, compiled and test again. this time,the traceid can transmit,but I found another bug,if I add a filter in my gateway,the traceid does not transmit again.

this is my filter code:

@Component public class GrayFilter implements GlobalFilter, Ordered {

private static final Logger log = LoggerFactory.getLogger( GrayFilter.class );

private static final String APPID = "appid";
//@Autowired
//private GrayConfig grayConfig;

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

    System.out.println("traceid="+ TraceContext.traceId());

    //System.out.println("config gray appid======"+grayConfig.getGrayAppid());
    ServerHttpRequest request = exchange.getRequest();

    boolean  result=isGrayRequest(request);

    if(result) {
        //.getQueryParams().add("gray", "true");
        log.info( "add header gray true..." );
        //RibbonFilterContextHolder.getCurrentContext().add("gray", "true");
        //给请求头添加灰度标标
        ServerHttpRequest newRequest = request.mutate().header("gray",String.valueOf("true")).build();
        ServerWebExchange nExchange = exchange.mutate().request(newRequest).build();
        return chain.filter(nExchange);
    }else{
        log.info( "add header gray false..." );
        //RibbonFilterContextHolder.getCurrentContext().add("gray", "false");
        ServerHttpRequest newRequest = request.mutate().header("gray",String.valueOf("false")).build();
        ServerWebExchange nExchange = exchange.mutate().request(newRequest).build();
        return chain.filter(nExchange);
    }
}

in this code ,I changed the request, so the traceid dose not transmit again.

wu-sheng commented 5 years ago

If you are manipulating header by yourself, then it is your responsibility to propagate skywalking's header. key is sw6.

csullh commented 5 years ago

can you provide a demo? I do not konw how propagate skywalking's header in my filter.

wu-sheng commented 5 years ago

There is no skywalking demo. We do that in the plugin. Which filter is this, upstream request filter?

csullh commented 5 years ago

I write a springcloud gateway filter, like this :

public class GrayFilter implements GlobalFilter, Ordered { private static final Logger log = LoggerFactory.getLogger( GrayFilter.class );

@Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { if(result) {

    ServerHttpRequest newRequest = request.mutate().header("gray",String.valueOf("true")).build();
    ServerWebExchange nExchange = exchange.mutate().request(newRequest).build();
    return chain.filter(nExchange);
}else{

    ServerHttpRequest newRequest = request.mutate().header("gray",String.valueOf("false")).build();
    ServerWebExchange nExchange = exchange.mutate().request(newRequest).build();
    return chain.filter(nExchange);
}

}

I think the traceid should be transmit by the springcloud gateway plugin,but is does not work. how propagate skywalking's header is my code?

hi-sb commented 5 years ago

I had the same problem. Waiting...

hi-sb commented 5 years ago

@csullh Have you solved it?

csullh commented 5 years ago

@hi-sb,I am trying. I found if my filter working,the header 'sw6' will lost. if I disable my filter, ,the header 'sw6' have value.I think if I do not modify the plugin, I must be import skywalking6 api in my filter to manually set the header 'sw6' .

hi-sb commented 5 years ago

@csullh Did you get the header information he transmitted? Can you write it in the comments?

csullh commented 5 years ago

@hi-sb, I found I can not transmit the traceid even I set header 'sw6' like '1-NjAzLjg2LjE1Njc3NTUzMDQ4NzEwMDAx-NjAzLjk1LjE1Njc3NTUzMDU3MTQwMDAw-0-603-603-xxxxxxx'.

csullh commented 5 years ago

@zhaoyuguang, can you give any idea to solved it? in my gateway , I use a filter,the traceid can not transmit.

hi-sb commented 5 years ago

@csullh It looks like a string connected by'-'characters. Among them, some things are coded by base64.

wu-sheng commented 5 years ago

@csullh Please don't separate the discussion in different places, like #3427. We will miss the context. You are listing the right header of skywalking, we don't have any mechanism to ignore him, so if this lost, trace breaks. Need to dig more about what happens when this filter works.

zhaoyuguang commented 5 years ago

@zhaoyuguang, can you give any idea to solved it? in my gateway , I use a filter,the traceid can not transmit.

Debug at NettyRoutingFilter::filter and see the real implementation class of exchange and find where is the location of Asyncspan.

zhaoyuguang commented 5 years ago

@zhaoyuguang ,I have already pull the master code, compiled and test again. this time,the traceid can transmit,but I found another bug,if I add a filter in my gateway,the traceid does not transmit again.

this is my filter code:

@component public class GrayFilter implements GlobalFilter, Ordered {

private static final Logger log = LoggerFactory.getLogger( GrayFilter.class );

private static final String APPID = "appid";
//@Autowired
//private GrayConfig grayConfig;

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

    System.out.println("traceid="+ TraceContext.traceId());

    //System.out.println("config gray appid======"+grayConfig.getGrayAppid());
    ServerHttpRequest request = exchange.getRequest();

    boolean  result=isGrayRequest(request);

    if(result) {
        //.getQueryParams().add("gray", "true");
        log.info( "add header gray true..." );
        //RibbonFilterContextHolder.getCurrentContext().add("gray", "true");
        //给请求头添加灰度标标
        ServerHttpRequest newRequest = request.mutate().header("gray",String.valueOf("true")).build();
        ServerWebExchange nExchange = exchange.mutate().request(newRequest).build();
        return chain.filter(nExchange);
    }else{
        log.info( "add header gray false..." );
        //RibbonFilterContextHolder.getCurrentContext().add("gray", "false");
        ServerHttpRequest newRequest = request.mutate().header("gray",String.valueOf("false")).build();
        ServerWebExchange nExchange = exchange.mutate().request(newRequest).build();
        return chain.filter(nExchange);
    }
}

in this code ,I changed the request, so the traceid dose not transmit again.

Very thanks your demo, I will use it to reproduce the case.

hi-sb commented 5 years ago

@csullh I modified the plug-in's code and solved the problem after compiling it locally. If you want to try it too, this is my "NettyRoutingFilterInterceptor":

`public class NettyRoutingFilterInterceptor implements InstanceMethodsAroundInterceptor {

private static final String SPRING_CLOUD_GATEWAY_ROUTE_PREFIX = "GATEWAY/";

@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
                         MethodInterceptResult result) throws Throwable {
    if (objInst != null) {
        ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
        AbstractSpan span =ContextManager.activeSpan();
        String operationName = SPRING_CLOUD_GATEWAY_ROUTE_PREFIX;
        if (span != null) {
            Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
            operationName = operationName + route.getId();
            span.setOperationName(operationName);
            SWTransmitter transmitter = new SWTransmitter(span.prepareForAsync(), ContextManager.capture(), operationName);
            ContextManager.stopSpan(span);
            ContextManager.getRuntimeContext().put(Constants.SPRING_CLOUD_GATEWAY_TRANSMITTER, transmitter);
        }
    }
}

@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
                          Class<?>[] argumentsTypes, Object ret) throws Throwable {
    if (ContextManager.getRuntimeContext().get(Constants.SPRING_CLOUD_GATEWAY_TRANSMITTER) != null) {
        ContextManager.getRuntimeContext().remove(Constants.SPRING_CLOUD_GATEWAY_TRANSMITTER);
    }
    return ret;
}

@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
                                  Class<?>[] argumentsTypes, Throwable t) {
}

} `

hi-sb commented 5 years ago

@wu-sheng Please see if it's the right way. ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

wu-sheng commented 5 years ago

@hi-sb Could you send a pull request? That is better to review. And maybe a good start to being a member of our contributor team.

csullh commented 5 years ago

@hi-sb,I try it and it works correctly.

zhaoyuguang commented 5 years ago

@csullh @hi-sb I add the filter like

@Component
public class GrayFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpRequest newRequest = request.mutate().header("gray", "true").build();
        ServerWebExchange nExchange = exchange.mutate().request(newRequest).build();
        return chain.filter(nExchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

but I can recreate problem as your said.

image

hi-sb commented 5 years ago

------------------ 原始邮件 ------------------ 发件人: "于玉桔"notifications@github.com; 发送时间: 2019年9月9日(星期一) 下午2:41 收件人: "apache/skywalking"skywalking@noreply.github.com; 抄送: "1922327128"1922327128@qq.com;"Mention"mention@noreply.github.com; 主题: Re: [apache/skywalking] spring-cloud-gateway traceid does nottransmit (#3411)

@csullh @hi-sb I add the filter like @Component public class GrayFilter implements GlobalFilter, Ordered { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); ServerHttpRequest newRequest = request.mutate().header("gray", "true").build(); ServerWebExchange nExchange = exchange.mutate().request(newRequest).build(); return chain.filter(nExchange); } @Override public int getOrder() { return 0; } }

but I can recreate problem as your said.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

csullh commented 5 years ago

@hi-sb,@zhaoyuguang Until just now,In the new version(NettyRoutingFilterInterceptor) I found the code can work correctly. And in the next service ,I can also receive and print the header 'sw6' correctly. In the old version,the traceid can not transmit.

hnsongbiao commented 11 months ago

,how to resolve this problem?

wu-sheng commented 11 months ago

@hnsongbiao One last warning, if you keep sending things everywhere, you will be blocked. Be polite and be patient. Open source community doesn't have obligation for your private deployment or use case.