我在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());
不过,所有这些都只是猜测,我真的很想更好地理解拓扑、螺栓和注入库之间的相互作用,然后才能舒服地为这个特定问题提供一个可接受的答案。
暂无答案!
目前还没有任何答案,快来回答吧!