Springboot 与 logback 一起工作,log4j2 工作,但在使用两者时不工作

问题描述 投票:0回答:1

我在使用 kafka 向 log4j2 和 logback 发送日志时观察到一个问题。

这是我非常简单的 Springboot 应用程序的代码:

@SpringBootApplication
public class QuestionApplication {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(QuestionApplication.class, args);
        HelloWorld helloWorld = new HelloWorld();
        HelloWorld.createLogs();
    }
}
public class HelloWorld {

    private static final Logger logger = LoggerFactory.getLogger(HelloWorld.class);

    public static void createLogs() throws JsonProcessingException {
        int k = 0;
        boolean b = true;
        while (b) {
            try{
                if(Math.random() > 0.5){
                    logger.info("ISSUE HERE -> custom logs and send log  messages  to Kafka topic at " +
                            DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));
                    int i =  2 / 0;
                    b = k < Integer.MAX_VALUE;
                    Thread.sleep(1000);
                } else{
                }
            } catch (Exception re){
                throw new RuntimeException("ISSUE HERE (custom log) error in try " + k, re);
            } finally {
                try {
                    int j = 2 / 0;
                } catch (Exception e) {
                    logger.error("ISSUE HERE (custom log) error in finally " + k, e);
                }
            }
            k++;
        }
    }
}

仅使用 log4j2 + kafka 附加程序的 ONE 项目 使用上面的代码,在第一个项目中,我需要将日志发送到 Kafka 主题。 为此,我使用以下依赖项:

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-log4j2</artifactId>
                </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-log4j-appender</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-layout-template-json</artifactId>
        </dependency>

还有这个 log4j2.xml 文件(不是 logback-spring.xml)

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" name="spring-boot-kafka-log">
    <Appenders>
        <Kafka name="Kafkalol" topic="question">
            <PatternLayout>
                <Pattern>
{
  "some field": "1.0",
  "parameters": {
    "class": "%logger",
    "message": "%message"
  }
}
                </Pattern>
            </PatternLayout>
            <Property name="bootstrap.servers">localhost:9093</Property>
        </Kafka>
        <Async name="Async">
            <AppenderRef ref="Kafkalol"/>
        </Async>

        <Console name="stdout" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5p [%-7t] %F:%L - %m%n"/>
        </Console>

    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="Kafkalol"/>
            <AppenderRef ref="stdout"/>
        </Root>
        <Logger name="org.apache.kafka" level="WARN" /><!-- avoid recursive logging -->
    </Loggers>
</Configuration>

这有效,我可以看到 kafka 主题中的所有日志。 我所说的所有日志是指我的自定义日志(来自 logger.info())和 springboot 日志

仅使用 logback + loki Appender 的项目二 使用上面相同的 java 代码,在第二个项目中,我需要将日志发送到 loki 实例。 为此,我使用以下依赖项:

   <dependency>
            <groupId>com.github.loki4j</groupId>
            <artifactId>loki-logback-appender</artifactId>
            <version>1.6.0-m1</version>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-core</artifactId>
        </dependency>

这是 logback-spring.xml (不是 log4j2.xml)

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>
                %d{yyyy-MM-dd HH:mm:ss} ${PID} %-5level --- [%thread] [${name},%X{traceId:-},%X{spanId:-}] %logger{36} : %msg%n
            </pattern>
        </encoder>
    </appender>

    <appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender">
        <metricsEnabled>true</metricsEnabled>
        <http>
            <url>https://logs-prod-006.grafana.net/loki/api/v1/push</url>
            <auth>
                <username>813123</username>
                <password>123</password>
            </auth>
        </http>
        <format>
            <label>
                <pattern>name=${name},host=${HOSTNAME},level=%level,pid=${PID},thread=%thread</pattern>
                <readMarkers>true</readMarkers>
            </label>
            <message>
                <pattern>
{
  "somefield":"1.0",
  "playload": {
    "pid":"${PID}",
    "class":"%logger",
    "thread":"%thread",
    "traceId":"%X{traceId}",
    "spanId":"%X{spanId}",
    "message":"%message"
  }
}
                </pattern>
            </message>
            <sortByTime>true</sortByTime>
        </format>
        <verbose>false</verbose>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="LOKI"/>
    </root>

</configuration>

这有效,我可以在 grafana loki 中查看所有日志。 我所说的所有日志是指我的自定义日志(来自 logger.info())和 springboot 日志

现在,在项目三中,我需要将两者结合起来,我需要将日志发送到 kafka 和 loki。

因此,我将 log4j2.xml 和 logback-spring.xml 添加到我的资源文件夹中。 我将所有依赖项合并到一个 pom 中,然后运行该程序

我希望看到两个位置的所有日志。

然而,结果是:

  • 所有日志(logger.info()日志+默认的springboot日志都在grafana loki中

  • 但是kafka主题中只有默认的springboot日志,缺少自定义日志。

通过 springboot 日志,我指的是:

2024-12-13T04:35:32.364+08:00  INFO 4394 --- [  main] [ ] org.example.EventApplication             : No active profile set, falling back to 1 default profile: "default"

问题,请问为什么自定义日志最终只出现在grafana日志中,而没有出现在Kafka中?

如何才能看到两个地方的所有日志?

java spring spring-boot log4j2 spring-logback
1个回答
0
投票

虽然您的应用程序可以同时使用多个日志记录API(例如 SLF4J、Log4j API、Apache Commons Logging (JCL)、

java.util.logging
(JUL)),但它不能使用多个日志记录实现(例如 Logback、 Log4j 核心)。 如果您有多个日志记录实现,则每个日志记录实现仅捕获由日志记录 API 子集生成的日志事件。 有关日志记录 API 和日志记录实现的更多详细信息,请参阅 Log4j 安装指南中的概念

由于您不能同时使用 Log4j Core 和 Logback,因此您需要选择一个具有适用于 Apache Kafka 和 Grafana Loki 的附加程序的日志记录实现。 我无法找到 Apache Kafka 的维护 Logback 附加程序,但另一方面,有 Grafana Loki 的维护 Log4j Core 附加程序

所以你需要做的就是:

  • 像之前一样配置您的应用程序以使用 Log4j 2 Core(添加
    spring-boot-starter-log4j2
    依赖项集并删除
    spring-boot-starter-logging
    )。
  • 像之前一样添加 Kafka 附加器。
  • pl.tkowalcz.tjahzi:log4j2-appender
    添加到您的依赖项并配置
    <Loki>
    附加程序。有关更多信息,请参阅附加程序的文档

备注

  • 您正在使用 非结构化

    Pattern
    布局尝试生成类似 JSON 的数据。您的附加程序的输出将始终是有效的 JSON,这为日志注入攻击打开了大门。使用 JSON 模板布局(需要额外的 dep)。

  • 我们已弃用 Log4j Core 3 中的

    Kafka
    附加程序,因为它几乎没有用户。 我再次对 Kafka 社区进行了民意调查,询问是否有兴趣在 this
    dev@kafka
    线程
    中使用 Kafka 附加程序,但到目前为止还没有答案。 如果您需要 Kafka 附加程序来工作,请考虑回答该线程。

© www.soinside.com 2019 - 2024. All rights reserved.