Logback日志模式中的进程ID

21

我有以下的logback模式:

<pattern>
    {"hostname": "${HOSTNAME}", 
     "level": "%p", 
     "method": "%M", 
     "process_id": "${process}", 
     "thread_id": "%t", 
     "timestamp": "%d{Y-M-d}T%d{H:M:S.s}", 
     "mesg":"%msg"}%n
</pattern>

很不幸,在生成日志消息时我看到:"process_id": "process_IS_UNDEFINED"

是否有自动设置进程ID的变量,就像主机名一样?我在logback文档中找不到这些自动设置变量的文件,是否有更好的文档来源?

编辑:我知道Mapped Diagnostic Contexts,但希望有内置解决方案,而不需要进行此类设置,就像主机名一样。

5个回答

18
您可以使用Mapped Diagnostic Context来解决问题。
import org.slf4j.MDC;

public class Main {
    public static void main(String... args) {
        // put process ID early
        MDC.put("process_id", 
            ManagementFactory.getRuntimeMXBean().getName());
    }
}

接下来,您只需要按照以下方式重新定义您的模式:

<pattern>{..., "process_id": "%X{process_id}"}</pattern>

编辑

您还可以创建自己的编码器和转换器,并在logback.xml中使用它们:

import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;

public class ExtendedPatternLayoutEncoder extends PatternLayoutEncoder {
    @Override
    public void start() {
        // put your converter
        PatternLayout.defaultConverterMap.put(
            "process_id", ProcessIdConverter.class.getName());
        super.start();
    }
}
import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;

import java.lang.management.ManagementFactory;

public class ProcessIdConverter extends ClassicConverter {
    private static final String PROCESS_ID =
            ManagementFactory.getRuntimeMXBean().getName();

    @Override
    public String convert(final ILoggingEvent event) {
        // for every logging event return processId from mx bean
        // (or better alternative)
        return PROCESS_ID;
    }
}
<encoder class="some.package.ExtendedPatternLayoutEncoder">
    <pattern>{..., "process_id": "%process_id"}</pattern>
</encoder>

完整示例:

    <encoder class="some.package.ExtendedPatternLayoutEncoder">
        <pattern>%d{dd.MM.yyyy HH:mm:ss.SSS} PID:%process_id [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>

这是一个我知道的解决方案,但很烦人,因为它需要修改我们实际的代码。有没有办法在不修改应用程序代码的情况下设置MDC?也许通过编写一个单独的类来修改MDC并将其放在类路径上? - qwwqwwq
@qwwqwwq 我不确定是否有一些记录的方法来实现它。我猜你可以重写 ch.qos.logback.classic.PatternLayoutBase 类并将你的转换器放在 defaultConverterMap 中。但这是一个肮脏的 hack :) - vsminkov
@qwwqwwq 还有另外一种方法。您可以从 ch.qos.logback.classic.PatternLayout 继承并在您的 logback.xml 文件中使用它,就像这里所示。 - vsminkov
1
@qwwqwwq 我认为实现自己的编码器/布局以呈现 json 输出是个好主意,这样你就可以正确地转义 "mesg" 中的消息。 - vsminkov
1
这看起来好多了!而且关于JSON的那个观点很好,谢谢你提出来。 - qwwqwwq
显示剩余3条评论

10

有比 @vsminkov 更好的解决方案。 我在这里找到了它:Layouts,其中写着创建自定义转换说明符。 基本上,您需要创建自己的转换器,但不是继承 PatternLayoutEncoder,而是将一个转换规则添加到您的配置:

<configuration>

  <conversionRule conversionWord="pid" 
                  converterClass="my.custom.converter.ProcessIdConverter" />
  <conversionRule conversionWord="processId" 
                  converterClass="my.custom.converter.ProcessIdConverter" />

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%-6pid [%thread] - %msg%n</pattern>
    </encoder>
  </appender>
  ...
</configuration>

那样你就可以摆脱编码器。

1
这是真正的交易。比默认答案好多了。 - ATrubka

2

DefaultLogbackConfiguration中定义的控制台日志记录默认模式为:

"${CONSOLE_LOG_PATTERN:-"
            + "%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) "
            + "%clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} "
            + "%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"

正如@Hlulani所指出的那样,并且正如您可以在此默认模式中看到的那样,您可以使用${PID},logback将用进程ID替换它。

2
你正在链接的日志模式来自于 spring-boot,这是一个使用 logback 作为第三方依赖的项目。他们在这里指定了 PID 作为自定义日志属性:https://github.com/spring-projects/spring-boot/blob/6a353c60216aeb51aa3d6c3ce947c61603af46aa/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java#L139 如果你只是使用 logback 作为依赖,你将无法使用这样的日志模式。 - qwwqwwq

0

我尝试使用 ${PID},这对我有用

<pattern>
    {"hostname": "${HOSTNAME}", 
     "level": "%p", 
     "method": "%M", 
     "process_id": "${PID}", 
     "thread_id": "%t", 
     "timestamp": "%d{Y-M-d}T%d{H:M:S.s}", 
     "mesg":"%msg"}%n
</pattern>

我认为这个在logback中不是“开箱即用”的,你的项目中一定有指定自定义日志属性PID的地方,也许是第三方库在做这件事?如果你在logback源代码中搜索字符串PID,似乎没有任何出现。 - qwwqwwq

-3

也许你可以尝试使用%thread而不是process。


1
谢谢您的回复,我已经有线程 ID 了,但是我正在寻找进程 ID。 - qwwqwwq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接