From dd8bbcd6bef11bffdd6cfa0ee17a14d476bb8505 Mon Sep 17 00:00:00 2001 From: Bernd Ahlers Date: Wed, 14 Jan 2015 14:40:25 +0100 Subject: [PATCH] Use structured syslog parser from the NessComputing syslog4j fork. Fixes parsing of structured data values that contain whitespace. This addresses issues from Graylog2/graylog2-server#845. Parser and test code from NessComputing/syslog4j@038caf2. --- pom.xml | 34 +++ .../syslog4j/impl/AbstractSyslog.java | 8 +- .../structured/StructuredSyslogMessage.java | 287 +++++++++--------- .../StructuredSyslogServerEvent.java | 2 +- .../server/impl/structured/TestMatchChar.java | 40 +++ .../StructuredSyslogMessageTest.java | 260 ++++++++++++++++ 6 files changed, 483 insertions(+), 148 deletions(-) create mode 100644 src/test/java/org/graylog2/syslog4j/server/impl/structured/TestMatchChar.java create mode 100644 src/test/java/org/graylog2/syslog4j/test/message/structured/StructuredSyslogMessageTest.java diff --git a/pom.xml b/pom.xml index 6baea7b..97b50c4 100644 --- a/pom.xml +++ b/pom.xml @@ -73,6 +73,16 @@ 1.5.4 true + + com.google.guava + guava + 18.0 + + + org.apache.commons + commons-lang3 + 3.3.2 + log4j log4j @@ -91,6 +101,12 @@ 6.8.8 test + + junit + junit + 4.11 + test + @@ -164,6 +180,24 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 2.18.1 + + + + org.apache.maven.surefire + surefire-junit4 + 2.18.1 + + + org.apache.maven.surefire + surefire-testng + 2.18.1 + + + diff --git a/src/main/java/org/graylog2/syslog4j/impl/AbstractSyslog.java b/src/main/java/org/graylog2/syslog4j/impl/AbstractSyslog.java index 0331430..97364f5 100644 --- a/src/main/java/org/graylog2/syslog4j/impl/AbstractSyslog.java +++ b/src/main/java/org/graylog2/syslog4j/impl/AbstractSyslog.java @@ -1,8 +1,5 @@ package org.graylog2.syslog4j.impl; -import java.util.ArrayList; -import java.util.List; - import org.graylog2.syslog4j.SyslogBackLogHandlerIF; import org.graylog2.syslog4j.SyslogConfigIF; import org.graylog2.syslog4j.SyslogIF; @@ -16,6 +13,9 @@ import org.graylog2.syslog4j.impl.message.structured.StructuredSyslogMessage; import org.graylog2.syslog4j.impl.message.structured.StructuredSyslogMessageIF; import org.graylog2.syslog4j.util.SyslogUtility; +import java.util.ArrayList; +import java.util.List; + /** * AbstractSyslog provides a base abstract implementation of the SyslogIF. *

