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?
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:
The Tailer initializes (I can see TailerListenerAdapter.init()
is called on the TailerListenerAdapter
I constructed it with)
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.
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
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!