I'd like find an API that will allow me to provide a specific canonical set of information in all of my critical log points of my application. More specifically, it would be a multi-line message with the following information (in addition to the basics):
- Logging Category
- Short Description Title
- Description
- Response Action (damage control) my application will take
- Details (exception information, etc.)
With a single multi-line log looking, for example, like so:
2017-11-10 14:26:59,156 [main] WARN o.s.t.c.s.ExampleClass:
Caption: Unconformable data
Description: The data provided from the X datasource in order to perform Y operation could not be translated
Response Action: Application will discard unusable data into this component's DLQ
Details: The data string "x" was not of expected Integer type
<Some stacktrace>....
This is a verbose statement that would be very informative about exactly what occurred, where it occurred, and what the application is doing in response to the event of the exception.
The closest I could find was the JBoss logging API and an example of some code I found in the ActiveMQ Artemis source. The message format declaration can be defined in a single file like so:
@LogMessage(level = Logger.Level.WARN)
@Message(id = 202008, value = "Failed to check Address list {0}.",
format = Message.Format.MESSAGE_FORMAT)
void failedToParseAddressList(@Cause Exception e, String addressList);
And one would log a line with this message in their code by writing:
ActiveMQUtilLogger.LOGGER.failedToParseAddressList(e, addressList);
That's the closest I could find to what I was looking for. Very cool. However, I'm not using JBoss (and also don't want to lock into that API).
I can use LOG4J, which has a StructuredDataMessage and Structured Data Lookup which can be used in a Layout, and I'll by default end up using that; my code could delegate to some StructuredDataMessage
factory to solve this. However, it's a little bit bulkier than using something like this JBoss API.
Does anyone have any suggestions for this problem -- whether it's another API, a code patterns, or a nifty trick?
You haven't stated any specific reasons why you wouldn't use log4j2 so I'd suggest going that route. As you point out it provides the
StructuredDataMessage
which you can use to fit your needs. Although in this case I would suggest usingMapMessage
since your example didn't include things likeid
andtype
which are built into theStructuredDataMessage
class.Here's some quick sample code:
and a log4j2.xml configuration file to go along with it:
Here is some sample output:
Some final thoughts:
I agree, the factory pattern would be a good choice here. As I commented in the sample code you could move the
buildMsg
method to a factory class.I don't really see how it's any bulkier. If you find that most of the time only one or two of the items in the
MapMessage
are changing you could easily write very specific methods similar to the API you mentioned. To add to the above example:You would probably want to assign constants to the strings being used in this method, but as I said this is just a quick example.