$cache[$key] = empty($arr) ? NULL : $arr; return $cache[$key]; } // 门户 获取需要在频道显示的栏目主题数据 function portal_channel_thread($fid) { global $forumlist; if (empty($fid)) return NULL; $orderby = array('tid' => 1); $page = 1; // 遍历所有在频道显示内容的栏目 $category_forumlist = channel_category($fid); $arrlist = array(); $forum_tids = array(); $tidlist = array(); if ($category_forumlist) { foreach ($category_forumlist as &$_forum) { // 频道显示数据 $arrlist['list'][$_forum['fid']] = array( 'fid' => $_forum['fid'], 'name' => $_forum['name'], 'rank' => $_forum['rank'], 'type' => $_forum['type'], 'url' => $_forum['url'], 'channel_new' => $_forum['channel_new'], ); $forum_thread = thread_tid__find(array('fid' => $_forum['fid']), $orderby, $page, $_forum['channel_new'], 'tid', array('tid')); // 最新信息按栏目分组 foreach ($forum_thread as $key => $_thread) { $forum_tids[$key] = $_thread; } unset($forum_thread); } $tidlist += $forum_tids; } unset($category_forumlist); // 获取属性对应的tid集合 list($flaglist, $flagtids) = flag_thread_by_fid($fid); empty($flagtids) || $tidlist += $flagtids; unset($flagtids); // 频道置顶 $stickylist = sticky_list_thread($fid); empty($stickylist) || $tidlist += $stickylist; // 在这之前合并所有二维数组 tid值为键/array('tid值' => tid值) $tidarr = arrlist_values($tidlist, 'tid'); // 在这之前使用$tidarr = array_merge($tidarr, $arr)前合并所有一维数组 tid/array(1,2,3) if (empty($tidarr)) { $arrlist['list'] = isset($arrlist['list']) ? array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid') : array(); return $arrlist; } $tidarr = array_unique($tidarr); $pagesize = count($tidarr); // 遍历获取的所有tid主题 $threadlist = well_thread_find_asc($tidarr, $pagesize); // 遍历时为升序,翻转为降序 $threadlist = array_reverse($threadlist); foreach ($threadlist as &$_thread) { // 各栏目最新内容 isset($forum_tids[$_thread['tid']]) AND $arrlist['list'][$_thread['fid']]['news'][$_thread['tid']] = $_thread; // 全站置顶内容 isset($stickylist[$_thread['tid']]) AND $arrlist['sticky'][$_thread['tid']] = $_thread; // 首页属性主题 if (!empty($flaglist)) { foreach ($flaglist as $key => $val) { if (isset($val['tids']) && in_array($_thread['tid'], $val['tids'])) { $arrlist['flaglist'][$key][array_search($_thread['tid'], $val['tids'])] = $_thread; ksort($arrlist['flaglist'][$key]); $arrlist['flag'][$_thread['tid']] = $_thread; } } } } unset($threadlist); if (isset($arrlist['sticky'])) { $i = 0; foreach ($arrlist['sticky'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flag'])) { $i = 0; foreach ($arrlist['flag'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flaglist'])) { foreach ($arrlist['flaglist'] as &$val) { $i = 0; foreach ($val as &$v) { ++$i; $v['i'] = $i; } } } isset($arrlist['list']) AND $arrlist['list'] = array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid'); return $arrlist; } ?>spring boot - Automatic Context Propagation fails to work with MDC logging in reactive API Gateway - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

spring boot - Automatic Context Propagation fails to work with MDC logging in reactive API Gateway - Stack Overflow

programmeradmin0浏览0评论

We have developed our API Gateway using Spring Cloud Gateway framework based on reactive paradigm using below libraries: Spring Boot: 3.2.0 Spring Cloud: 2023.0.0 Spring: 6.1.1 Spring Cloud Gateway: 4.1.0

We are using Logback SLF4J library for logging purpose and MDC for injecting contextual information like request and session tracking id. We observed that MDC contextual information is NOT appropriately logged in log messages in reactive app execution since ThreadLocal is used by MDC whereas SCG is thread-agnostic. Request and session tracking id were missing or obsolete ones printed in many messages, mainly when thread switch happens.

We tried to enable automatic context propagation provided by Micrometer context-propagation(1.1.2 version) library to propagate contextual info to ThreadLocals.

public static void main(String args[]) {
    SpringApplication.run(GatewayApplication.class, args);
    Hooks.enableAutomaticContextPropagation();
    final String key = "TRACK_ID";
    ContextRegistry.getInstance().registerThreadLocalAccessor(
       key,
       () -> MDC.get(key),
       value -> MDC.put(key, value),
       () -> MDC.remove(key)
    );
}

And update the reactor context in the global filter in which the request tracking id is generated as below:

    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        final String reqTrackId = UUID.randomUUID().toString();
        MDC.put("TRACK_ID", reqTrackId);
        log.info("Request received with route: {}", exchange.getRequest().getPath());
        return chain.filter(exchange).contextWrite(Context.of("TRACK_ID", reqTrackId));
    }

After making above changes, the MDC contextual information seems to be appropriately written in log messages. However, the same issue happens when an exception is thrown from one of the global filter and its handled by custom error handler which is implementing ErrorWebExceptionHandler interface.

We tried to develop minimal version project that can reproduce the issue (which is attached in this issue for reference) and identified below 2 scenarios:

  1. when below statement is added then request tracking id is: a. written in logs written in global filters b. missing in logs written in custom exception handler
      return chain.filter(exchange).contextWrite(Context.of("TRACK_ID", reqTrackId));
    
  2. When contextWrite statement is removed, then request tracking id is a. randomly missing in logs written in global filters b. written in logs written in custom exception handler.

One possible way we found to fix the above issue was to update(do not remove key/value from MDC) the MDC key registration as below however it does not seems appropriate:

    ContextRegistry.getInstance().registerThreadLocalAccessor(
       key,
       () -> MDC.get(key),
       value -> MDC.put(key, value),
       () -> MDC.remove("")
    );   

We also tried to make similar changes in spring webflux project and it does not seems to have any issues in custom exception handler messages since there was no scope for contextWrite operator.

Could you please check the attached sample project that reproduces the reported issue and provide any possible help to resolve the issue? Thanks in advance.

Sample project is attached in below issue:

发布评论

评论列表(0)

  1. 暂无评论