log4jdbc与apachestorm1.0.1不写日志语句

iyfamqjs  于 2021-06-24  发布在  Storm
关注(0)|答案(0)|浏览(221)

我在storm(1.0.1)中使用log4j2(2.1)时遇到问题,无法登录到jdbc appender。我一直在关注microsoftwidinsight docapachestorm开发java拓扑。其他因素包括使用MicrosoftEventHubs(1.0.2)库进行EventHubsPout配置,这往往会导致slf4j出现一些maven“依赖地狱”问题。
在调试本地集群时,我将storm core 1.0.1包含在jar中(在部署拓扑时,在pom.xml中标记为provided)。我为jdbc连接创建了一个连接工厂类,然后在log4j2.xml配置文件中声明jdbc appender。本地集群倾向于正确输出(我们已经成功地尝试了控制台和jdbc appender)。
当拓扑提交到hdinsight集群时,storm ui中没有抛出错误,但是没有输出到数据库的日志语句。我试过:
隐式使用storm core log4j2依赖项。
在pom.xml中显式地包含核心和api的log4j2依赖项(参见代码段)。
使用所有可用的日志类型(调试->错误)。我在其他在线解决方案中看到,一些日志输出类型会被storm的内部日志记录到StormUI中,但事实并非如此。
在环境方面,我们已经确认集群可以与sql server对话。我们还确认了jdbc驱动程序在集群上工作以与sql服务器通信。
关于为什么它作为本地集群成功地登录,但在提交到hdinsight集群时“失败”地登录(考虑到除了使用jdbc而不是console之外,安装与microsoftdoc几乎相同)的任何输入?
下面的代码片段(reminder,storm core->scope:为本地集群注解掉):
pom.xml文件:

<dependencies>
    <dependency>
        <groupId>org.apache.storm</groupId>
        <artifactId>storm-core</artifactId>
        <version>1.0.1</version>
        <!-- keep storm out of the jar-with-dependencies -->
        <!--<scope>provided</scope>-->
        <exclusions>
            <exclusion>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-slf4j-impl</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>log4j-over-slf4j</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
            </exclusion>
            <exclusion>
                <groupId>logback-classic</groupId>
                <artifactId>ch.qos.logback</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.microsoft</groupId>
        <artifactId>eventhubs</artifactId>
        <version>1.0.2</version>
        <exclusions>
            <exclusion>
                <groupId>org.apache.log4j</groupId>
                <artifactId>log4j</artifactId>
            </exclusion>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
            </exclusion>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>log4j-over-slf4j</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-dbcp2</artifactId>
        <version>2.1.1</version>
    </dependency>
    <dependency>
        <groupId>com.microsoft.sqlserver</groupId>
        <artifactId>mssql-jdbc</artifactId>
        <version>6.2.2.jre8</version>
    </dependency>
</dependencies>
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>false</filtering>
            <includes>
                <include>log4j2.xml</include>
            </includes>
        </resource>
    </resources>
</build>

连接工厂:

public class ConnectionFactory {
    private interface Singleton {
        ConnectionFactory INSTANCE = new ConnectionFactory();
    }

    private final BasicDataSource dataSource;
    private static Properties dbProperties;

    private static String URL;
    private static String DRIVER;
    private static String USERNAME;
    private static String PASSWORD;

    private ConnectionFactory() {
        this.dataSource = new BasicDataSource();
    }

    public static void SetConnectionProperties(Properties properties) {
        try {
            //This property is used by logger
            System.setProperty("hostName", InetAddress.getLocalHost().getHostName());

            //Get environment properties
            dbProperties = properties;
            URL = dbProperties.getProperty("jdbc.url");
            DRIVER = dbProperties.getProperty("jdbc.driverClassName");
            USERNAME = dbProperties.getProperty("jdbc.username");
            PASSWORD = dbProperties.getProperty("jdbc.password");

            //Set connection properties
            Singleton.INSTANCE.dataSource.setUrl(URL);
            Singleton.INSTANCE.dataSource.setDriverClassName(DRIVER);
            Singleton.INSTANCE.dataSource.setUsername(USERNAME);
            Singleton.INSTANCE.dataSource.setPassword(PASSWORD);
        } catch (IOException ex){

        }
    }

    public static Connection getConnection() throws SQLException {
        return Singleton.INSTANCE.dataSource.getConnection();
    }
}

log4j2.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<configuration monitorInterval="60">
    <Appenders>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <JDBC name="databaseAppender" tableName="NotificationLog">
            <ConnectionFactory
                    class="ConnectionFactory" method="getConnection" />
            <Column name="LocalTimestamp" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}" />
            <Column name="UtcTimestamp" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}{GMT}" />
            <Column name="Level" pattern="%p" />
            <Column name="Message" pattern="%m" />
            <Column name="MachineName" pattern="${hostName}" />
            <Column name="Exception" pattern="%throwable{full}" />
        </JDBC>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="STDOUT"/>
            <AppenderRef ref="databaseAppender"/>
        </Root>
    </Loggers>
</configuration>

螺栓.java

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class Bolt extends BaseRichBolt {
    private OutputCollector collector;

    private static final Logger LOG = LogManager.getLogger(Bolt.class);

    @SuppressWarnings("rawtypes")
    @Override
    public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
        this.collector = collector;
    }

    @Override
    public void execute(Tuple input) {
        LOG.debug("Test debug");
        LOG.info("Test Info");
        LOG.error("Test Error");

        collector.ack(input);
    }
    ...
}

更新(2/20/2018):将跟踪日志语句添加到jar的主方法中,我们能够成功地登录到数据库。这意味着该问题似乎与螺栓的日志记录无关。这可能是序列化的问题吗?如果是这样,为什么要在本地机器上运行jar,并在部署到storm集群时出现问题?
更新(2/23/2018):虽然我们还没有解决这个问题的方法,但是我们实现了一个解决方案,直接使用jdbc驱动程序和sql准备的语句(例如,制作我们自己的日志解决方案)。
我认为我最近的问题的答案与这样一个事实有关:在storm集群上,序列化的组件被馈送到zookeepers,或者从zookeepers馈送到zookeepers,并且出于某种原因,log4j不能很好地发挥作用。但是,使用我们自己的“日志记录”解决方案,我们在提交拓扑之前注册工厂进行序列化,它似乎可以工作(请参阅代码片段)。

....
Config conf = new Config();
conf.registerSerialization(LoggerFactory.class);
StormSubmitter.submitTopology(topologyName, conf, builder.createTopology());

不过,所有这些都只是猜测,我真的很想更好地理解拓扑、螺栓和注入库之间的相互作用,然后才能舒服地为这个特定问题提供一个可接受的答案。

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题