I did a couple of small projects over the holidays while drinking coquito, so here they are.
The first is a "simplest possible dynamic logging" project called dynamic-logback. This is a project that sets up Logback, and then periodically refreshes log levels from a file. The functionality is in one file and is less than 100 lines of code. (After writing this, I did a search on "dynamic logback" on Github and discovered https://github.com/syamantm/dynamic-logback which is a more complete example.)
Anyway, the point is that dynamic logging is easy! You don't need a lot of infrastructure or to set up a database, you can just set up a timer task and be done with it.
There is an assumption that changing log levels requires a total configuration refresh. This is not helped by the documentation that only mentions autoscan as an option, and encourages the setting of levels directly in
logback.xml. The reality is that reloading only applies to Logback appenders and their ancillary supports. Log levels can be queried and modified without any heavy lifting. In SQL terms, appenders and filters are the
DDL statements, while querying and changing log levels are the
To abstract it from Log4J/Logback APIs, you could add a
LogLevelResult interaction for querying log levels, and a
LogLevelEvent for modifying log levels, and that would allow for a CQRS style API. That's probably for another project though.
Migrating terse-logback-showcase from Heroku to fly.io
The application runs on Play Framework, which is JVM based and has built in docker deployment via sbt-native-packager, so the only thing I needed to for a
Dockerfile was run
sbt docker:publishLocal. Play itself takes up barely any memory, but the JVM is used to having a bunch of memory available – the free tier is only 256 MB, so it was time to get creative.
dockerBaseImage := "ibm-semeru-runtimes:open-17-jre-focal" Universal / javaOptions += "-J-XX:MaxRAM=70m"
Then, I had to add the explicit
add-opens required by JDK 17 as
--illegal-access=permit is gone. I don't think there's any way to avoid this for now.
Universal / javaOptions ++= Seq( "-J--add-opens=java.base/java.lang=ALL-UNNAMED", "-J--add-opens=java.base/sun.security.ssl=ALL-UNNAMED", "-J--add-opens=java.base/sun.security.util=ALL-UNNAMED" )
I had to make sure the internal sqlite database used by Blacklite was writable:
dockerChmodType := DockerChmodType.UserGroupWriteExecute
And I had to disable the PID file:
Universal / javaOptions += "-Dpidfile.path=/dev/null"
You can see build.sbt for the actual implementation.
For some reason the
logs directory wouldn't be created by
sbt docker:publishLocal so I added it to
dist directory for deployment:
mkdir -p dist/logs touch dist/logs/.README
I didn't have to set up HTTPS or anything special for fly.toml. I did have to set up some fly secrets:
fly secrets set PLAY_APP_SECRET=<secret> fly secrets set SENTRY_DSN=$SENTRY_DSN fly secrets set HONEYCOMB_API_KEY=$HONEYCOMB_API_KEY
and then it was just a case of creating docker images and running
sbt clean stage docker:publishLocal cd target/docker/stage fly deploy --app terse-logback-showcase
And now https://terse-logback-showcase.fly.dev/ is up! It has pictures of cats.