/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2010-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) 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 3 of the License, * or (at your option) any later version. * * OpenNMS(R) 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 OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.netmgt.syslogd; import java.util.Date; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.opennms.core.utils.LogUtils; import org.opennms.netmgt.config.SyslogdConfig; import org.opennms.netmgt.config.SyslogdConfigFactory; public class CustomSyslogParser extends SyslogParser { private static final Pattern m_messageIdPattern = Pattern.compile("^((\\S+):\\s*)"); private static final Pattern m_datePattern = Pattern.compile("^((\\d\\d\\d\\d-\\d\\d-\\d\\d)\\s+)"); private static final Pattern m_oldDatePattern = Pattern.compile("^\\s*(\\S\\S\\S\\s+\\d{1,2}\\s+\\d\\d:\\d\\d:\\d\\d)\\s+"); private Pattern m_forwardingPattern; private int m_matchingGroupHost; private int m_matchingGroupMessage; protected CustomSyslogParser(final String text) throws SyslogParserException { super(text); final SyslogdConfig config = SyslogdConfigFactory.getInstance(); final String forwardingRegexp = config.getForwardingRegexp(); if (forwardingRegexp == null || forwardingRegexp.length() == 0) { throw new SyslogParserException("no forwarding regular expression defined"); } m_forwardingPattern = Pattern.compile(forwardingRegexp, Pattern.MULTILINE); m_matchingGroupHost = config.getMatchingGroupHost(); m_matchingGroupMessage = config.getMatchingGroupMessage(); } public static SyslogParser getParser(final String text) throws SyslogParserException { return new CustomSyslogParser(text); } public SyslogMessage parse() throws SyslogParserException { final SyslogMessage syslogMessage = new SyslogMessage(); String message = getText(); int lbIdx = message.indexOf('<'); int rbIdx = message.indexOf('>'); if (lbIdx < 0 || rbIdx < 0 || lbIdx >= (rbIdx - 1)) { LogUtils.warnf(this, "Syslogd received an unparsable message!"); } int priCode = 0; String priStr = message.substring(lbIdx + 1, rbIdx); try { priCode = Integer.parseInt(priStr); } catch (final NumberFormatException ex) { LogUtils.debugf(this, "ERROR Bad priority code '%s'", priStr); } LogUtils.tracef(this, "priority code = %d", priCode); syslogMessage.setFacility(SyslogFacility.getFacilityForCode(priCode)); syslogMessage.setSeverity(SyslogSeverity.getSeverityForCode(priCode)); message = message.substring(rbIdx + 1, message.length()); final Matcher idMatcher = m_messageIdPattern.matcher(message); if (idMatcher.find()) { final String messageId = idMatcher.group(2); LogUtils.tracef(this, "found message ID '%s'", messageId); syslogMessage.setMessageID(messageId); message = message.substring(idMatcher.group(1).length() - 1); } LogUtils.tracef(this, "message = %s", message); Matcher oldDateMatcher = m_oldDatePattern.matcher(message); if (!oldDateMatcher.find()) { oldDateMatcher = null; } LogUtils.tracef(this, "stdMsg = %s", Boolean.toString(oldDateMatcher != null)); if (!this.find()) { if (traceEnabled()) { LogUtils.tracef(this, "Lenient Syslog pattern '%s' did not match '%s'", getPattern(), getText()); } return null; } String timestamp; if (oldDateMatcher == null) { final Matcher stampMatcher = m_datePattern.matcher(message); if (stampMatcher.find()) { timestamp = stampMatcher.group(2); LogUtils.tracef(this, "found timestamp '%s'", timestamp); // message = message.substring(stampMatcher.group(1).length()); } else { try { timestamp = SyslogTimeStamp.getInstance().format(new Date()); } catch (final IllegalArgumentException ex) { LogUtils.debugf(this, "ERROR INTERNAL DATE ERROR!"); timestamp = ""; } } } else { timestamp = oldDateMatcher.group(1); message = oldDateMatcher.replaceFirst(""); } LogUtils.tracef(this, "timestamp = %s", timestamp); syslogMessage.setDate(parseDate(timestamp)); // These 2 debugs will aid in analyzing the regexes as syslog seems // to differ a lot depending on implementation or message structure. if (LogUtils.isTraceEnabled(this)) { LogUtils.tracef(this, "message = %s", message); LogUtils.tracef(this, "pattern = %s", m_forwardingPattern); LogUtils.tracef(this, "host group = %d", m_matchingGroupHost); LogUtils.tracef(this, "message group = %d", m_matchingGroupMessage); } // We will also here find out if, the host needs to // be replaced, the message matched to a UEI, and // last if we need to actually hide the message. // this being potentially helpful in avoiding showing // operator a password or other data that should be // confidential. final Pattern pattern = m_forwardingPattern; final Matcher m = pattern.matcher(message); /* * We matched on a regexp for host/message pair. * This can be a forwarded message as in BSD Style * or syslog-ng. */ if (m.matches()) { final String matchedMessage = m.group(m_matchingGroupMessage); syslogMessage.setMatchedMessage(matchedMessage); if (LogUtils.isTraceEnabled(this)) { LogUtils.tracef(this, "Syslog message '%s' matched regexp '%s'", message, m_forwardingPattern); LogUtils.tracef(this, "Found host '%s'", m.group(m_matchingGroupHost)); LogUtils.tracef(this, "Found message '%s'", matchedMessage); } syslogMessage.setHostName(m.group(m_matchingGroupHost)); message = matchedMessage; } else { LogUtils.debugf(this, "Regexp not matched: %s", message); return null; } lbIdx = message.indexOf('['); rbIdx = message.indexOf(']'); final int colonIdx = message.indexOf(':'); final int spaceIdx = message.indexOf(' '); int processId = 0; String processName = ""; String processIdStr = ""; if (lbIdx < (rbIdx - 1) && colonIdx == (rbIdx + 1) && spaceIdx == (colonIdx + 1)) { processName = message.substring(0, lbIdx); processIdStr = message.substring(lbIdx + 1, rbIdx); message = message.substring(colonIdx + 2); try { processId = Integer.parseInt(processIdStr); } catch (final NumberFormatException ex) { LogUtils.debugf(this, "Bad process id '%s'", processIdStr); processId = 0; } } else if (lbIdx < 0 && rbIdx < 0 && colonIdx > 0 && spaceIdx == (colonIdx + 1)) { processName = message.substring(0, colonIdx); message = message.substring(colonIdx + 2); } syslogMessage.setProcessId(processId); syslogMessage.setProcessName(processName); syslogMessage.setMessage(message.trim()); return syslogMessage; } }