All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.graylog2.syslog4j.impl.message.structured.StructuredSyslogMessage Maven / Gradle / Ivy

Go to download

Syslog4j provides client and server implementations of the BSD Syslog protocol (RFC 3164) and the draft "structured syslog" protocol (RFC Draft). This is a repackaged fork used in Graylog2, as the original package has no recent versions published to Maven Central.

There is a newer version: 0.9.61
Show newest version
package org.graylog2.syslog4j.impl.message.structured;

import org.apache.commons.lang3.StringUtils;
import org.graylog2.syslog4j.SyslogConstants;
import org.graylog2.syslog4j.impl.message.AbstractSyslogMessage;
import org.graylog2.syslog4j.util.Preconditions;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * SyslogStructuredMessage extends AbstractSyslogMessage's ability to provide
 * support for turning POJO (Plain Ol' Java Objects) into Syslog messages. It
 * adds support for structured syslog messages as specified by
 * draft-ietf-syslog-protocol-23. More information here:
 * 

*

* http://tools.ietf.org/html/draft-ietf-syslog-protocol-23#section-6 *

*

*

* Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy of the * LGPL license is available in the META-INF folder in all distributions of * Syslog4j and in the base directory of the "doc" ZIP. *

* * @author Manish Motwani * @version $Id: StructuredSyslogMessage.java,v 1.5 2010/09/11 16:49:24 cvs Exp $ */ public class StructuredSyslogMessage extends AbstractSyslogMessage implements StructuredSyslogMessageIF { public static final String EMPTY_STRUCTURED_DATA_PREFIX = "- - "; public static final int EMPTY_STRUCTURED_DATA_PREFIX_LENGTH = EMPTY_STRUCTURED_DATA_PREFIX.length(); private String messageId; private Map> structuredData; private String message; private String procId; private StructuredSyslogMessage() { this.messageId = null; this.message = null; this.procId = null; this.structuredData = null; } /** * Constructs the {@link StructuredSyslogMessage} using MSGID, * STRUCTURED-DATA and MSG fields, as described in: * *

* http://tools.ietf.org/html/draft-ietf-syslog-protocol-23#section-6 *

* * The Map must be a String -> (Map of String -> String), which encompasses * the STRUCTURED-DATA field described in above document. * * @param messageId * @param structuredData * @param message */ public StructuredSyslogMessage(final String messageId, final String procId, final Map> structuredData, final String message) { super(); this.messageId = messageId; this.procId = procId; this.structuredData = structuredData; this.message = message; } /** * Parses and loads a {@link StructuredSyslogMessage} from string. * * @param syslogMessageStr * @return Returns an instance of StructuredSyslogMessage. */ public static StructuredSyslogMessage fromString( final String syslogMessageStr) { final StructuredSyslogMessage syslogMessage = new StructuredSyslogMessage(); syslogMessage.deserialize(syslogMessageStr); return syslogMessage; } private void deserialize(final String stringMessage) { // Check if the RFC5424 MSGID and STRUCTURED-DATA fields are empty. // This avoids throwing an exception and also strips the "- - " from the message. // See: https://github.com/Graylog2/graylog2-server/issues/1161 if (stringMessage.startsWith(EMPTY_STRUCTURED_DATA_PREFIX)) { this.message = stringMessage.substring(EMPTY_STRUCTURED_DATA_PREFIX_LENGTH); return; } int start = stringMessage.indexOf('['); int end = -1; // Check correct format if (start <= 0) throw new IllegalArgumentException("Invalid Syslog string format: " + stringMessage); //SYSLOG HEADER // Divide the string in 2 sections final String syslogHeader = stringMessage.substring(0, stringMessage.indexOf('[')); // Split into tokens final String[] tokens = syslogHeader.split(" "); // Check number of tokens must be 1 -- rest of the header should already // be stripped if (tokens.length != 1) { throw new IllegalArgumentException("Invalid Syslog string format: " + stringMessage); } this.messageId = SyslogConstants.STRUCTURED_DATA_NILVALUE.equals(tokens[0]) ? null : tokens[0]; //STRUCTURED_DATA if (stringMessage.contains(SyslogConstants.STRUCTURED_DATA_EMPTY_VALUE)){ this.structuredData = Collections.emptyMap(); end=stringMessage.indexOf(SyslogConstants.STRUCTURED_DATA_EMPTY_VALUE)+4; } else { final Map> structuredDataMap = new HashMap>(); while(start < stringMessage.length() && matchChar(stringMessage, start, '[') == start) { Preconditions.checkArgument(stringMessage.charAt(start) == '[', "Invalid structured data in syslog message '%s'", stringMessage); end = matchChar(stringMessage, start, ']'); Preconditions.checkArgument(end != -1 && stringMessage.charAt(end) == ']', "Invalid structured data in syslog message '%s'", stringMessage); String key = null; Map keyMap = new HashMap(); while (start < end) { if (key == null) { final int keyEnd = matchChar(stringMessage, ++start, ']', ' '); // Key can be terminated by a space (then more fields to follow) or a ] key = stringMessage.substring(start, keyEnd); start = keyEnd; // start either points after the end (then the while terminates) or at the first char of the first field. } else { Preconditions.checkArgument(start < stringMessage.length() && stringMessage.charAt(start) == ' ', "Invalid structured data in syslog message '%s'", stringMessage); start = start + 1; // Start points at the space behind either the key or the previous value final int equalsIndex = stringMessage.indexOf('=', start); // Equals terminates the field name. Preconditions.checkArgument(equalsIndex != -1, "Invalid structured data in syslog message '%s'", stringMessage); Preconditions.checkArgument(stringMessage.charAt(equalsIndex + 1) == '"', "Invalid structured data in syslog message '%s'", stringMessage); // Look for the end of the value. It needs to be terminated by " final int valueEnd = matchChar(stringMessage, equalsIndex + 2, '"'); Preconditions.checkArgument(valueEnd != -1 && stringMessage.charAt(valueEnd) == '"', "Invalid structured data in syslog message '%s'", stringMessage); keyMap.put(stringMessage.substring(start, equalsIndex), unescape(stringMessage.substring(equalsIndex + 2, valueEnd))); start = valueEnd + 1; } } start++; structuredDataMap.put(key, keyMap); } this.structuredData = structuredDataMap; } //MESSAGE if ((end + 2) <= stringMessage.length()){ this.message = stringMessage.substring(end + 2); } else { this.message = ""; } } /** * Returns the MSGID field of the structured message format, as described * in: * *

* http://tools.ietf.org/html/draft-ietf-syslog-protocol-23#section-6 *

* * @return Returns the MSG ID field. */ public String getMessageId() { return this.messageId; } /** * Returns the structured data map. The Map is a String -> (Map of String -> * String), which encompasses the STRUCTURED-DATA field, as described in: * *

* http://tools.ietf.org/html/draft-ietf-syslog-protocol-23#section-6 *

* * @return Returns a Map object containing structured data. */ public Map> getStructuredData() { return this.structuredData; } /** * Returns the MSG field of the structured message format, as described in: * *

* http://tools.ietf.org/html/draft-ietf-syslog-protocol-23#section-6 *

* * @return Returns the MSG field. */ public String getMessage() { return this.message; } public String getProcId() { return procId; } /* * (non-Javadoc) * * @see com.nesscomputing.syslog4j.impl.message.AbstractSyslogMessage# * createMessage() */ public String createMessage() { return serialize(); } private String serialize() { if (!StructuredSyslogMessage.checkIsPrintable(getMessageId())) throw new IllegalArgumentException("Invalid message id: " + getMessageId()); final StringBuffer sb = new StringBuffer(); sb.append(StructuredSyslogMessage.nilProtect(getMessageId())); sb.append(' '); if (getStructuredData() == null || getStructuredData().size() == 0) { // This is not desired, but rsyslogd does not store version 1 syslog // message correctly if // there is no // structured data present sb.append(SyslogConstants.STRUCTURED_DATA_EMPTY_VALUE); } else { Set>> sdEntrySet = getStructuredData().entrySet(); for (Iterator>> it = sdEntrySet.iterator(); it.hasNext();) { final Map.Entry> sdElement = it.next(); final String sdId = sdElement.getKey(); if (StringUtils.isBlank(sdId) || !StructuredSyslogMessage.checkIsPrintable(sdId)) { throw new IllegalArgumentException("Illegal structured data id: " + sdId); } sb.append('[').append(sdId); final Map sdParams = sdElement.getValue(); if (sdParams != null) { Set> entrySet = sdParams.entrySet(); for (Iterator> it2 = entrySet.iterator(); it2.hasNext();) { Map.Entry entry = it2.next(); final String paramName = entry.getKey(); final String paramValue = entry.getValue(); if (StringUtils.isBlank(paramName) || !StructuredSyslogMessage.checkIsPrintable(paramName)) throw new IllegalArgumentException("Illegal structured data parameter name: " + paramName); if (paramValue == null) throw new IllegalArgumentException("Null structured data parameter value for parameter name: " + paramName); sb.append(' '); sb.append(paramName); sb.append('=').append('"'); StructuredSyslogMessage.sdEscape(sb, paramValue); sb.append('"'); } } sb.append(']'); } } if (!StringUtils.isEmpty(getMessage())) { sb.append(' '); sb.append(StructuredSyslogMessage.nilProtect(getMessage())); } return sb.toString(); } public static void sdEscape(final StringBuffer sb, final String value) { for (int i = 0; i < value.length(); i++) { final char c = value.charAt(i); if (c == '"' || c == '\\' || c == ']') { sb.append('\\'); } sb.append(c); } } public static boolean checkIsPrintable(final String value) { if (value == null) return true; for (int i = 0; i < value.length(); i++) { final char c = value.charAt(i); if (c < 33 || c > 126) return false; } return true; } public static String nilProtect(final String value) { if (StringUtils.isBlank(value)) { return SyslogConstants.STRUCTURED_DATA_NILVALUE; } return value; } public static int matchChar(final String data, final int start, final char ... matchChars) { int ptr = start; for(;;) { if (ptr >= data.length()) { return -1; } if (data.charAt(ptr) == '\\') { ptr++; ptr++; continue; } if (ptr >= data.length()) { return -1; } for (int i = 0; i < matchChars.length; i++) { if (data.charAt(ptr) == matchChars[i]) { return ptr; } } ptr++; } } private String unescape(final String str) { if (str.indexOf('\\') == -1) { return str; } final StringBuilder sb = new StringBuilder(); for (int i = 0; i < str.length(); i++) { if (str.charAt(i) == '\\') { continue; } sb.append(str.charAt(i)); } return sb.toString(); } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((message == null) ? 0 : message.hashCode()); result = prime * result + ((messageId == null) ? 0 : messageId.hashCode()); result = prime * result + ((structuredData == null) ? 0 : structuredData.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; StructuredSyslogMessage other = (StructuredSyslogMessage) obj; if (message == null) { if (other.message != null) return false; } else if (!message.equals(other.message)) return false; if (messageId == null) { if (other.messageId != null) return false; } else if (!messageId.equals(other.messageId)) return false; if (structuredData == null) { if (other.structuredData != null) return false; } else if (!structuredData.equals(other.structuredData)) return false; return true; } public String toString() { return serialize(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy