This article demonstrates how to stream logs from a Java application running on a local Mac directly into Azure Event Hub using the Azure SDK for Java.
Prerequisites
- Java 17+
- Maven
- Azure Event Hub Namespace, Event Hub, and SAS Key
- Azure CLI configured and logged in
- Internet access to download dependencies
Project Structure
java-eventhub-logger/
├── pom.xml
├── src
│ └── main
│ ├── java
│ │ ├── DemoAppLogger.java
│ │ └── EHLogTailStreamer.java
│ └── resources
│ └── logback.xml
└── logs
└── app.log
pom.xml
<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>java-eventhub-logger</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<!-- Azure Event Hubs SDK -->
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-messaging-eventhubs</artifactId>
<version>5.17.0</version>
</dependency>
<!-- SLF4J Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.13</version>
</dependency>
<!-- Apache Commons IO for tailing logs -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.1</version>
</dependency>
</dependencies>
</project>
DemoAppLogger.java
This is a demo Java app that generates the logs to the app.log file.
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class DemoAppLogger {
public static void main(String[] args) throws IOException, InterruptedException {
FileWriter writer = new FileWriter("logs/app.log", true);
Random random = new Random();
String[] levels = {"INFO", "DEBUG", "WARN", "ERROR"};
while (true) {
String level = levels[random.nextInt(levels.length)];
String log = String.format("%s - [%s] This is a simulated %s message\n",
java.time.LocalDateTime.now(), level, level.toLowerCase());
writer.write(log);
writer.flush();
TimeUnit.SECONDS.sleep(2);
}
}
}
EHLogTailStreamer.java
import com.azure.messaging.eventhubs.EventData;
import com.azure.messaging.eventhubs.EventHubProducerClient;
import com.azure.messaging.eventhubs.EventHubClientBuilder;
import org.apache.commons.io.input.Tailer;
import org.apache.commons.io.input.TailerListenerAdapter;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class EHLogTailStreamer {
private static final String CONNECTION_STRING = "Endpoint=sb://<eendpoint>/;SharedAccessKeyName=<actual key name>;SharedAccessKey=<access key>;EntityPath=<event-hub-name>";
private static final String LOG_FILE_PATH = "logs/app.log";
public static void main(String[] args) {
EventHubProducerClient producer = new EventHubClientBuilder()
.connectionString(CONNECTION_STRING)
.buildProducerClient();
TailerListenerAdapter listener = new TailerListenerAdapter() {
@Override
public void handle(String line) {
try {
System.out.println("Sending log: " + line);
producer.send(Collections.singletonList(new EventData(line)));
} catch (Exception e) {
System.err.println("Failed to send log: " + e.getMessage());
}
}
};
Tailer tailer = new Tailer(new java.io.File(LOG_FILE_PATH), listener, 2000, true);
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(tailer::run);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
producer.close();
executor.shutdown();
}));
}
}
logback.xml
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>logs/app.log</file>
<append>true</append>
<encoder>
<pattern>%date [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
Run the App
1. Generate Logs
mvn compile exec:java -Dexec.mainClass="DemoAppLogger"
mvn compile exec:java -Dexec.mainClass="DemoAppLogger"
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< com.example:java-eventhub-logger >------------------
[INFO] Building java-eventhub-logger 1.0.0
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ java-eventhub-logger ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource from src/main/resources to target/classes
[INFO]
[INFO] --- compiler:3.13.0:compile (default-compile) @ java-eventhub-logger ---
[INFO] Nothing to compile - all classes are up to date.
[INFO]
[INFO] --- exec:3.5.1:java (default-cli) @ java-eventhub-logger ---
2. Stream to Event Hub
mvn compile exec:java -Dexec.mainClass="EHLogTailStreamer"
mvn compile exec:java -Dexec.mainClass="EHLogTailStreamer"
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< com.example:java-eventhub-logger >------------------
[INFO] Building java-eventhub-logger 1.0.0
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ java-eventhub-logger ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource from src/main/resources to target/classes
[INFO]
[INFO] --- compiler:3.13.0:compile (default-compile) @ java-eventhub-logger ---
[INFO] Nothing to compile - all classes are up to date.
[INFO]
[INFO] --- exec:3.5.1:java (default-cli) @ java-eventhub-logger ---
[EHLogTailStreamer.main()] INFO com.azure.messaging.eventhubs.EventHubClientBuilder - {"az.sdk.message":"Emitting a single connection.","connectionId":"MF_9e944c_1751012373534"}
[EHLogTailStreamer.main()] INFO com.azure.messaging.eventhubs.implementation.EventHubConnectionProcessor - {"az.sdk.message":"Setting next AMQP channel.","entityPath":"rranjan-event"}
Sending log: 2025-06-27T13:49:35.374570 - [ERROR] This is a simulated error message
Sending log: 2025-06-27T13:49:37.380537 - [INFO] This is a simulated info message
Sending log: 2025-06-27T13:49:39.385760 - [ERROR] This is a simulated error message
Sending log: 2025-06-27T13:49:41.389575 - [INFO] This is a simulated info message
Validate in Azure
Log in to the Azure portal and validate the same in Event Hub under both Metrics and Data Explorer.


Using Azure Portal
- Navigate to your Event Hub Namespace.
- Click on your Event Hub (e.g.,
rranjan-event). - Go to Metrics to visualize throughput.
- Enable Capture to route logs to Blob or Data Lake.
- Use Diagnostic settings to archive or pipe to Log Analytics.
In this guide, we walked through building a lightweight Java application that logs messages to a file using SLF4J + Logback and streams those logs to Azure Event Hub in near real-time using the Azure SDK. With end-to-end validation in the Azure Portal(can also be done via Azure CLI), this approach is well-suited for custom observability pipelines, audit logging, or streaming telemetry use cases.
Whether you’re building a large-scale distributed system or just need a reliable logging relay, this pattern is easy to extend with batching, retry policies, and error-handling enhancements.
#AzureEventHub #JavaLogging #Observability #LogStreaming #AzureSDK #DevOps #CloudLogging
The code will be uploaded to my GitHub.
Reach out on LinkedIn for any questions or





Leave a comment