Search code examples
javaspringspring-bootapache-tailer

How do I use Apache Tailer within a Spring Boot App?


Main Question

I'm writing an app (available here on GitHub - build/run instructions below) that scrapes a log file and reacts to certain events written to the log (in this case, making an HTTP request to a REST API). I've chosen Java, Spring Boot 2.x, Apache Tailer and OpenFeign as the primary vehicles to that end.

I suspect I'm not understanding how Apache Tailer and the threading it does in the background work, or how to properly leverage it within a Spring Boot app. What's a correct way to initialize and run a Tailer in the context of a Spring Boot app?

Additional Info

To test this, I'm starting the app locally, and echoing lines of text into the given log file via a shell. As of writing (commit 1fed906), when I run the app it seems that:

  1. The Tailer initializes (I can see TailerListenerAdapter.init() is called on the TailerListenerAdapter I constructed it with)

  2. The Tailer runs (I see everything I write to the log file it watches passed to TailerListenerAdapter.handle()).

As soon as I write something to the log that my TailerListenerAdapter knows it should react to, it looks like control exits from the Tailer.run() method call, and the app exits (gracefully). I want it to keep running and tailing the log until I stop the app though.

I wasn't really sure where to call Tailer.run() in this context so I have it in a @PostConstruct method in my custom Tailer subclass. I've never used @PostConstruct before, so I'm not 100% sure I'm using it correctly, or if there's a better place to put it to ensure that run() gets called at start up while also allowing me to inject all of my my config-file / bean driven options into it.

Build / Run Instructions

  1. Clone the project
  2. Run this in a shell: mvn spring-boot:run -Dspring-boot.run.arguments=--tailer.logFile=/path/to/any/test.log,--logging.level.com.github.ubunfu.mclogbot=DEBUG

    OR

    Set up an equivalent run configuration in your IDE. There's an application-local.yml Spring Boot config file with a place to specify the path to the test log file. In IntelliJ, set up a Maven run config with the following in Command Line: spring-boot:run -Dspring-boot.run.arguments=--spring.profiles.active=local


Solution

  • I'm pretty sure now that the right way to run the Tailer in a Spring Boot app is to modify the main class to implement CommandLineRunner (as described in this nice little Mkyong article), and run the Tailer from there. I believe this is because Spring boot assumes that you're writing a web app where the entry-point is an inbound request to be handled by Tomcat or something. If you want to change the entry-point (e.g. it's not a web app), you'd do the above and essentially override the default behavior.

    Also, I had a problem where the app would stop gracefully unexpectedly after reading a line that was supposed to result in the Feign client making an API call. It turns out the reason for that was that the Feign client was throwing a RuntimeException that I wasn't handling. It was not immediately apparent that any exception had occurred because there wasn't a stack trace or anything. I suspect this is because the Tailer is running in another thread? I'm not really sure. Point is - watch out for that when you're using Tailer!

    I hope this helps somebody!