SpringBoot MDC 仅作下日志
SpringBoot MDC only for the next log
关于 SpringBoot 应用的小问题,请 MDC 记录。
我有一个非常简单的 SpringBoot 网络处理程序:
@GetMapping(path = "/mdcOnlyToThisLogPlease")
public Mono<String> mdcOnlyToThisLogPlease(@RequestBody Book book) {
MDC.setContextMap(Map.of("bookName", book.getTitle(), "bookAuthor", book.getAuthor()));
LOGGER.info("I would like to have a log with bookName and bookValue as first level key for the MDC Json log, and only for this log please");
return bookService.doSomething(book.getTitle(), book.getAuthor());
}
在这里,我想在 json 中作为一级键登录书名和作者,我想得到这个:
{
@timestamp: 2022-02-22T02:22:22.222Z
@version: 1
bookName: someName
bookAuthor: someAuthor
level: INFO
level_value: 20000
logger_name: MyClass
message: I would like to have a log with bookName and bookValue as first level key for the MDC Json log, and only for this log please
spanId: e58ad767e34525de
thread_name: reactor-http-epoll-1
traceId: ccf32f0b5d210aa2
}
我认为这段代码可以做到这一点。
不幸的是,它还记录了密钥,对于后面的每一个日志!
例如,我在 bookService.doSomething() 的日志、运行状况检查日志等中也看到了...
{
@timestamp: 2022-05-02T04:31:30.648Z
@version: 1
bookName: someName
bookAuthor: someAuthor
level: INFO
level_value: 20000
logger_name: reactor.netty.http.server.AccessLog
message: 0:0:0:0:0:0:0:1%0 - - [02/May/2022:04:31:30 +0000] "GET /health/readiness HTTP/2.0" 200 5088 19
thread_name: reactor-http-epoll-1
}
{
@timestamp: 2022-05-02T04:33:30.648Z
@version: 1
bookName: someName
bookAuthor: someAuthor
level: INFO
level_value: 20000
logger_name: bookService
message: Log from book service. I do not wish to see bookName and bookAuthor as keys
thread_name: reactor-http-epoll-1
}
{
@timestamp: 2022-05-02T04:40:48.742Z
@version: 1
bookName: someName
bookAuthor: someAuthor
level: INFO
level_value: 20000
logger_name: reactor.netty.http.server.AccessLog
message: 0:0:0:0:0:0:0:1%0 - - [02/May/2022:04:40:48 +0000] "GET /health/liveness HTTP/2.0" 200 5088 25
thread_name: reactor-http-epoll-1
}
请问如何添加密钥,但只能用于下一个/一个日志?
谢谢
假设您使用的是 SLF4J MDC-
对于一次 单个 key-value 对,MDC 附带 MDCCloseable
,这使您可以利用 try-with-resources块:
log.info("This will be logged without myKey, myValue");
try (MDC.MDCCloseable ignored = MDC.putCloseable("myKey", "myValue")) {
log.info("This will be logged with myKey, myValue");
}
log.info("This will be logged without myKey, myValue");
在此表单中,您在 MDC.putCloseable(...)
中输入的条目将在该块的末尾自动删除。见 Javadocs.
不幸的是,没有类似的方便方法可以一次完成 多个 条目。可以嵌套多个 try-with-resources/MDC.putCloseable()
块,但这样做会使代码变得混乱。
幸运的是,自己编写并不太难,只需实施 Closeable
并跟踪您输入 MDC 的密钥:
// MDCCloseableMap.java
public class MDCCloseableMap implements Closeable {
private final Set<String> keys;
public MDCCloseableMap(Map<String, String> entries) {
this.keys = Collections.unmodifiableSet(entries.keySet());
entries.forEach(MDC::put);
}
@Override
public void close() {
keys.forEach(MDC::remove);
}
}
然后你可以用同样的方式使用:
log.info("This will be logged without myKeys, myValues");
Map<String, String> myEntries = Map.of("myKey1", "myValue1", "myKey2", "myValue2");
try (MDCCloseableMap ignored = new MDCCloseableMap(myEntries)) {
log.info("This will be logged with myKeys, myValues");
}
log.info("This will be logged without myKeys, myValues");
关于 SpringBoot 应用的小问题,请 MDC 记录。
我有一个非常简单的 SpringBoot 网络处理程序:
@GetMapping(path = "/mdcOnlyToThisLogPlease")
public Mono<String> mdcOnlyToThisLogPlease(@RequestBody Book book) {
MDC.setContextMap(Map.of("bookName", book.getTitle(), "bookAuthor", book.getAuthor()));
LOGGER.info("I would like to have a log with bookName and bookValue as first level key for the MDC Json log, and only for this log please");
return bookService.doSomething(book.getTitle(), book.getAuthor());
}
在这里,我想在 json 中作为一级键登录书名和作者,我想得到这个:
{
@timestamp: 2022-02-22T02:22:22.222Z
@version: 1
bookName: someName
bookAuthor: someAuthor
level: INFO
level_value: 20000
logger_name: MyClass
message: I would like to have a log with bookName and bookValue as first level key for the MDC Json log, and only for this log please
spanId: e58ad767e34525de
thread_name: reactor-http-epoll-1
traceId: ccf32f0b5d210aa2
}
我认为这段代码可以做到这一点。 不幸的是,它还记录了密钥,对于后面的每一个日志!
例如,我在 bookService.doSomething() 的日志、运行状况检查日志等中也看到了...
{
@timestamp: 2022-05-02T04:31:30.648Z
@version: 1
bookName: someName
bookAuthor: someAuthor
level: INFO
level_value: 20000
logger_name: reactor.netty.http.server.AccessLog
message: 0:0:0:0:0:0:0:1%0 - - [02/May/2022:04:31:30 +0000] "GET /health/readiness HTTP/2.0" 200 5088 19
thread_name: reactor-http-epoll-1
}
{
@timestamp: 2022-05-02T04:33:30.648Z
@version: 1
bookName: someName
bookAuthor: someAuthor
level: INFO
level_value: 20000
logger_name: bookService
message: Log from book service. I do not wish to see bookName and bookAuthor as keys
thread_name: reactor-http-epoll-1
}
{
@timestamp: 2022-05-02T04:40:48.742Z
@version: 1
bookName: someName
bookAuthor: someAuthor
level: INFO
level_value: 20000
logger_name: reactor.netty.http.server.AccessLog
message: 0:0:0:0:0:0:0:1%0 - - [02/May/2022:04:40:48 +0000] "GET /health/liveness HTTP/2.0" 200 5088 25
thread_name: reactor-http-epoll-1
}
请问如何添加密钥,但只能用于下一个/一个日志?
谢谢
假设您使用的是 SLF4J MDC-
对于一次 单个 key-value 对,MDC 附带 MDCCloseable
,这使您可以利用 try-with-resources块:
log.info("This will be logged without myKey, myValue");
try (MDC.MDCCloseable ignored = MDC.putCloseable("myKey", "myValue")) {
log.info("This will be logged with myKey, myValue");
}
log.info("This will be logged without myKey, myValue");
在此表单中,您在 MDC.putCloseable(...)
中输入的条目将在该块的末尾自动删除。见 Javadocs.
不幸的是,没有类似的方便方法可以一次完成 多个 条目。可以嵌套多个 try-with-resources/MDC.putCloseable()
块,但这样做会使代码变得混乱。
幸运的是,自己编写并不太难,只需实施 Closeable
并跟踪您输入 MDC 的密钥:
// MDCCloseableMap.java
public class MDCCloseableMap implements Closeable {
private final Set<String> keys;
public MDCCloseableMap(Map<String, String> entries) {
this.keys = Collections.unmodifiableSet(entries.keySet());
entries.forEach(MDC::put);
}
@Override
public void close() {
keys.forEach(MDC::remove);
}
}
然后你可以用同样的方式使用:
log.info("This will be logged without myKeys, myValues");
Map<String, String> myEntries = Map.of("myKey1", "myValue1", "myKey2", "myValue2");
try (MDCCloseableMap ignored = new MDCCloseableMap(myEntries)) {
log.info("This will be logged with myKeys, myValues");
}
log.info("This will be logged without myKeys, myValues");