log

loggerId 标识线程调用链

loggerId 标识线程调用链

Posted by lijian on May 21, 2020

添加 filter 拦截请求并生成放入loggerId


import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.UUID;

/**
 * @author lijian@jovision.com
 * @date 2020/8/11
 **/
@Slf4j
public class LoggerIdFilter implements Filter {

    public static final String LOGGER_ID = "logger_id";

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            String loggerId = httpServletRequest.getHeader(LOGGER_ID);
            if (StringUtils.isEmpty(loggerId)) {
                loggerId = MDC.get(LOGGER_ID);
                if (StringUtils.isEmpty(loggerId)) {
                    loggerId = UUID.randomUUID().toString().replace("-", "");
                }
            }
            MDC.put(LOGGER_ID, loggerId);
            chain.doFilter(request, response);
        } finally {
            MDC.remove(LOGGER_ID);
        }
    }
}

将 LoggerIdFilter 纳入容器


import com.jovision.vpass.pms.common.filter.LoggerIdFilter;
import com.jovision.vpass.pms.common.filter.ThreadLocalClearFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;

import javax.servlet.DispatcherType;

/**
 * @author lijian@jovision.com
 * @date 2020/8/10
 **/
@Configuration
public class SpringConfig {

    @Bean
    public FilterRegistrationBean logIdFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new LoggerIdFilter());
        registration.addUrlPatterns("/*");
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
        registration.setName("logIdFilter");
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        return registration;
    }
}

重写 feign hystrix 的调用策略


import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

import java.util.Map;
import java.util.concurrent.Callable;

/**
 * 跨服务loggerId 传递
 *
 * @author lijian@jovision.com
 * @date 2020/8/24
 **/
@Slf4j
public class HystrixConcurrencyStrategyCustome extends HystrixConcurrencyStrategy {

    @Override
    public <T> Callable<T> wrapCallable(final Callable<T> callable) {
        final Map context = MDC.getCopyOfContextMap();

        return () -> {
            Map<String, String> original = MDC.getCopyOfContextMap();
            if (context != null) {
                MDC.setContextMap(context);
            } else {
                MDC.clear();
            }
            try {
                return callable.call();
            } catch (Exception e) {
                log.error("HttpCallCommand call failed.", e);
                return null;
            } finally {
                if (original != null) {
                    MDC.setContextMap(original);
                } else {
                    MDC.clear();
                }
            }
        };

    }
}

使用自定义的 hystrix 调用策略


@Slf4j
@Configuration
public class FeignConfig {

    @PostConstruct
    public void init() {
        try {
            HystrixConcurrencyStrategyCustome target = new HystrixConcurrencyStrategyCustome();
            HystrixConcurrencyStrategy strategy = HystrixPlugins.getInstance().getConcurrencyStrategy();
            if (strategy instanceof HystrixConcurrencyStrategyCustome) {
                // Welcome to singleton hell...
                return;
            }
            HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins
                    .getInstance().getCommandExecutionHook();
            HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance()
                    .getEventNotifier();
            HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance()
                    .getMetricsPublisher();
            HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance()
                    .getPropertiesStrategy();
            HystrixPlugins.reset();
            HystrixPlugins.getInstance().registerConcurrencyStrategy(target);
            HystrixPlugins.getInstance()
                    .registerCommandExecutionHook(commandExecutionHook);
            HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
            HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
            HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
        }
        catch (Exception e) {
            log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);
        }
    }

    /**
     * 内部服务接口增加逻辑
     * @return
     */
    @Bean
    public RequestInterceptor headerInterceptor() {
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                addHeader(requestTemplate, LoggerIdFilter.LOGGER_ID, MDC.get(LoggerIdFilter.LOGGER_ID));
            }
        };
    }
    private void addHeader(RequestTemplate requestTemplate, String name,
                           String... values) {

        if (!requestTemplate.headers().containsKey(name)) {
            requestTemplate.header(name, values);
        }
    }

}


参考

https://www.jianshu.com/p/3c1cc45d7745

https://www.cnblogs.com/2YSP/p/11440700.html