6

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.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
CVA
  • 1,477
  • 1
  • 14
  • 23

1 Answers1

3

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:

enter image description here

Glorfindel
  • 21,988
  • 13
  • 81
  • 109