There is an appender called CyclicBufferAppender
in logback and there seems to be no examples for it. What does it do? How does it work in the context of a RollingFileappender
? does it work with RollingFileappender
or works independently ? Is it similar to AsyncAppender
? Any example programmatically written is welcome.
Let me share an example of where I use it to let my Spring Boot web application show its own log messages in the UI.
I have a CyclicBufferAppender
subclass, InMemoryAppender
whose only purpose is to let Spring manage it as a bean. (Inspired by this answer by @NeemePraks.)
@Component
public class InMemoryAppender extends CyclicBufferAppender<ILoggingEvent> implements SmartLifecycle {
@Override
public boolean isRunning() {
return isStarted();
}
}
I'm adding that component during startup (this means it will miss Spring Boot startup log messages, as indicated in the linked answer, but I'm OK with that):
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(WebApplication.class, args);
LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory();
Logger rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
rootLogger.addAppender(context.getBean(InMemoryAppender.class));
}
I have a simple Controller with just an index page, which reads the contents of the appender:
@Controller
@RequestMapping(path = "/logs")
public class LogController {
public LogController(InMemoryAppender appender) {
this.appender = appender;
}
private final InMemoryAppender appender;
@GetMapping
public String index(Model model) throws Exception {
ILoggingEvent[] events = new ILoggingEvent[appender.getLength()];
for (int i = 0; i < appender.getLength(); i++) {
events[i] = appender.get(i);
}
model.addAttribute("logs", events);
return "logs/index";
}
}
and finally a simple Thymeleaf page to show the logs:
<h1>Logs</h1>
<table style="border-collapse: separate; border-spacing: 2px;">
<thead>
<tr>
<th scope="col">Timestamp</th>
<th scope="col">Level</th>
<th scope="col">Message</th>
</tr>
</thead>
<tbody>
<tr th:each="log: ${logs}" th:object="${log}">
<td th:text="*{#dates.format(timeStamp, 'yyyy-MM-dd HH:mm:ss.SSS')}" style="white-space: nowrap;">[timestamp]</td>
<td th:text="*{level}">[level]</td>
<td th:text="*{message}">[message]</td>
</tr>
</tbody>
</table>
This is how it looks like: