quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.53k stars 2.61k forks source link

Customizing the JSON logging formatter #41525

Open michaeldimchuk opened 2 months ago

michaeldimchuk commented 2 months ago

Description

I use structured (JSON) logging quite a bit and need to be able to modify the properties of log records being generated by the application in order to be able to do filtering on log messages.

One specific example is for dealing with exceptions, where I'll pass enum based error codes into any thrown exception, with the enum name being automatically injected into a log record which logged that exception, like in the label or errorCode property. This allows for exceptions to be filtered / filtered out based on those error codes, making it a lot easier to go through logs. In theory MDC could be used for this, but it feels wrong to add a thread local error code just to have it show up in the one log record that actually prints the exception log.

With Logback this is fairly easy, and can be achieved by extending the JsonLayout class it uses. I looked into something similar with Quarkus, and while the JsonFormatter class seems to support this via the StructuredFormatter#before method as suggested here, there's no easy to extend the Quarkus JsonFormatter because it's initialized directly in the recorder.

The feature request would be to either allow the quarkus-logging-json extension to have alternative implementations (instances of JsonFormatter) to be provided to be used by Quarkus to format JSON logs, or an alternative mechanism to augment log records, for example by overriding the before method and running optional interceptors (provided via CDI) on the generator / log record.

Implementation ideas

Not super familiar with recorders and the way formatter creation is implemented right now, playing around with it, I wasn't able to create the JsonFormatter instance with an @ApplicationScoped JsonFormatterFactory class that just creates a new instance and have that be injected into the recorder with a synthetic injection point.

If going with a more basic @Producer based approach, then either the Formatter beans could have @Default on them allowing for overrides, or the existing JsonFormatter class could override the before method and take in a list of LogRecordInterceptor implementations, which would be allowed to modify the log record before it's written. I'm not fully familiar with the potential impact in switching from recorders to producers though.

quarkus-bot[bot] commented 2 months ago

/cc @dmlloyd (logging)

melloware commented 1 month ago

@michaeldimchuk does the Quarkus-logging-json extension offer you any hope?

It's a Quarkiverse extension.

michaeldimchuk commented 1 month ago

That'll definitely work and that is an extension I looked at before, I was just hoping to use something as close to a native Quarkus extension as possible, and since there's an official extension for JSON logging, it seems like a reasonable feature to have.

I don't know how much it matters, but the Quarkiverse extension isn't updated very frequently to update for the version of the Quarkus bom, which isn't causing any issues in my project right now, but has with some custom extensions I've written before.