使用tag()进行日志记录

时间:2018-09-21 13:13:24

标签: spring-webflux

我想使用tag(key, value)运算符进行记录,将所有tags()放入MDC并进行记录。

但是我似乎找不到如何做类似的事情?我该如何检索标签?

@Test
public void testTags() {
  List<String> strings = Mono.just("asdf")
      .tag("bla", "blubb")
      .toProcessor()
      .tags()
      .map(Tuple2::toString)
      .collect(Collectors.toList());
  assertEquals("[bla, blubb]", strings); // strings is empty
}

我还想先不要使用toProcessor,因为它会使流变热,并且我想登录订阅。

-

所有这些都在spring-boot / Webflux上下文中,在这里我可以使用WebFilter(忘了提一下)。下面的答案来自Webflux的MetricsFilter和MDC。putCloseable来自另一个Blog;希望对别人有帮助。

1 个答案:

答案 0 :(得分:0)

最终使用从MetricsFilter派生的WebFilter进行了此操作

@Named
@Order(Ordered.LOWEST_PRECEDENCE)
public class AuditAccessLogFilter implements WebFilter {

  private final Logger log = LoggerFactory.getLogger(getClass());

  @Inject
  private Logger AUDIT;

  private Authentication anonymousUser = new AnonymousAuthenticationToken("key", "anonymous", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));

  private static final String hostname;

  static {
    try {
      hostname = InetAddress.getLocalHost()
          .getHostName();
    } catch (UnknownHostException e) {
      throw new RuntimeException("Could not find local hostname");
    }
  }

  @Value("${spring.application.name}")
  private String appName;

  @Value("${server.port}")
  private String serverPort;

  public AuditAccessLogFilter() {
    if (StringUtils.isEmpty(appName)) {
      log.warn("Application name is not set, using run directory");
      appName = "-";
    }

  }

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
    return chain.filter(exchange)
        .compose(call -> filter(exchange, call));
  }

  private Publisher<Void> filter(ServerWebExchange exchange, Mono<Void> call) {
    long start = System.currentTimeMillis();
    ServerHttpResponse response = exchange.getResponse();
    return Mono.subscriberContext()
        .flatMap(context -> exchange.getPrincipal()
            .switchIfEmpty(Mono.just(anonymousUser))
            .flatMap(principal -> call.doOnSuccess(done -> success(exchange, principal, context, start))
                .doOnError(cause -> {
                  if (response.isCommitted()) {
                    error(exchange, principal, start, context, cause);
                  }
                  else {
                    response.beforeCommit(() -> {
                      error(exchange, principal, start, context, cause);
                      return Mono.empty();
                    });
                  }
                })));
  }

  private void success(ServerWebExchange exchange, Principal principal, Context context, long start) {
    long timeTaken = System.currentTimeMillis() - start;
    auditLog(() -> AUDIT.info("accesslog"), timeTaken, exchange, principal, context);
  }

  private void error(ServerWebExchange exchange, Principal principal, long start, Context context, Throwable cause) {
    long timeTaken = System.nanoTime() - start;
    auditLog(() -> AUDIT.error("accesslog", cause.getMessage()), timeTaken, exchange, principal, context);
  }

  private void auditLog(Runnable fun, long timeTaken, ServerWebExchange exchange, Principal principal, Context context) {
    HttpStatus tmpStatusCode = exchange.getResponse()
        .getStatusCode();
    int statusCode = (tmpStatusCode == null ? 0 : tmpStatusCode.value());

    String uri = exchange.getRequest()
        .getURI()
        .toString();
    String queryParams = exchange.getRequest()
        .getQueryParams()
        .toString();
    String reasonPhrase = exchange.getResponse()
        .getStatusCode()
        .getReasonPhrase();
    try (MDC.MDCCloseable ignored = MDC.putCloseable("id", context.getOrDefault(GeneralConfig.REQUEST_HASH, "-"));
         MDC.MDCCloseable ignored2 = MDC.putCloseable("responsetimeMs", Long.toString(timeTaken));
         MDC.MDCCloseable ignored3 = MDC.putCloseable("uri", uri);
         MDC.MDCCloseable ignored4 = MDC.putCloseable("user", principal.getName());
         MDC.MDCCloseable ignored5 = MDC.putCloseable("params", queryParams);
         MDC.MDCCloseable ignored6 = MDC.putCloseable("httpCode", Integer.toString(statusCode));
         MDC.MDCCloseable ignored7 = MDC.putCloseable("httpReason", reasonPhrase);
         MDC.MDCCloseable ignored8 = MDC.putCloseable("hostname", hostname + ":" + serverPort);
         MDC.MDCCloseable ignored9 = MDC.putCloseable("appname", appName)) {
      fun.run();
    }

  }
}