-
Hi, I have used the appender with JSON layout to include a JSON object in the message attribute of each log message by using ObjectMessage. <Console name="console-jsonlayout" target="SYSTEM_OUT">
<JsonLayout properties="true" compact="true" eventEol="true" complete="false" objectMessageAsJsonObject="true" charset="UTF-8" />
</Console> Log output:
This worked fine so. However I want to use the appender with JsonTemplate to create log messages that fit the ElasticSearch layout. <Console name="console-jsontemplate" target="SYSTEM_OUT">
<JsonTemplateLayout eventTemplateUri="classpath:EcsLayout.json" />
</Console> The problem now is, that the ObjectMessage containing my own message Object is now just being added with its instance hash: Log output: So my question is: For JsonLayout there was the parameter objectMessageAsJsonObject="true" to add my message entity as JSON to the log entry instead of its instance hash - how can I achieve this with JsonTemplateLayout? Thank you in advance! |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 12 replies
-
For one, we strongly recommend all JTL falls back to Creating a custom message resolverYou need to create a custom message resolver and its factory. See the Extending section of the JTL manual for an example. There you can reuse code from Paying somebody to implement LOG4J2-3082I happen to be the JTL creator and maintainer. 😅 Though Log4j is more than an individual. Check out our sponsorship page. You can sponsor either me or another Log4j maintainer of your preference to implement LOG4J2-3082. |
Beta Was this translation helpful? Give feedback.
-
Hi, what goes in this custom resolver? Can you please give an example, which would create valid json message? |
Beta Was this translation helpful? Give feedback.
-
If you are logging objects that don't have a proper
Custom message factory public class JsonMessageFactory extends AbstractMessageFactory {
public static final MessageFactory2 INSTANCE = new JsonMessageFactory();
@Override
public Message newMessage(String pattern, Object... params) {
return new ParameterizedMessage(pattern, params);
}
@Override
public Message newMessage(Object obj) {
return new JsonObjectMessage(obj);
}
private static class JsonObjectMessage extends ObjectMessage implements MultiformatMessage {
private static final String[] FORMATS = new String[] {"JSON"};
public JsonObjectMessage(Object obj) {
super(obj);
}
@Override
public String[] getFormats() {
return FORMATS;
}
@Override
public String getFormattedMessage(String[] ignored) {
return getFormattedMessage();
}
@Override
public String getFormattedMessage() {
// Insert your logic here:
Object obj = getParameter();
...
}
}
} |
Beta Was this translation helpful? Give feedback.
-
Thank you for response.
Before using JsonTemplateLayout i used to
log in the following way: logger.debug(gson.toJson(myNestedObject):
The result was that not the whole java log record was jsonized, but just
the message part. It was ok, but i wanted both to have it all jsonized and
for the result to be more elastic friendly
So i used the recommended JsonTemplateLayout. It did the trick regarding
making the whole of log level jsonized, but when i needed to log the same
nested object with
gson.toJson(nestedObject) somehow escape backslashes appeared everywhere
(only in the message part of the log record)
My question is, if i implement in the way you suggest, what guarantees no
backslashes will be generated?
What is the advantage of message resolver over my previous approach, if at
the end i still have to use Gson for example?
Another thing i could not understand on the official docs: if i want to add
another property at the root level of the JsonTemplateLayout, is it
possible to sippe add another key+value, or i absolutely must use the
additionalFields described in the official docs.
Thank you in advance for your patience
…On Thu, Jul 18, 2024, 16:52 Piotr P. Karwasz ***@***.***> wrote:
The problem now is, that the ObjectMessage containing my own message
Object is now just being added with its instance hash
If you are logging objects that don't have a proper toString() method,
you should probably take a more generic approach, that gives a meaningful
result regardless of the layout your are using:
1. Create a custom MessageFactory2
<https://logging.apache.org/log4j/2.x/javadoc/log4j-api/org/apache/logging/log4j/message/MessageFactory2.html>
that uses your favorite JSON mapper. An stub factory is shown below.
2. Pass an instance of the factory to the LogManager.getLogger()
<https://logging.apache.org/log4j/2.x/javadoc/log4j-api/org/apache/logging/log4j/LogManager.html#getLogger(org.apache.logging.log4j.message.MessageFactory)>
call:
private static final Logger logger = LogManager.getLogger(JsonMessageFactory.INSTANCE);
3. You can now safely log any Object: JTL will recognize the message
as valid JSON and will not stringify it.
Other layouts such as PatternLayout will print the
JsonMessage.getFormattedMessage() instead of Object.toString().
Custom message factory
public class JsonMessageFactory extends AbstractMessageFactory {
public static final MessageFactory2 INSTANCE = new JsonMessageFactory();
@OverRide
public Message newMessage(String pattern, Object... params) {
return new ParameterizedMessage(pattern, params);
}
@OverRide
public Message newMessage(Object obj) {
return new JsonObjectMessage(obj);
}
private static class JsonObjectMessage extends ObjectMessage implements MultiformatMessage {
private static final String[] FORMATS = new String[] {"JSON"};
public JsonObjectMessage(Object obj) {
super(obj);
}
@OverRide
public String[] getFormats() {
return FORMATS;
}
@OverRide
public String getFormattedMessage(String[] ignored) {
return getFormattedMessage();
}
@OverRide
public String getFormattedMessage() {
// Insert your logic here:
Object obj = getParameter();
...
}
}
}
—
Reply to this email directly, view it on GitHub
<#1939 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AEG5HL5OU27Y6GHDJY3JEB3ZM7CARAVCNFSM6AAAAABLCPC6Z6VHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTAMBYGUYDMMQ>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
Hi, public class ExampleClass {
private static final String property 1= "AAA";
private static final String property 2= "BBB";
// constructor
public void logMethod(Object nestedObject) {
log.info(nestedObject);
}
} I would like to to have a log output, using the JTL, which has the following structure: {
"property 1" : "AAA",
"property 2" : "BBB",
"message": // here i need my nestedObject as json
} i need this whole output to be elastic friendly
{
"@timestamp": {
"$resolver": "timestamp",
"pattern": {
"format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
"timeZone": "UTC"
}
},
"ecs.version": "1.2.0"
....
....
.....
"property 1" : "AAA",
"property 2" : "BBB"
} |
Beta Was this translation helpful? Give feedback.
-
@miberg81, imagine I try to insert the following two documents into Elasticsearch:
[Last time I checked,] Elastic will fail on the 2nd document, since its type for field @miberg81, I have the impression you're trying to solve a problem that doesn't exist. Instead of providing full flexibility, start with basics, grow your experience, and extend your setup when it is needed. |
Beta Was this translation helpful? Give feedback.
For one, we strongly recommend all
Gelf-
andJsonLayout
users to migrate toJsonTemplateLayout
, JTL for short. It is feature-rich, faster, and customizable; simply better. Hence, you are on the right path.JTL falls back to
Object#toString()
for types that are not known to it. Earlier I created LOG4J2-3082 to allow JTL to use external serializers (e.g., Jackson) too, though I am swamped with other Log4j priorities. Though you can still achieve this using a custom message resolver.Creating a custom message resolver
You need to create a custom message resolver and its factory. See the Extending section of the JTL manual for an example. There you can reuse code from
org.apache.logging.log4j…