@@ -115,7 +115,7 @@ public abstract class AbstractSyslog implements SyslogIF { public void log(int level, String message) { if (this.syslogConfig.isUseStructuredData()) { - StructuredSyslogMessageIF structuredMessage = new StructuredSyslogMessage(null, null, message); + StructuredSyslogMessageIF structuredMessage = new StructuredSyslogMessage(null, null, null, message); log(getStructuredMessageProcessor(), level, structuredMessage.createMessage()); diff --git a/src/main/java/org/graylog2/syslog4j/impl/message/structured/StructuredSyslogMessage.java b/src/main/java/org/graylog2/syslog4j/impl/message/structured/StructuredSyslogMessage.java index 5f9f009..0219a5e 100644 --- a/src/main/java/org/graylog2/syslog4j/impl/message/structured/StructuredSyslogMessage.java +++ b/src/main/java/org/graylog2/syslog4j/impl/message/structured/StructuredSyslogMessage.java @@ -1,13 +1,16 @@ package org.graylog2.syslog4j.impl.message.structured; -import java.util.HashMap; +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import org.apache.commons.lang3.StringUtils; +import org.graylog2.syslog4j.SyslogConstants; +import org.graylog2.syslog4j.impl.message.AbstractSyslogMessage; + +import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.Set; -import org.graylog2.syslog4j.SyslogConstants; -import org.graylog2.syslog4j.impl.message.AbstractSyslogMessage; - /** * SyslogStructuredMessage extends AbstractSyslogMessage's ability to provide * support for turning POJO (Plain Ol' Java Objects) into Syslog messages. It @@ -28,26 +31,26 @@ import org.graylog2.syslog4j.impl.message.AbstractSyslogMessage; * @version $Id: StructuredSyslogMessage.java,v 1.5 2010/09/11 16:49:24 cvs Exp $ */ public class StructuredSyslogMessage extends AbstractSyslogMessage implements StructuredSyslogMessageIF { - private static final long serialVersionUID = 3669887659567965965L; - private String messageId; - private Map structuredData; + 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. * @@ -56,45 +59,14 @@ public class StructuredSyslogMessage extends AbstractSyslogMessage implements St * @param message */ public StructuredSyslogMessage(final String messageId, - final Map structuredData, final String message) { + final String procId, + final Map> structuredData, + final String message) { super(); this.messageId = messageId; + this.procId = procId; this.structuredData = structuredData; this.message = message; - - ensureCorrectMapType(); - } - - private void ensureCorrectMapType() { - if (!(getStructuredData() == null)) { - Set sdEntrySet = getStructuredData().entrySet(); - for (Iterator it = sdEntrySet.iterator(); it.hasNext(); ) { - Map.Entry sdEntry = (Map.Entry) it.next(); - if (!(sdEntry.getKey() instanceof String)) { - throw new IllegalArgumentException( - "Structured data map must be a map of String -> (Map of String,String)"); - } - if (!(sdEntry.getValue() instanceof Map)) { - throw new IllegalArgumentException( - "Structured data map must be a map of String -> (Map of String,String)"); - } - - Set entrySet = ((Map) sdEntry.getValue()).entrySet(); - for (Iterator it2 = entrySet.iterator(); it2.hasNext(); ) { - Map.Entry entry = (Map.Entry) it2.next(); - - if (!(entry.getKey() instanceof String)) { - throw new IllegalArgumentException( - "Structured data map must be a map of String -> (Map of String,String)"); - } - if (!(entry.getValue() instanceof String)) { - throw new IllegalArgumentException( - "Structured data map must be a map of String -> (Map of String,String)"); - } - } - } - - } } /** @@ -110,91 +82,82 @@ public class StructuredSyslogMessage extends AbstractSyslogMessage implements St return syslogMessage; } - private void deserialize(final String stringMessage) { - // Check correct format - if (stringMessage.indexOf('[') <= 0) - throw new IllegalArgumentException("Invalid Syslog string format: " - + stringMessage); + private void deserialize(final String stringMessage) { + 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('[')); - String structuredDataString = stringMessage.substring(stringMessage - .indexOf('['), stringMessage.lastIndexOf(']') + 1); - - if ((stringMessage.lastIndexOf(']') + 2) <= stringMessage.length()) - this.message = stringMessage.substring(stringMessage.lastIndexOf(']') + 2); - - else { - this.message = ""; - } - + 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); + 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 = Maps.newHashMap(); + + 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 = Maps.newHashMap(); + 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 + Preconditions.checkArgument(key != null, "Invalid structured data in syslog message '%s'", stringMessage); + 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; } - this.messageId = SyslogConstants.STRUCTURED_DATA_NILVALUE.equals(tokens[0]) ? null - : tokens[0]; - - this.structuredData = new HashMap(); - if (!SyslogConstants.STRUCTURED_DATA_EMPTY_VALUE.equals(structuredDataString)) { - while (!"".equals(structuredDataString)) { - if (!structuredDataString.startsWith("[") - || structuredDataString.indexOf(']') == -1) { - throw new IllegalArgumentException( - "Invalid structured data format in Syslog message: " - + stringMessage); - } - - final String structuredDataIteration = structuredDataString - .substring(1, structuredDataString.indexOf(']')); - - final Map iterMap = new HashMap(); - - final String[] params = structuredDataIteration.split(" "); - - for (int i = 1; i < params.length; i++) { - final String[] paramIter = params[i].split("="); - if (paramIter.length != 2) { - throw new IllegalArgumentException( - "Invalid structured data format in Syslog message: " - + stringMessage); - } - - if (!paramIter[1].startsWith("\"") - || !paramIter[1].endsWith("\"")) { - throw new IllegalArgumentException( - "Invalid structured data format in Syslog message: " - + stringMessage); - } - - iterMap.put(paramIter[0], paramIter[1].substring(1, - paramIter[1].length() - 1)); - } - - this.structuredData.put(params[0], iterMap); - - if (structuredDataString.indexOf(']') != structuredDataString - .lastIndexOf(']')) { - structuredDataString = structuredDataString - .substring(structuredDataString.indexOf(']') + 1); - } else { - structuredDataString = ""; - } - } + //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 *

@@ -208,20 +171,20 @@ public class StructuredSyslogMessage extends AbstractSyslogMessage implements St /** * 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() { + 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 *

@@ -232,10 +195,15 @@ public class StructuredSyslogMessage extends AbstractSyslogMessage implements St return this.message; } + public String getProcId() + { + return procId; + } + /* * (non-Javadoc) * - * @seeorg.productivity.java.syslog4j.impl.message.AbstractSyslogMessage# + * @see com.nesscomputing.syslog4j.impl.message.AbstractSyslogMessage# * createMessage() */ public String createMessage() { @@ -259,40 +227,31 @@ public class StructuredSyslogMessage extends AbstractSyslogMessage implements St // 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 = (Map.Entry) it.next(); - final String sdId = (String) sdElement.getKey(); + Set>> sdEntrySet = getStructuredData().entrySet(); + for (Iterator>> it = sdEntrySet.iterator(); it.hasNext();) { + final Map.Entry> sdElement = it.next(); + final String sdId = sdElement.getKey(); - if (sdId == null || sdId.length() == 0 - || !StructuredSyslogMessage.checkIsPrintable(sdId)) { - throw new IllegalArgumentException( - "Illegal structured data id: " + sdId); + if (StringUtils.isBlank(sdId) || !StructuredSyslogMessage.checkIsPrintable(sdId)) { + throw new IllegalArgumentException("Illegal structured data id: " + sdId); } sb.append('[').append(sdId); - final Map sdParams = (Map) sdElement.getValue(); + final Map sdParams = sdElement.getValue(); if (sdParams != null) { - Set entrySet = sdParams.entrySet(); - for (Iterator it2 = entrySet.iterator(); it2.hasNext(); ) { - Map.Entry entry = (Map.Entry) it2.next(); - final String paramName = (String) entry.getKey(); - final String paramValue = (String) entry.getValue(); + 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 (paramName == null - || paramName.length() == 0 - || !StructuredSyslogMessage - .checkIsPrintable(paramName)) - throw new IllegalArgumentException( - "Illegal structured data parameter name: " - + paramName); + 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); + throw new IllegalArgumentException("Null structured data parameter value for parameter name: " + paramName); sb.append(' '); sb.append(paramName); @@ -306,7 +265,7 @@ public class StructuredSyslogMessage extends AbstractSyslogMessage implements St } } - if (getMessage() != null && getMessage().length() != 0) { + if (!StringUtils.isEmpty(getMessage())) { sb.append(' '); sb.append(StructuredSyslogMessage.nilProtect(getMessage())); } @@ -342,13 +301,55 @@ public class StructuredSyslogMessage extends AbstractSyslogMessage implements St } public static String nilProtect(final String value) { - if (value == null || value.trim().length() == 0) { + 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; diff --git a/src/main/java/org/graylog2/syslog4j/server/impl/event/structured/StructuredSyslogServerEvent.java b/src/main/java/org/graylog2/syslog4j/server/impl/event/structured/StructuredSyslogServerEvent.java index c8c2b5a..e7e93de 100644 --- a/src/main/java/org/graylog2/syslog4j/server/impl/event/structured/StructuredSyslogServerEvent.java +++ b/src/main/java/org/graylog2/syslog4j/server/impl/event/structured/StructuredSyslogServerEvent.java @@ -146,7 +146,7 @@ public class StructuredSyslogServerEvent extends SyslogServerEvent { // throw new SyslogRuntimeException( // "Message received is not a valid structured message: " // + getMessage(), e); - return new StructuredSyslogMessage(null, null, getMessage()); + return new StructuredSyslogMessage(null, null, null, getMessage()); } } } diff --git a/src/test/java/org/graylog2/syslog4j/server/impl/structured/TestMatchChar.java b/src/test/java/org/graylog2/syslog4j/server/impl/structured/TestMatchChar.java new file mode 100644 index 0000000..3da8012 --- /dev/null +++ b/src/test/java/org/graylog2/syslog4j/server/impl/structured/TestMatchChar.java @@ -0,0 +1,40 @@ +/** + * + * (C) Copyright 2008-2011 syslog4j.org + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser General Public License + * (LGPL) version 2.1 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl-2.1.html + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +package org.graylog2.syslog4j.server.impl.structured; + +import org.graylog2.syslog4j.impl.message.structured.StructuredSyslogMessage; +import org.junit.Assert; +import org.junit.Test; + +public class TestMatchChar +{ + @Test + public void testMatchChar() throws Exception + { + Assert.assertEquals(2, StructuredSyslogMessage.matchChar("hello", 0, 'l')); + Assert.assertEquals(2, StructuredSyslogMessage.matchChar("hello", 2, 'l')); + Assert.assertEquals(3, StructuredSyslogMessage.matchChar("hello", 3, 'l')); + Assert.assertEquals(-1, StructuredSyslogMessage.matchChar("hello", 4, 'l')); + Assert.assertEquals(-1, StructuredSyslogMessage.matchChar("hello", 10, 'l')); + + Assert.assertEquals(2, StructuredSyslogMessage.matchChar("\\ll", 0, 'l')); + Assert.assertEquals(-1, StructuredSyslogMessage.matchChar("\\l\\l", 0, 'l')); + Assert.assertEquals(-1, StructuredSyslogMessage.matchChar("\\", 0, 'x')); + Assert.assertEquals(-1, StructuredSyslogMessage.matchChar("foo\\", 0, 'x')); + + Assert.assertEquals(-1, StructuredSyslogMessage.matchChar("this\\\"is\\ a\\ test.", 0, ' ')); + } + +} diff --git a/src/test/java/org/graylog2/syslog4j/test/message/structured/StructuredSyslogMessageTest.java b/src/test/java/org/graylog2/syslog4j/test/message/structured/StructuredSyslogMessageTest.java new file mode 100644 index 0000000..ed345b4 --- /dev/null +++ b/src/test/java/org/graylog2/syslog4j/test/message/structured/StructuredSyslogMessageTest.java @@ -0,0 +1,260 @@ +/** + * + * (C) Copyright 2008-2011 syslog4j.org + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser General Public License + * (LGPL) version 2.1 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl-2.1.html + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +package org.graylog2.syslog4j.test.message.structured; + +// +// Cleversafe open-source code header - Version 1.2 - February 15, 2008 +// +// Cleversafe Dispersed Storage(TM) is software for secure, private and +// reliable storage of the world's data using information dispersal. +// +// Copyright (C) 2005-2008 Cleversafe, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +// USA. +// +// Contact Information: Cleversafe, 224 North Desplaines Street, Suite 500 +// Chicago IL 60661 +// email licensing@cleversafe.org +// +// END-OF-HEADER +// ----------------------- +// @author: mmotwani +// +// Date: Jul 15, 2009 +// --------------------- + +import com.google.common.collect.Maps; +import junit.framework.TestCase; +import org.graylog2.syslog4j.impl.message.structured.StructuredSyslogMessage; +import org.graylog2.syslog4j.server.impl.event.structured.StructuredSyslogServerEvent; +import org.junit.Assert; + +import java.net.InetAddress; +import java.util.Map; + +public class StructuredSyslogMessageTest extends TestCase +{ + public void testFromString1() + { + final String messageStr = "msgId1 [0@0] my message!!"; + + final StructuredSyslogMessage message = StructuredSyslogMessage.fromString(messageStr); + + assertEquals("msgId1 [0@0] my message!!",message.toString()); + assertEquals(-108931075,message.hashCode()); + + assertEquals("my message!!", message.getMessage()); + assertEquals("msgId1", message.getMessageId()); + assertTrue(message.getStructuredData().size() == 0); + } + + + public void testFromString1a() + { + final String messageStr = "msgId1 [type a=\"[xx\\] xx\"] [first] my message!!"; + + final StructuredSyslogMessage message = StructuredSyslogMessage.fromString(messageStr); + + assertEquals("msgId1 [type a=\"[xx\\] xx\"] [first] my message!!",message.toString()); + + + assertEquals("[first] my message!!", message.getMessage()); + assertEquals("msgId1", message.getMessageId()); + assertEquals("[xx] xx", (message.getStructuredData().get("type")).get("a")); + } + + public void testFromString1b() + { + final String messageStr = "msgId1 [type a=\"[xx\\] xx\"] my [second] message!!"; + + final StructuredSyslogMessage message = StructuredSyslogMessage.fromString(messageStr); + + assertEquals("msgId1 [type a=\"[xx\\] xx\"] my [second] message!!",message.toString()); + + + assertEquals("my [second] message!!", message.getMessage()); + assertEquals("msgId1", message.getMessageId()); + assertEquals("[xx] xx", (message.getStructuredData().get("type")).get("a")); + } + + public void testFromString1c() + { + final String messageStr = "msgId1 [type a=\"[xx\\] xx\"][value b=\"c\"] my message!! [last]"; + + final StructuredSyslogMessage message = StructuredSyslogMessage.fromString(messageStr); + + assertEquals("my message!! [last]", message.getMessage()); + assertEquals("msgId1", message.getMessageId()); + assertEquals("[xx] xx", (message.getStructuredData().get("type")).get("a")); + assertEquals("c", (message.getStructuredData().get("value")).get("b")); + } + + public void testFromString2() + { + final String messageStr = "msgId1 [invalid SD] my message!!"; + + try { + StructuredSyslogMessage.fromString(messageStr); + fail(); + + } catch (IllegalArgumentException iae) { + // + } + } + + public void testFromString3() + { + final String messageStr = "msgId1 [data1 a=b] my message!!"; + + try { + StructuredSyslogMessage.fromString(messageStr); + fail(); + + } catch (IllegalArgumentException iae) { + // + } + } + + public void testFromString4() + { + final String messageStr = "msgId1 [data1 a=\"b] my message!!"; + + try { + StructuredSyslogMessage.fromString(messageStr); + fail(); + + } catch (IllegalArgumentException iae) { + // + } + } + + public void testFromString5() + { + final String messageStr = "msgId1 [data1 a=b\"] my message!!"; + + try { + StructuredSyslogMessage.fromString(messageStr); + fail(); + + } catch (IllegalArgumentException iae) { + // + } + + } + + public void testFromString6() + { + final String messageStr = "msgId1 [data1 a=\"b\"] my message!!"; + + final StructuredSyslogMessage message = StructuredSyslogMessage.fromString(messageStr); + + assertEquals("my message!!", message.getMessage()); + assertEquals("msgId1", message.getMessageId()); + assertTrue(message.getStructuredData().size() == 1); + assertTrue((message.getStructuredData().get("data1")).size() == 1); + assertEquals("b", (message.getStructuredData().get("data1")).get("a")); + } + + public void testFromString7() + { + final String messageStr = + "msgId1 [data1 a=\"b\"][data2 a=\"b\" x1=\"c1\" n2=\"f5\"] my message!!"; + + final StructuredSyslogMessage message = StructuredSyslogMessage.fromString(messageStr); + + assertEquals("my message!!", message.getMessage()); + assertEquals("msgId1", message.getMessageId()); + assertTrue(message.getStructuredData().size() == 2); + assertTrue((message.getStructuredData().get("data1")).size() == 1); + assertTrue((message.getStructuredData().get("data2")).size() == 3); + assertEquals("b", (message.getStructuredData().get("data1")).get("a")); + assertEquals("b", (message.getStructuredData().get("data2")).get("a")); + assertEquals("c1", (message.getStructuredData().get("data2")).get("x1")); + assertEquals("f5", (message.getStructuredData().get("data2")).get("n2")); + } + + public void testCreateMessage1() + { + final StructuredSyslogMessage message = new StructuredSyslogMessage("msgId", null, null, null); + assertEquals("msgId [0@0]", message.createMessage()); + } + + public void testCreateMessage2() + { + final StructuredSyslogMessage message = + new StructuredSyslogMessage("msgId", null, null, "my message"); + assertEquals("msgId [0@0] my message", message.createMessage()); + } + + public void testCreateMessage3() + { + final StructuredSyslogMessage message = + new StructuredSyslogMessage("msgId", null, Maps.>newHashMap(), "my message"); + assertEquals("msgId [0@0] my message", message.createMessage()); + } + + public void testCreateMessage4() + { + final Map> map = Maps.newHashMap(); + final StructuredSyslogMessage message = + new StructuredSyslogMessage("msgId", null, map, "my message"); + assertEquals("msgId [0@0] my message", message.createMessage()); + } + + public void testMessageWithNulls() throws Exception + { + final String message = "<134>1 2012-07-25T21:32:08.887+00:00 some-server.some.domain noprog qtp583592918-80437 95d42b22c48e4eadb59e61a182c102d4 [l@2 si=\"some-server-s4\" sc=\"/a/b-c/d\" ip=\"1.2.3.4\" m=\"GET\" u=\"http://1.2.3.4:8081/path/PATH:12345/path\" q=\"source=SERVICE\" rc=\"200\" t=\"12\"][co@2 auth-cookie=\"jskldjskldjasskljlaskjas\"][rs@2 some-header=\"4054630f-8d31-457c-b1ff-2f2b465d69ef\"] nomsg"; + final StructuredSyslogServerEvent ev = new StructuredSyslogServerEvent(message, InetAddress.getLocalHost()); + final StructuredSyslogMessage msg = ev.getStructuredMessage(); + Assert.assertEquals("95d42b22c48e4eadb59e61a182c102d4", msg.getMessageId()); + Assert.assertNotNull(msg.getStructuredData()); + Assert.assertNotNull(msg.getStructuredData().get("l@2")); + Assert.assertEquals("/a/b-c/d", msg.getStructuredData().get("l@2").get("sc")); + } + + public void testMessageWithEmptyStruct() throws Exception + { + final String message = "<134>1 2012-07-25T21:32:08.887+00:00 some-server.some.domain noprog qtp583592918-80437 95d42b22c48e4eadb59e61a182c102d4 [l@2][a@3 a=\"b\\\"c\"]"; + final StructuredSyslogServerEvent ev = new StructuredSyslogServerEvent(message, InetAddress.getLocalHost()); + final StructuredSyslogMessage msg = ev.getStructuredMessage(); + Assert.assertEquals("95d42b22c48e4eadb59e61a182c102d4", msg.getMessageId()); + Assert.assertNotNull(msg.getStructuredData()); + Assert.assertNotNull(msg.getStructuredData().get("l@2")); + Assert.assertNotNull(msg.getStructuredData().get("a@3")); + Assert.assertEquals("b\"c", msg.getStructuredData().get("a@3").get("a")); + } + + public void testMessageWithSpace() throws Exception + { + final String message = "<134>1 2012-07-25T21:32:08.887+00:00 some-server.some.domain noprog qtp583592918-80437 95d42b22c48e4eadb59e61a182c102d4 [rh@12345 xxx=\"hell0 7|133454|00022f444ad7fe10ef5d0d536ae879f1\"]'"; + final StructuredSyslogServerEvent ev = new StructuredSyslogServerEvent(message, InetAddress.getLocalHost()); + final StructuredSyslogMessage msg = ev.getStructuredMessage(); + Assert.assertNotNull(msg.getStructuredData().get("rh@12345")); + Assert.assertEquals("hell0 7|133454|00022f444ad7fe10ef5d0d536ae879f1", msg.getStructuredData().get("rh@12345").get("xxx")); + } +}