Backend Development 9 min read

Using Spring's ResponseBodyEmitter for Real‑Time Log Streaming

This article explains how Spring Framework's ResponseBodyEmitter enables real‑time, chunked HTTP responses for use cases such as log streaming, progress updates, chat, and AI output, detailing its advantages over SSE, usage scenarios, core methods, a complete controller example, and best‑practice considerations.

Top Architecture Tech Stack
Top Architecture Tech Stack
Top Architecture Tech Stack
Using Spring's ResponseBodyEmitter for Real‑Time Log Streaming

When ChatGPT sparked interest in streaming output, many developers turned to Server‑Sent Events (SSE), but Spring Framework offers a simpler alternative: ResponseBodyEmitter , introduced in Spring 4.2, which allows asynchronous HTTP responses that can push data piece by piece.

ResponseBodyEmitter's purpose is to let the server send partial data to the client without waiting for the whole response to be ready. It works by permitting incremental writes, making it ideal for long‑running or real‑time scenarios.

Typical use cases include long polling, server‑push events (SSE), generic streaming, and asynchronous processing such as progress bars, real‑time chat, stock price updates, system log streaming, and AI‑driven incremental responses.

Real‑time log streaming example – a Spring Boot controller that creates a ResponseBodyEmitter and launches a background thread to fetch the latest log entry every second and send it to the client:

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;

@RestController
@RequestMapping("/api/log")
public class LogController {
    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public ResponseBodyEmitter streamLogs() {
        ResponseBodyEmitter emitter = new ResponseBodyEmitter();
        // Start async thread to produce data and send
        new Thread(() -> {
            try {
                while (true) {
                    String logEntry = getLatestLogEntry();
                    if (logEntry != null) {
                        emitter.send(logEntry);
                    }
                    // Check for new logs every second
                    Thread.sleep(1000);
                }
            } catch (Exception e) {
                // End response with error if exception occurs
                emitter.completeWithError(e);
            }
        }).start();
        return emitter;
    }

    private String getLatestLogEntry() {
        // Simulate fetching the newest log line
        return "2025-02-12 12:00:00 - INFO: User logged in successfully.";
    }
}

Core methods of ResponseBodyEmitter :

send(Object data) – push a chunk of data to the client; can be called multiple times.

complete() – signal that all data has been sent and close the connection.

onTimeout(Runnable callback) – register a timeout handler.

onCompletion(Runnable callback) – register a completion handler.

Compared with other streaming techniques, Streaming using OutputStream gives low‑level control but requires manual resource management, while SSE relies on the text/event-stream protocol and needs client support. ResponseBodyEmitter works with any HTTP client and integrates seamlessly with Spring, making it a versatile choice.

Important considerations :

Client compatibility – most modern browsers support chunked transfer, but very old clients may have issues.

Timeout configuration – e.g., emitter.onTimeout(() -> emitter.complete());

Thread safety – send() is thread‑safe, but you must manage the lifecycle of background tasks to avoid leaks.

Always call complete() or completeWithError() when the work finishes to close the connection.

Conclusion : ResponseBodyEmitter is a lightweight, Spring‑native solution for real‑time data push, improving user experience in high‑concurrency scenarios such as progress updates, chat, stock monitoring, and log streaming.

backendJavaStreamingSpring Bootreal-time logsResponseBodyEmitter
Top Architecture Tech Stack
Written by

Top Architecture Tech Stack

Sharing Java and Python tech insights, with occasional practical development tool tips.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.