/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache license, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.message;
import java.util.Map;
import org.apache.logging.log4j.util.EnglishEnums;
import org.apache.logging.log4j.util.StringBuilders;
Represents a Message that conforms to an RFC 5424 StructuredData element along with the syslog message.
Thread-safety note: the contents of this message can be modified after construction.
When using asynchronous loggers and appenders it is not recommended to modify this message after the message is
logged, because it is undefined whether the logged message string will contain the old values or the modified
values.
See Also:
/**
* Represents a Message that conforms to an RFC 5424 StructuredData element along with the syslog message.
* <p>
* Thread-safety note: the contents of this message can be modified after construction.
* When using asynchronous loggers and appenders it is not recommended to modify this message after the message is
* logged, because it is undefined whether the logged message string will contain the old values or the modified
* values.
* </p>
*
* @see <a href="https://tools.ietf.org/html/rfc5424">RFC 5424</a>
*/
@AsynchronouslyFormattable
public class StructuredDataMessage extends MapMessage<StructuredDataMessage, String> {
private static final long serialVersionUID = 1703221292892071920L;
private static final int MAX_LENGTH = 32;
private static final int HASHVAL = 31;
private StructuredDataId id;
private String message;
private String type;
private final int maxLength;
Supported formats.
/**
* Supported formats.
*/
public enum Format {
The map should be formatted as XML. /** The map should be formatted as XML. */
XML,
Full message format includes the type and message. /** Full message format includes the type and message. */
FULL
}
Creates a StructuredDataMessage using an ID (max 32 characters), message, and type (max 32 characters).
Params: - id – The String id.
- msg – The message.
- type – The message type.
/**
* Creates a StructuredDataMessage using an ID (max 32 characters), message, and type (max 32 characters).
* @param id The String id.
* @param msg The message.
* @param type The message type.
*/
public StructuredDataMessage(final String id, final String msg, final String type) {
this(id, msg, type, MAX_LENGTH);
}
Creates a StructuredDataMessage using an ID (user specified max characters), message, and type (user specified
maximum number of characters).
Params: - id – The String id.
- msg – The message.
- type – The message type.
- maxLength – The maximum length of keys;
Since: 2.9
/**
* Creates a StructuredDataMessage using an ID (user specified max characters), message, and type (user specified
* maximum number of characters).
* @param id The String id.
* @param msg The message.
* @param type The message type.
* @param maxLength The maximum length of keys;
* @since 2.9
*/
public StructuredDataMessage(final String id, final String msg, final String type, final int maxLength) {
this.id = new StructuredDataId(id, null, null, maxLength);
this.message = msg;
this.type = type;
this.maxLength = maxLength;
}
Creates a StructuredDataMessage using an ID (max 32 characters), message, type (max 32 characters), and an
initial map of structured data to include.
Params: - id – The String id.
- msg – The message.
- type – The message type.
- data – The StructuredData map.
/**
* Creates a StructuredDataMessage using an ID (max 32 characters), message, type (max 32 characters), and an
* initial map of structured data to include.
* @param id The String id.
* @param msg The message.
* @param type The message type.
* @param data The StructuredData map.
*/
public StructuredDataMessage(final String id, final String msg, final String type,
final Map<String, String> data) {
this(id, msg, type, data, MAX_LENGTH);
}
Creates a StructuredDataMessage using an (user specified max characters), message, and type (user specified
maximum number of characters, and an initial map of structured data to include.
Params: - id – The String id.
- msg – The message.
- type – The message type.
- data – The StructuredData map.
- maxLength – The maximum length of keys;
Since: 2.9
/**
* Creates a StructuredDataMessage using an (user specified max characters), message, and type (user specified
* maximum number of characters, and an initial map of structured data to include.
* @param id The String id.
* @param msg The message.
* @param type The message type.
* @param data The StructuredData map.
* @param maxLength The maximum length of keys;
* @since 2.9
*/
public StructuredDataMessage(final String id, final String msg, final String type,
final Map<String, String> data, final int maxLength) {
super(data);
this.id = new StructuredDataId(id, null, null, maxLength);
this.message = msg;
this.type = type;
this.maxLength = maxLength;
}
Creates a StructuredDataMessage using a StructuredDataId, message, and type (max 32 characters).
Params: - id – The StructuredDataId.
- msg – The message.
- type – The message type.
/**
* Creates a StructuredDataMessage using a StructuredDataId, message, and type (max 32 characters).
* @param id The StructuredDataId.
* @param msg The message.
* @param type The message type.
*/
public StructuredDataMessage(final StructuredDataId id, final String msg, final String type) {
this(id, msg, type, MAX_LENGTH);
}
Creates a StructuredDataMessage using a StructuredDataId, message, and type (max 32 characters).
Params: - id – The StructuredDataId.
- msg – The message.
- type – The message type.
- maxLength – The maximum length of keys;
Since: 2.9
/**
* Creates a StructuredDataMessage using a StructuredDataId, message, and type (max 32 characters).
* @param id The StructuredDataId.
* @param msg The message.
* @param type The message type.
* @param maxLength The maximum length of keys;
* @since 2.9
*/
public StructuredDataMessage(final StructuredDataId id, final String msg, final String type, final int maxLength) {
this.id = id;
this.message = msg;
this.type = type;
this.maxLength = maxLength;
}
Creates a StructuredDataMessage using a StructuredDataId, message, type (max 32 characters), and an initial map
of structured data to include.
Params: - id – The StructuredDataId.
- msg – The message.
- type – The message type.
- data – The StructuredData map.
/**
* Creates a StructuredDataMessage using a StructuredDataId, message, type (max 32 characters), and an initial map
* of structured data to include.
* @param id The StructuredDataId.
* @param msg The message.
* @param type The message type.
* @param data The StructuredData map.
*/
public StructuredDataMessage(final StructuredDataId id, final String msg, final String type,
final Map<String, String> data) {
this(id, msg, type, data, MAX_LENGTH);
}
Creates a StructuredDataMessage using a StructuredDataId, message, type (max 32 characters), and an initial map
of structured data to include.
Params: - id – The StructuredDataId.
- msg – The message.
- type – The message type.
- data – The StructuredData map.
- maxLength – The maximum length of keys;
Since: 2.9
/**
* Creates a StructuredDataMessage using a StructuredDataId, message, type (max 32 characters), and an initial map
* of structured data to include.
* @param id The StructuredDataId.
* @param msg The message.
* @param type The message type.
* @param data The StructuredData map.
* @param maxLength The maximum length of keys;
* @since 2.9
*/
public StructuredDataMessage(final StructuredDataId id, final String msg, final String type,
final Map<String, String> data, final int maxLength) {
super(data);
this.id = id;
this.message = msg;
this.type = type;
this.maxLength = maxLength;
}
Constructor based on a StructuredDataMessage.
Params: - msg – The StructuredDataMessage.
- map – The StructuredData map.
/**
* Constructor based on a StructuredDataMessage.
* @param msg The StructuredDataMessage.
* @param map The StructuredData map.
*/
private StructuredDataMessage(final StructuredDataMessage msg, final Map<String, String> map) {
super(map);
this.id = msg.id;
this.message = msg.message;
this.type = msg.type;
this.maxLength = MAX_LENGTH;
}
Basic constructor.
/**
* Basic constructor.
*/
protected StructuredDataMessage() {
maxLength = MAX_LENGTH;
}
Returns the supported formats.
Returns: An array of the supported format names.
/**
* Returns the supported formats.
* @return An array of the supported format names.
*/
@Override
public String[] getFormats() {
final String[] formats = new String[Format.values().length];
int i = 0;
for (final Format format : Format.values()) {
formats[i++] = format.name();
}
return formats;
}
Returns this message id.
Returns: the StructuredDataId.
/**
* Returns this message id.
* @return the StructuredDataId.
*/
public StructuredDataId getId() {
return id;
}
Sets the id from a String. This ID can be at most 32 characters long.
Params: - id – The String id.
/**
* Sets the id from a String. This ID can be at most 32 characters long.
* @param id The String id.
*/
protected void setId(final String id) {
this.id = new StructuredDataId(id, null, null);
}
Sets the id.
Params: - id – The StructuredDataId.
/**
* Sets the id.
* @param id The StructuredDataId.
*/
protected void setId(final StructuredDataId id) {
this.id = id;
}
Returns this message type.
Returns: the type.
/**
* Returns this message type.
* @return the type.
*/
public String getType() {
return type;
}
protected void setType(final String type) {
if (type.length() > MAX_LENGTH) {
throw new IllegalArgumentException("structured data type exceeds maximum length of 32 characters: " + type);
}
this.type = type;
}
@Override
public void formatTo(final StringBuilder buffer) {
asString(Format.FULL, null, buffer);
}
@Override
public void formatTo(final String[] formats, final StringBuilder buffer) {
asString(getFormat(formats), null, buffer);
}
Returns the message.
Returns: the message.
/**
* Returns the message.
* @return the message.
*/
@Override
public String getFormat() {
return message;
}
protected void setMessageFormat(final String msg) {
this.message = msg;
}
Formats the structured data as described in RFC 5424.
Returns: The formatted String.
/**
* Formats the structured data as described in RFC 5424.
*
* @return The formatted String.
*/
@Override
public String asString() {
return asString(Format.FULL, null);
}
Formats the structured data as described in RFC 5424.
Params: - format – The format identifier. Ignored in this implementation.
Returns: The formatted String.
/**
* Formats the structured data as described in RFC 5424.
*
* @param format The format identifier. Ignored in this implementation.
* @return The formatted String.
*/
@Override
public String asString(final String format) {
try {
return asString(EnglishEnums.valueOf(Format.class, format), null);
} catch (final IllegalArgumentException ex) {
return asString();
}
}
Formats the structured data as described in RFC 5424.
Params: - format – "full" will include the type and message. null will return only the STRUCTURED-DATA as
described in RFC 5424
- structuredDataId – The SD-ID as described in RFC 5424. If null the value in the StructuredData
will be used.
Returns: The formatted String.
/**
* Formats the structured data as described in RFC 5424.
*
* @param format "full" will include the type and message. null will return only the STRUCTURED-DATA as
* described in RFC 5424
* @param structuredDataId The SD-ID as described in RFC 5424. If null the value in the StructuredData
* will be used.
* @return The formatted String.
*/
public final String asString(final Format format, final StructuredDataId structuredDataId) {
final StringBuilder sb = new StringBuilder();
asString(format, structuredDataId, sb);
return sb.toString();
}
Formats the structured data as described in RFC 5424.
Params: - format – "full" will include the type and message. null will return only the STRUCTURED-DATA as
described in RFC 5424
- structuredDataId – The SD-ID as described in RFC 5424. If null the value in the StructuredData
will be used.
- sb – The StringBuilder to append the formatted message to.
/**
* Formats the structured data as described in RFC 5424.
*
* @param format "full" will include the type and message. null will return only the STRUCTURED-DATA as
* described in RFC 5424
* @param structuredDataId The SD-ID as described in RFC 5424. If null the value in the StructuredData
* will be used.
* @param sb The StringBuilder to append the formatted message to.
*/
public final void asString(final Format format, final StructuredDataId structuredDataId, final StringBuilder sb) {
final boolean full = Format.FULL.equals(format);
if (full) {
final String myType = getType();
if (myType == null) {
return;
}
sb.append(getType()).append(' ');
}
StructuredDataId sdId = getId();
if (sdId != null) {
sdId = sdId.makeId(structuredDataId); // returns sdId if structuredDataId is null
} else {
sdId = structuredDataId;
}
if (sdId == null || sdId.getName() == null) {
return;
}
if (Format.XML.equals(format)) {
asXml(sdId, sb);
return;
}
sb.append('[');
StringBuilders.appendValue(sb, sdId); // avoids toString if implements StringBuilderFormattable
sb.append(' ');
appendMap(sb);
sb.append(']');
if (full) {
final String msg = getFormat();
if (msg != null) {
sb.append(' ').append(msg);
}
}
}
private void asXml(final StructuredDataId structuredDataId, final StringBuilder sb) {
sb.append("<StructuredData>\n");
sb.append("<type>").append(type).append("</type>\n");
sb.append("<id>").append(structuredDataId).append("</id>\n");
super.asXml(sb);
sb.append("\n</StructuredData>\n");
}
Formats the message and return it.
Returns: the formatted message.
/**
* Formats the message and return it.
* @return the formatted message.
*/
@Override
public String getFormattedMessage() {
return asString(Format.FULL, null);
}
Formats the message according the the specified format.
Params: - formats – An array of Strings that provide extra information about how to format the message.
StructuredDataMessage accepts only a format of "FULL" which will cause the event type to be
prepended and the event message to be appended. Specifying any other value will cause only the
StructuredData to be included. The default is "FULL".
Returns: the formatted message.
/**
* Formats the message according the the specified format.
* @param formats An array of Strings that provide extra information about how to format the message.
* StructuredDataMessage accepts only a format of "FULL" which will cause the event type to be
* prepended and the event message to be appended. Specifying any other value will cause only the
* StructuredData to be included. The default is "FULL".
*
* @return the formatted message.
*/
@Override
public String getFormattedMessage(final String[] formats) {
return asString(getFormat(formats), null);
}
private Format getFormat(final String[] formats) {
if (formats != null && formats.length > 0) {
for (int i = 0; i < formats.length; i++) {
final String format = formats[i];
if (Format.XML.name().equalsIgnoreCase(format)) {
return Format.XML;
} else if (Format.FULL.name().equalsIgnoreCase(format)) {
return Format.FULL;
}
}
return null;
}
return Format.FULL;
}
@Override
public String toString() {
return asString(null, null);
}
@Override
public StructuredDataMessage newInstance(final Map<String, String> map) {
return new StructuredDataMessage(this, map);
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final StructuredDataMessage that = (StructuredDataMessage) o;
if (!super.equals(o)) {
return false;
}
if (type != null ? !type.equals(that.type) : that.type != null) {
return false;
}
if (id != null ? !id.equals(that.id) : that.id != null) {
return false;
}
if (message != null ? !message.equals(that.message) : that.message != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = HASHVAL * result + (type != null ? type.hashCode() : 0);
result = HASHVAL * result + (id != null ? id.hashCode() : 0);
result = HASHVAL * result + (message != null ? message.hashCode() : 0);
return result;
}
@Override
protected void validate(final String key, final boolean value) {
validateKey(key);
}
Since: 2.9
/**
* @since 2.9
*/
@Override
protected void validate(final String key, final byte value) {
validateKey(key);
}
Since: 2.9
/**
* @since 2.9
*/
@Override
protected void validate(final String key, final char value) {
validateKey(key);
}
Since: 2.9
/**
* @since 2.9
*/
@Override
protected void validate(final String key, final double value) {
validateKey(key);
}
Since: 2.9
/**
* @since 2.9
*/
@Override
protected void validate(final String key, final float value) {
validateKey(key);
}
Since: 2.9
/**
* @since 2.9
*/
@Override
protected void validate(final String key, final int value) {
validateKey(key);
}
Since: 2.9
/**
* @since 2.9
*/
@Override
protected void validate(final String key, final long value) {
validateKey(key);
}
Since: 2.9
/**
* @since 2.9
*/
@Override
protected void validate(final String key, final Object value) {
validateKey(key);
}
Since: 2.9
/**
* @since 2.9
*/
@Override
protected void validate(final String key, final short value) {
validateKey(key);
}
@Override
protected void validate(final String key, final String value) {
validateKey(key);
}
protected void validateKey(final String key) {
if (maxLength > 0 && key.length() > maxLength) {
throw new IllegalArgumentException("Structured data keys are limited to " + maxLength +
" characters. key: " + key);
}
for (int i = 0; i < key.length(); i++) {
final char c = key.charAt(i);
if (c < '!' || c > '~' || c == '=' || c == ']' || c == '"') {
throw new IllegalArgumentException("Structured data keys must contain printable US ASCII characters" +
"and may not contain a space, =, ], or \"");
}
}
}
}