java—允许在SpringWebFlux中填充serverwebexchange.logprefix以进行uniquerequestid日志记录

sczxawaw  于 2021-07-24  发布在  Java
关注(0)|答案(2)|浏览(344)

Spring Webflux 提供需要 ServerRequest 是我们实现代码的地方。根据下面的文章,spring有一个 LogId 这个概念似乎是我所说的 UniqueRequestId . 当抛出异常时,框架将 LogId 通过 AbstractErrorWebExceptionHandler / ServerWebExchange . 我的情况与许多服务相互呼叫和共享服务有关 UniqueRequestId . 因此,我们不希望spring生成这个id,而是希望用一种方法来设置 LogId 通过http请求头,例如x-request-id。我的原因是这样一个服务的日志可以与另一个服务的日志相关。我找不到任何关于如何做到这一点的文章。
一些相关的背景知识:我已经找到了一个90%的部分替代解决方案 UniqueRequestId 通过设置 UniqueRequestId 进入mdc( ThreadLocal )然后根据这一特征通过React链(https://projectreactor.io/docs/core/release/reference/#context ->请参阅“向React序列添加上下文”)。这适用于在我的React序列+处理程序中处理的代码,但是如果我的代码抛出 Exception 或者 Mono.error(...) 然后,springwebflux框架似乎将日志调度到一个异步线程,因此mdc和上下文都丢失了。因此,我希望通过戳我的手指来解决最后一个问题 UniqueRequestId 进入 LogId .
https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-日志id
spring:boot:2.4.1,web+webflux:5.3.2

mm9b1k5b

mm9b1k5b1#

您是否希望使用 UniqueRequestId ?
如果您只希望能够跟踪您在服务上或跨服务的处理,那么您应该查看 tracing 常见于 application performance monitoring 图书馆。
我想你可以 spring-cloud-sleuth 只有对数相关(https://cloud.spring.io/spring-cloud-sleuth/reference/html/#only-侦探日志关联)
sleuth支持reactor(springwebflux),它会自动将一些数据添加到日志中 trace.idtrace 表示可以在多个服务上执行的操作或数据流。对我来说,这就是你要找的,这个跟踪被发送到其他服务,以便他们在日志中重用它。允许您通过多个服务跟踪特定呼叫。 transaction.idtransaction 表示同一服务内的操作或数据流。
例如(下面的代码不起作用,它只是给你一个想法):
servicea对serviceb进行http调用,两者都运行在不同的容器/jvm中

public class serviceA() {

  private final ServiceBClient serviceBClient;

  @Get
  public Flux<Cat> getSomething() {
    log.info('Calling serviceB');
    return serviceBClient
      .listAllCats()
      .then(() -> {    log.info('Called serviceB') });
  }

}
public class serviceB() {

  private final CatRepository catRepository;

  @Get
  public Flux<Cat> listCats() {
    log.info('Asking for cats');
    return catRepository.listAll()
     .doOnSuccess(() -> { log.info('Request success!') })
  }

}

下面是自定义日志消息的示例(只关心trace.id)
服务A.log

[INFO] .... Calling serviceB, trace.id=1321313543121, transaction.id=123546   
[INFO] .... Called serviceB, trace.id=1321313543121, transaction.id=123546

服务B.log

[INFO] .... Asking for cats, trace.id=1321313543121, transaction.id=224465   
[INFO] .... Called serviceB, trace.id=1321313543121, transaction.id=224465
``` `transaction.id` ,事务表示特定服务上的操作。
sleuth还应该将trace.id添加到错误日志中
zzoitvuj

zzoitvuj2#

如果它有助于其他人:我又看了一眼springsleuth(因为它是在另一个答案中提出的),它解决了我的问题的起源,即在日志中获得uniquetracingid。但是这个答案仍然不能解决我原来想回答的问题。
如果只添加“starter”依赖项,那么只可能使用sleuth的日志记录功能 implementation 'org.springframework.cloud:spring-cloud-starter-sleuth:3.0.0' . 最后,我们决定使用它作为一个临时解决方案,因为它似乎将traceid传递到大部分React链中,并将其放入mdc中,这样就可以很容易地将其打印到日志中,例如通过logback %X{traceId} .
所以步骤是:
将springsleuth添加到您的项目中
将下面的traceidpropagator代码添加到您的项目中
在logback中添加类似的内容(或者为log4j计算equivalnt) <pattern>%d{HH:mm:ss.SSS} [%t] %X{traceId} [%-5level] %logger{15} - %msg%n%rEx</pattern> ```
@Component
@Log4j2
class TraceIdPropagator extends Propagation.Factory implements Propagation {

private static final long NON_NEEDED_VALUE = 1L;

@Override
public List<String> keys() {
    return Arrays.asList(ContractHandler.REQUEST_ID_HEADER);
}

@Override
public <R> TraceContext.Injector<R> injector(Setter<R, String> setter) {
    return (traceContext, request) -> {
        setter.put(request, ContractHandler.REQUEST_ID_HEADER, traceContext.traceIdString());
    };
}

@Override
public <R> TraceContext.Extractor<R> extractor(Getter<R, String> getter) {
    return request -> {
        String xRequestId = getter.get(request, ContractHandler.REQUEST_ID_HEADER);

        long traceId;

        if (StringUtils.isEmpty(xRequestId)) {
            traceId = NON_NEEDED_VALUE;
        } else {
            try {
                traceId = HexCodec.lowerHexToUnsignedLong(xRequestId);
            } catch (NumberFormatException ex) {
                throw new RuntimeException(
                    "Invalid X-Request-Id: " + xRequestId + ". It should be a 1 - 32 character lower case hex string.");
            }
        }

        return TraceContextOrSamplingFlags.create(TraceContext.newBuilder()
            .traceId(traceId)
            .spanId(NON_NEEDED_VALUE)
            .build());
        };
}

@Override
public <K> Propagation<K> create(KeyFactory<K> keyFactory) {
    return StringPropagationAdapter.create(this, keyFactory);
}

}

相关问题