在使用Azure Event Hub的SDK時候,常規情況下,發現範例程式碼中並沒有SDK內部的紀錄檔輸出。因為在Java專案中,沒有新增 SLF4J 依賴,已致於在啟動時候有如下提示:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
那麼,有什麼方便的辦法,能把SDK中,內部處理Event Hub的紀錄檔列印出來,並且儲存在紀錄檔檔案中呢?
是的,如提示所說,使用 SLF4J 就可以了。因為Azure Event Hub SDK中使用 (com.azure.core.util.logging.ClientLogger) 對紀錄檔進行輸出,所以在最外層(應用程式碼級)就需要有一個接收紀錄檔的Provider,那就是SLF4J。
下面的步驟,就是展示如何新增SLF4J依賴,如何新增輸出到檔案,輸出到Console的設定,最後檢視輸出結果。
前提要求:根據官方範例程式碼,已經成功執行消費端應用:https://docs.azure.cn/zh-cn/event-hubs/event-hubs-java-get-started-send (文末附帶本文的範例程式碼)
第一步:在 pom.xml 中新增 SLF4J 的3個依賴項
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
第二步:在 .\src\main\resources 目錄中新增 log4j.properties 檔案,並設定最關鍵的 紀錄檔輸出級別,路徑 和 格式
# Root logger option
log4j.rootLogger=INFO, stdout, FILE
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n
# Direct log messages to file
# Define the file appender
log4j.appender.FILE=org.apache.log4j.FileAppender
# Set the name of the file
log4j.appender.FILE.File=Logs/log.out
# Set the immediate flush to true (default)
log4j.appender.FILE.ImmediateFlush=true
# Set the threshold to debug mode
log4j.appender.FILE.Threshold=debug
# Set the append to false, overwrite
log4j.appender.FILE.Append=false
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n
第三步: 檢查輸出結果
1)實驗專案的檔案結構
2)pom.xml 中新增的 slf4j 依賴
3)為紀錄檔輸出到檔案和控制檯設定屬性
4)檢視檔案紀錄檔輸出
5)檢視控制檯紀錄檔輸出
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>ConsumeMessageAbort</artifactId> <version>1.0-SNAPSHOT</version> <name>ConsumeMessageAbort</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>com.azure</groupId> <artifactId>azure-messaging-eventhubs</artifactId> <version>5.12.2</version> </dependency> <dependency> <groupId>com.azure</groupId> <artifactId>azure-messaging-eventhubs-checkpointstore-blob</artifactId> <version>1.14.0</version> </dependency> <dependency> <groupId>com.azure</groupId> <artifactId>azure-identity</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>2.5.5</version> <configuration> <archive> <manifest> <mainClass>com.example.App</mainClass> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> </plugins> </build> </project>
# Root logger option
log4j.rootLogger=INFO, stdout, FILE
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n
# Direct log messages to file
# Define the file appender
log4j.appender.FILE=org.apache.log4j.FileAppender
# Set the name of the file
log4j.appender.FILE.File=Logs/log.out
# Set the immediate flush to true (default)
log4j.appender.FILE.ImmediateFlush=true
# Set the threshold to debug mode
log4j.appender.FILE.Threshold=debug
# Set the append to false, overwrite
log4j.appender.FILE.Append=false
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n
package com.example; import com.azure.messaging.eventhubs.EventData; import com.azure.messaging.eventhubs.EventHubClientBuilder; import com.azure.messaging.eventhubs.EventHubConsumerAsyncClient; import com.azure.messaging.eventhubs.EventProcessorClientBuilder; import java.io.IOException; import java.sql.Date; import java.time.Instant; import java.time.temporal.TemporalUnit; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Hello world! * */ public class App { final static Logger logger = LoggerFactory.getLogger(App.class); private static final String azureEventHubConnectionString = "event hub namespace connection string"; private static final String azureEventHubHostName = "event hub name"; public static void main(String[] args) throws IOException { System.out.println("Hello World!"); EventHubConsumerAsyncClient consumer = new EventHubClientBuilder() .connectionString(azureEventHubConnectionString, azureEventHubHostName) .consumerGroup(EventHubClientBuilder.DEFAULT_CONSUMER_GROUP_NAME) .buildAsyncConsumerClient(); try { consumer.receive(true).subscribe( event -> { EventData data = event.getData(); String message = "SequenceNumber is" + data.getSequenceNumber().toString() + " The eventData is " + data.getBodyAsString(); System.out.println(message); logger.info(message); }, error -> logger.error("The iot hub failed to listen for messages, error is {}" + error.toString())); } catch (Exception e) { consumer = new EventHubClientBuilder() .connectionString(azureEventHubConnectionString, azureEventHubHostName) .consumerGroup(EventHubClientBuilder.DEFAULT_CONSUMER_GROUP_NAME) .buildAsyncConsumerClient(); System.out.println("recollect consumer"); logger.warn("recollect consumer"); } System.out.println("Press enter to stop."); logger.info("Press enter to stop."); System.in.read(); System.out.println("...End..."); } }
使用 Java 向/從 Azure 事件中心 (azure-messaging-eventhubs) 傳送/接收事件 : https://docs.azure.cn/zh-cn/event-hubs/event-hubs-java-get-started-send
當在複雜的環境中面臨問題,格物之道需:濁而靜之徐清,安以動之徐生。 雲中,恰是如此!