关于带有自定义追加程序和patternlayout的Apache Kafka:log4j2无法正常工作

log4j2 with custom appender and patternlayout not working

我在我的Web项目中使用log4j2。 我试图通过扩展abstractAppender将日志直接放入kafka。 根据文档,我的理解是,我可以为自定义的附加程序指定patternlayout,并设置该格式,我的记录器将使用格式化后的字符串将日志事件发送到kafka,但这没有发生。 log4j2.xml看起来像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" packages="com.abc.webservice.log.appender">

    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout>
                <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L- %X{sessionId}--%X{guid}- %m #]%n</pattern>
            </PatternLayout>
        </Console>
        <Kafka name="kafka" topic="test">
            <PatternLayout>
                <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L- %X{sessionId}--%X{guid}- %m #]%n</pattern>
            </PatternLayout>
            <Property name="metadata.broker.list">127.0.0.1:9092</Property>
            <Property name="serializer.class">kafka.serializer.StringEncoder</Property>
        </Kafka>
    </Appenders>

    <Loggers>
        <AsyncLogger name="async">
            <AppenderRef ref="kafka" />
            <AppenderRef ref="console" />
        </AsyncLogger>
        <Root level="info">
            <AppenderRef ref="console" />
            <AppenderRef ref="kafka" />
        </Root>
        <Logger name="com.abc" level="debug">
<!--            -->
            <!---->
            <!---->
           
        </Logger>

        <Logger name="org.hibernate.SQL">    
           
           
        </Logger>

        <Logger name="org.hibernate.type">
           
           
        </Logger>

        <Root level="info">
            <AppenderRef ref="kafka"/>
            <AppenderRef ref="console"/>
        </Root>

    </Loggers>
</Configuration>

如果我使用控制台附加程序,则日志采用正确的格式,但是当我使用自定义附加程序时,将接收不带格式的日志。 我如何使用指定的paatternlayout将日志发送到kafka。

请找到我的追加器实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import java.io.Serializable;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.appender.AppenderLoggingException;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.util.Booleans;
import org.apache.logging.log4j.message.Message;

@Plugin(name ="Kafka", category ="Core", elementType ="appender", printObject = true)
public final class KafkaAppender extends AbstractAppender {

    private final Lock lock = new ReentrantLock();

    private KafkaManager manager;

    protected KafkaAppender(String name, Filter filter, Layout layout, boolean ignoreExceptions, KafkaManager manager) {
        super(name, filter, layout, ignoreExceptions);
                System.err.println("hello world hello");
        this.manager = manager;
    }

    @PluginFactory
    public static KafkaAppender createAppender(@PluginAttribute("name") final String name, @PluginElement("Filter") final Filter filter,
            @PluginAttribute("ignoreExceptions") final String ignore, @PluginAttribute("topic") final String topic,
            @PluginElement("Properties") final Property[] properties, @PluginElement("layout") final Layout layout) {
        boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
        KafkaManager kafkaManager = KafkaManager.getKafkaManager(name, topic, properties);
        if (kafkaManager == null) {
            return null;
        }

//                Layout patternLayout = PatternLayout.createLayout("%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L- %X{sessionId}--%X{guid}- %m #]%n",
//                        null, null, null, true, false, null, null);  
//                System.err.println(patternLayout.toString());
        return new KafkaAppender(name, filter, layout, ignoreExceptions, kafkaManager);
    }

    @Override
    public final void start() {
        if (this.getManager() == null) {
            LOGGER.error("No KafkaManager set for the appender named [{}].", this.getName());
        }
        super.start();
        if (this.getManager() != null) {
            this.getManager().startup();
        }
    }

    @Override
    public final void stop() {
        super.stop();
        if (this.getManager() != null) {
            this.getManager().release();
        }
    }

    public final KafkaManager getManager() {
        return this.manager;
    }

    public void append(LogEvent event) {
        this.lock.lock();
        try {
            String s = event.getMessage().getFormattedMessage();
                        Message logEvent1 = event.getMessage();
                        String sp = logEvent1.getFormattedMessage();
                        this.getManager().send(event.getMessage().getFormattedMessage());
        } catch (final Exception e) {
            LOGGER.error("Unable to write to kafka [{}] for appender [{}].", this.getManager().getName(), this.getName(), e);
            throw new AppenderLoggingException("Unable to write to kafka in appender:" + e.getMessage(), e);
        } finally {
            this.lock.unlock();
        }
    }

    @Override
    public Layout<? extends Serializable> getLayout() {
            Layout patternLayout = PatternLayout.createLayout("%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L- %X{sessionId}--%X{guid}- %m #]%n",
                        null, null, null, true, false, null, null);      
            return patternLayout;
    }

}


在KafkaAppender类中,您的append方法应调用getLayout().toByteArray(event)格式化事件。

我注意到示例代码覆盖了getLayout。 我不会推荐这个。 getLayout的AbstractAppender实现返回配置的布局,该布局使您可以在配置中控制布局而无需更改代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
public void append(LogEvent event) {
    this.lock.lock();
    try {
        // let the Layout format the data in the LogEvent object
        final byte[] bytes = getLayout().toByteArray(event);

        // then pass the byte[] array with the formatted event to the manager
        // (I assume that your manager provides this method)
        manager.write(bytes, 0, bytes.length);

    } catch (Exception e) {
        LOGGER.error("Unable to write to kafka [{}] for appender [{}].",
               this.getManager().getName(), this.getName(), e);
        if (!ignoreExceptions()) {
            throw new AppenderLoggingException(
               "Unable to write to kafka in appender:" + e.getMessage(), e);
        }
    } finally {
        this.lock.unlock();
    }
}

// I would recommend not to override getLayout.
// The AbstractAppender implementation of getLayout returns the configured
// layout, which allows you to control the layout in configuration
// without code changes.
// @Override
// public Layout<? extends Serializable> getLayout() {...