是否有可能在运行时使用MDC命名日志文件.
我有一个Web应用程序,使用tomcat docbase同时使用不同的名称调用.所以我需要为每个文件都有单独的日志文件.
我正在使用Vaadin框架,它对截取事件的支持很少,我不知道会话或UI何时被激活,所以我不能将它们的ID放在MDC中.
通常我会:
public void onSessionBegin(){
MDC.put("session", VaadinSession.getCurrent().toString()); //<-- String is immutable
}
public void onSessionEnd(){
MDC.remove("session");
}
Run Code Online (Sandbox Code Playgroud)
但我没有这样的事件,所以我想:
// in the servlet init or wherever
MDC.put("session", new Object(){
public String toString() {
VaadinSession.getCurrent().toString()
};
}); //<-- This is mutable and will be evaluated each time
Run Code Online (Sandbox Code Playgroud)
这样,无论多少时间都会改变会话,在日志中我会得到当前的一个.
这可能吗?如何使用自定义MDC实现替换logback MDC实现?我应该编辑slf4j和logback的来源吗?
我正在配置我的Akka应用程序以使用此处指定的SLF4J记录器:
http://doc.akka.io/docs/akka/2.3.4/scala/logging.html
在引擎盖下,我依靠Logback进行日志记录.我正在开发一个用于日志记录目的的通用模块,用户可以在他们的actor系统中使用.主要是,我正在创造一个他们可以混合的特质.
我有一个特点,这样做:
我有这样的东西:
trait ActorLogger {
val log: DiagnosticLoggingAdapter = Logging(this);
}
Run Code Online (Sandbox Code Playgroud)
我有一些额外的逻辑,它将MDC值添加到DiagnosticLoggingAdapter的MDC.现在的问题是:如果用户想要混合到非演员类,我会完全暴露一个不同的记录器.所以我可能有这样的事情:
trait ClassLogger {
val log = LoggerFactory getLogger getClass.getName
}
Run Code Online (Sandbox Code Playgroud)
我希望MDC值能够延续到此记录器.因此,例如,如果我将MDC值放入我的DiagnosticAdapterLogger,我应该能够从org.slf4j.MDC获取这些值
如何以干净的方式实现这一目标?
谢谢!
回到一个较旧的项目并开始更新其依赖项之后,我必须意识到自从版本以来,logback不再将MDC传播给子项1.1.5:https://github.com/qos-ch/logback/commit/aa7d584ecdb1638bfc4c7223f4a5ff92d5ee6273
这种变化使得大多数日志几乎无用.
虽然我可以理解链接问题中给出的论点,但我无法理解为什么这种更改不能以更向后兼容的方式进行(如java中通常常见的那样).
问:除了必须将所有内容从Runnables子类化为Threads之外,实现相同行为的现在正确的方法是什么?
我有一个spring-boot Web应用程序,该应用程序利用logback的MDC上下文来用自定义数据丰富日志。我具有以下实现方式,该实现方式可以使用一些与“ customKey”关联的自定义数据,并且在将%X {customKey}添加到logback配置中的日志记录模式后,它会被正确记录:
public class MDCFilter extends OncePerRequestFilter implements Ordered {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
FilterChain filterChain) throws ServletException, IOException {
try {
MDC.put("customKey", "someValue");
filterChain.doFilter(httpServletRequest, httpServletResponse);
} catch(Throwable t) {
LOG.error("Uncaught exception occurred", t);
throw t;
} finally {
MDC.remove("customKey");
}
}
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE - 4;
}
}
Run Code Online (Sandbox Code Playgroud)
只要没有抛出未捕获的异常,此方法就可以正常工作。为了解决这些问题,我准备了控制器建议。遗憾的是,MDC在登录控制器建议期间不再可用,因为它已被清理。如果我正确理解,spring将通过使用HandlerExceptionResolverComposite来确定负责的ExceptionHandler,该实现以最低的优先级进行注册,因此,它是在MDC已清理之后的最后一个。
我现在的困惑是:我应该如何注册我的过滤器,以便在登录控制器建议期间仍可以使用MDC?
我认为一个选择是从过滤器的finally块中删除MDC.remove(...)调用,而是实现一个ServletRequestListener,它在requestDestroyed-方法中清除MDC。但是由于该过滤器用于多个Web模块,所以我需要确保在每个现有的预期模块以及MDCFilter中也声明了ServletRequestListener,这对我来说似乎很容易出错。此外,如果负责将数据添加到MDC的过滤器还负责删除它,我希望使用它。
我们有一个日志记录流,其中我们的 java 应用程序填充 MDC,该 MDC 通过 log4j2 传输到 syslog 到中央 rsyslog 安装。在这里,我们广泛使用了 MDC。我们的设置是这样的:
<Syslog name="syslog" format="RFC5424" host="localhost" port="514" protocol="UDP"
appName="messaging_platform.${application}" mdcId="mdc" includeMDC="true" facility="LOCAL5" connectTimeoutMillis="100" ignoreExceptions="false">
<LoggerFields>
<KeyValuePair key="class" value="%c"/>
<KeyValuePair key="classname" value="%c{1}"/>
<KeyValuePair key="exception" value="%ex{full}"/>
<KeyValuePair key="method" value="%method"/>
<KeyValuePair key="line" value="%line"/>
<KeyValuePair key="application_name" value="${application}"/>
<KeyValuePair key="sequenceNumber" value="%sequenceNumber"/>
<KeyValuePair key="application_version" value="${application.version}"/>
<KeyValuePair key="marker" value="%marker"/>
<KeyValuePair key="thread" value="%thread"/>
<KeyValuePair key="system_nano_time" value="%nano"/>
<KeyValuePair key="app_uptime" value="%relative"/>
</LoggerFields>
</Syslog>
Run Code Online (Sandbox Code Playgroud)
我正在尝试将其转换为使用 graylog,似乎 GELF 是推荐的传输协议。我找到了多个库来做到这一点,并从GelfLayoutlog4j2 的内置开始。但那不支持LoggerFields。
那么将这些字段放入 Graylog 的推荐方法是什么?如果我做
<Socket name="Graylog" protocol="udp" host="localhost" …Run Code Online (Sandbox Code Playgroud) 我喜欢在我的应用程序中使用 MDC 日志记录字段,因为它使查找所有相关日志行变得更加容易。我还发现在处理开始时清除 MDC 上下文要容易得多,因为我知道应用程序的入口点在哪里,但有许多可能的异常路径,我自己或其他开发人员可能忘记调用 MDC.clear( )。
所以我的问题是,我这样做有什么缺点吗?根据经验,始终在处理开始和结束时清除上下文。
为了清楚起见,如果我从头开始编写代码,我会这样做:
MDC.put();
try {
...
} finally {
MDC.clear();
}
Run Code Online (Sandbox Code Playgroud)
但有时我必须使用基类或库中没有任何 MDC 相关代码的内容,因此我按照我所描述的方式进行操作,因为我不想从库中复制基类只是为了添加几行 MDC 代码...
我有一个用 spring 5 和 reactor 编写的应用程序。我在订阅者上下文中放入了一些信息,例如用户 ID。现在我想记录这个用户 ID。我正在尝试使用 MDC 但如果请求更改线程我丢失了信息。我该如何解决这个问题?有没有办法设置 MDC,以便应用程序周围的所有日志,包括外部库,我使用订阅者上下文放入的数据?我已经尝试过这里描述的内容,但它工作正常,但它不能解决我的外部库日志问题。
https://simonbasle.github.io/2018/02/contextual-logging-with-reactor-context-and-mdc/
这是我用来向标头添加过滤器并添加 UUID 的代码
@Slf4j
public class ReqTxIdFilterImpl implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
List<String> headerNames = Collections.list(request.getHeaderNames());
String requestTxId = "";
if(!headerNames.isEmpty()){
requestTxId = request.getHeader(
headerNames.stream()//
.filter(header -> header.contains("txId"))
.findAny()
.orElse("")//
);
}
if (StringUtils.isEmpty(requestTxId)) {
requestTxId = UUID.randomUUID().toString();
}
MDC.put("txId", requestTxId);
filterChain.doFilter(servletRequest, servletResponse);
MDC.clear();
}
}
Run Code Online (Sandbox Code Playgroud)
我使用 spring boot 和 MockMvc 来测试 API
@Autowired
private MockMvc mockMvc;
@Test
public void test_generatePolicyNumber() throws Exception { …Run Code Online (Sandbox Code Playgroud) kafka 监听消息之前/之后是否有任何类型的钩子可用?
使用案例:必须设置 MDC 关联 ID 才能执行日志可追溯性
我在寻找什么?之前/之后回调方法,以便可以在进入时设置 MDC 关联 ID,并最终在退出时清除 MDC。
编辑后的场景: 我将关联 id 作为 Kafka 标头的一部分,并且我想在 Kafka 监听器中收到消息后立即在 MDC 中进行设置
感谢您的帮助