gpt4 book ai didi

spring-boot - 更改 appender 级别而不是 logger 级别

转载 作者:行者123 更新时间:2023-12-04 21:03:06 26 4
gpt4 key购买 nike

我的团队使用 Spring Boot Admin 用于控制我们的 spring application ,
Spring Boot Admin我们可以选择更改 logger 级别在 Runtime ,
我们为每个 task 都有一个单独的记录器(Thread),如果我们只想查看一个线程的控制台日志,我们关闭所有其他线程记录器,
问题是每个记录器都为 STDOUT 发送它的输出。还有对于某个文件,我们想关闭只有标准输出。

log4j2.xml 配置示例:

<Loggers>
<Logger name="task1" level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
<Logger name="task2" level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
</Loggers>

我们尝试了很多解决方案:
  • 将父记录器与可加性结合使用,并将每个 appender 分离到不同的记录器,
    关于它的任何想法?
  • 最佳答案

    默认情况下,Log4j2 不允许管理 System.out 和 System.err 流。

    澄清控制台记录器的工作原理:
    只需 Console appender 将其输出打印到 System.out 或 System.err。根据文档,如果默认情况下不指定目标,它将打印到 System.out:

    https://logging.apache.org/log4j/2.x/manual/appenders.html

    target || String || Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is "SYSTEM_OUT".



    这是一个例子:
    log4j2.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    <Properties>
    <Property name="log-pattern">%d{ISO8601} %-5p %m\n</Property>
    </Properties>
    <appenders>
    <Console name="Console" target="SYSTEM_OUT">
    <PatternLayout>
    <pattern>${log-pattern}</pattern>
    </PatternLayout>
    </Console>
    </appenders>
    <Loggers>
    <logger name="testLogger" level="info" additivity="false">
    <AppenderRef ref="Console"/>
    </logger>
    </Loggers>
    </configuration>
    LogApp.java
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;

    public class LogApp {
    public static void main(String[] args) {
    Logger log = LogManager.getLogger("testLogger");
    log.info("Logger output test!");
    System.out.println("System out test!");
    }
    }

    输出:
    2019-01-08T19:08:57,587 INFO  Logger output test!
    System out test!

    管理系统流的解决方法

    以 Dmitry Pavlenko 的流重定向类为例

    https://sysgears.com/articles/how-to-redirect-stdout-and-stderr-writing-to-a-log4j-appender/
    import org.apache.logging.log4j.Level;
    import org.apache.logging.log4j.Logger;

    import java.io.IOException;
    import java.io.OutputStream;

    /**
    * A change was made on the existing code:
    * - At (LoggingOutputStream#flush) method 'count' could contain
    * single space character, this types of logs has been skipped
    */
    public class LoggingOutputStream extends OutputStream {
    private static final int DEFAULT_BUFFER_LENGTH = 2048;
    private boolean hasBeenClosed = false;
    private byte[] buf;
    private int count;

    private int curBufLength;

    private Logger log;

    private Level level;

    public LoggingOutputStream(final Logger log,
    final Level level)
    throws IllegalArgumentException {
    if (log == null || level == null) {
    throw new IllegalArgumentException(
    "Logger or log level must be not null");
    }
    this.log = log;
    this.level = level;
    curBufLength = DEFAULT_BUFFER_LENGTH;
    buf = new byte[curBufLength];
    count = 0;
    }

    public void write(final int b) throws IOException {
    if (hasBeenClosed) {
    throw new IOException("The stream has been closed.");
    }
    // don't log nulls
    if (b == 0) {
    return;
    }
    // would this be writing past the buffer?
    if (count == curBufLength) {
    // grow the buffer
    final int newBufLength = curBufLength +
    DEFAULT_BUFFER_LENGTH;
    final byte[] newBuf = new byte[newBufLength];
    System.arraycopy(buf, 0, newBuf, 0, curBufLength);
    buf = newBuf;
    curBufLength = newBufLength;
    }

    buf[count] = (byte) b;
    count++;
    }

    public void flush() {
    if (count <= 1) {
    count = 0;
    return;
    }
    final byte[] bytes = new byte[count];
    System.arraycopy(buf, 0, bytes, 0, count);
    String str = new String(bytes);
    log.log(level, str);
    count = 0;
    }

    public void close() {
    flush();
    hasBeenClosed = true;
    }
    }

    并为系统输出流创建一个自定义记录器,而不是注册它。

    下面是记录器使用的完整代码:
    log4j2.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    <Properties>
    <Property name="log-pattern">%d{ISO8601} %-5p %m\n</Property>
    </Properties>
    <appenders>
    <Console name="Console" target="SYSTEM_OUT">
    <PatternLayout>
    <pattern>${log-pattern}</pattern>
    </PatternLayout>
    </Console>
    </appenders>
    <Loggers>
    <logger name="testLogger" level="info" additivity="false">
    <AppenderRef ref="Console"/>
    </logger>
    <logger name="systemOut" level="info" additivity="true"/>
    </Loggers>
    </configuration>
    SystemLogging.java
    import org.apache.logging.log4j.Level;
    import org.apache.logging.log4j.LogManager;

    import java.io.PrintStream;

    public class SystemLogging {
    public void enableOutStreamLogging() {
    System.setOut(createPrintStream("systemOut", Level.INFO));
    }

    private PrintStream createPrintStream(String name, Level level) {
    return new PrintStream(new LoggingOutputStream(LogManager.getLogger(name), level), true);
    }
    }
    LogApp.java
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;

    public class LogApp {
    public static void main(String[] args) {
    new SystemLogging().enableOutStreamLogging();

    Logger log = LogManager.getLogger("testLogger");
    log.info("Logger output test!");
    System.out.println("System out test!");
    }
    }

    最终输出
    2019-01-08T19:30:43,456 INFO  Logger output test!
    19:30:43.457 [main] INFO systemOut - System out test!

    现在,根据需要使用新的记录器配置自定义系统。

    加;如果您不想覆盖 System.out 而只想保存它: TeeOutputStream 库中有 commons-io。您可以将原始 System.out 替换为原始 System.outLoggingOutputStream 的组合,这将同时写入两个流。这不会更改原始输出,但允许您使用日志附加程序保存 System.out

    关于spring-boot - 更改 appender 级别而不是 logger 级别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53993719/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com