// // Copyright 2010 Cinch Logic Pty Ltd. // // http://www.chililog.com // // Licensed 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.chililog.server.engine.parsers; import java.text.ParseException; import java.util.ArrayList; import java.util.Hashtable; import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang.StringUtils; import org.chililog.server.common.ChiliLogException; import org.chililog.server.common.Log4JLogger; import org.chililog.server.common.StringsProperties; import org.chililog.server.data.RepositoryEntryBO; import org.chililog.server.data.RepositoryFieldConfigBO; import org.chililog.server.data.RepositoryConfigBO; import org.chililog.server.data.RepositoryParserConfigBO; import org.chililog.server.data.RepositoryEntryBO.Severity; import org.chililog.server.engine.Strings; import com.mongodb.BasicDBObject; /** * <p> * Parser to extract field values from delimited log entries. For example, * </p> * <code> * field1|field2|field3 * </code> * <p> * The fields are delimited by the pipe character (|). * </p> * * @author vibul * */ public class DelimitedEntryParser extends EntryParser { private static Log4JLogger _logger = Log4JLogger.getLogger(DelimitedEntryParser.class); private String _delimiter; private ArrayList<DelimitedFieldInfo> _fields = new ArrayList<DelimitedFieldInfo>(); /** * Delimiter repository property denotes the field delimiter character */ public static final String DELIMITER_PROPERTY_NAME = "delimiter"; /** * Position field property denotes the position of this field. Position 1 is the 1st field. */ public static final String POSITION_FIELD_PROPERTY_NAME = "position"; /** * <p> * Basic constructor * </p> * * @param repoInfo * Repository meta data * @param repoParserInfo * Parser information that we need * @throws ChiliLogException */ public DelimitedEntryParser(RepositoryConfigBO repoInfo, RepositoryParserConfigBO repoParserInfo) throws ChiliLogException { super(repoInfo, repoParserInfo); try { Hashtable<String, String> properties = repoParserInfo.getProperties(); _delimiter = properties.get(DELIMITER_PROPERTY_NAME); if (StringUtils.isBlank(_delimiter)) { throw new ChiliLogException(Strings.PARSER_DELIMITER_NOT_SET_ERROR, repoParserInfo.getName(), repoInfo.getName()); } // Parse our field value so that we don't have to keep on doing it for (RepositoryFieldConfigBO f : repoParserInfo.getFields()) { String s = f.getProperties().get(POSITION_FIELD_PROPERTY_NAME); Integer i = Integer.parseInt(s) - 1; _fields.add(new DelimitedFieldInfo(i, f)); } } catch (Exception ex) { if (ex instanceof ChiliLogException) { throw (ChiliLogException) ex; } else { throw new ChiliLogException(ex, Strings.PARSER_INITIALIZATION_ERROR, repoParserInfo.getName(), repoInfo.getName(), ex.getMessage()); } } return; } /** * Parse a string for fields. All exceptions are caught and logged. If <code>null</code> is returned, this indicates * that the entry should be skipped. * * @param timestamp * Time when this log entry was created at the source on the host. * @param source * Name of the input device or application that created this text entry * @param host * IP address of the input device or application that created this text entry * @param severity * Classifies the importance of the entry. Can be the severity code (0-7) or text. * @param preparsedFields * Pre-parsed fields in JSON format. * @param message * The text for this entry to parse * @return <code>RepositoryEntryBO</code> ready for saving to mongoDB. If the entry cannot be parsed, then null is * returned */ @Override public RepositoryEntryBO parse(String timestamp, String source, String host, String severity, String preparsedFields, String message) { try { this.setLastParseError(null); checkParseArguments(timestamp, source, host, severity, message); BasicDBObject parsedFields = this.readPreparsedFields(preparsedFields); String[] ss = StringUtils.split(message, _delimiter); for (DelimitedFieldInfo delimitedField : _fields) { String fieldName = delimitedField.getRepoFieldInfo().getDbObjectName(); String fieldStringValue = null; Object fieldValue = null; try { fieldStringValue = ss[delimitedField.getArrayIndex()]; fieldValue = delimitedField.getParser().parse(fieldStringValue); parsedFields.put(fieldName, fieldValue); } catch (Exception ex) { switch (this.getRepoParserInfo().getParseFieldErrorHandling()) { case SkipField: String msg = StringsProperties.getInstance().getString( Strings.PARSER_FIELD_ERROR_SKIP_FIELD); _logger.error(ex, msg, fieldStringValue, fieldName, this.getRepoName(), ex.getMessage(), message); break; case SkipEntry: throw new ChiliLogException(ex, Strings.PARSER_FIELD_ERROR_SKIP_ENTRY, fieldStringValue, fieldName, this.getRepoName(), ex.getMessage(), message); case SkipFieldIgnoreError: break;// Do nothing default: throw new NotImplementedException("ParseFieldErrorHandling type " + this.getRepoParserInfo().getParseFieldErrorHandling().toString()); } } } Severity sev = Severity.parse(severity); ArrayList<String> keywords = parseKeywords(source, host, sev, message); return new RepositoryEntryBO(parseTimestamp(timestamp), source, host, sev, keywords, message, parsedFields); } catch (Exception ex) { this.setLastParseError(ex); _logger.error(ex, "Error parsing text entry: " + message); return null; } } /** * Encapsulates a delimited field */ private static class DelimitedFieldInfo { private int _arrayIndex; private RepositoryFieldConfigBO _repoFieldInfo; private FieldParser _parser; public DelimitedFieldInfo(int arrayIndex, RepositoryFieldConfigBO repoFieldInfo) throws ParseException { _arrayIndex = arrayIndex; _repoFieldInfo = repoFieldInfo; _parser = FieldParserFactory.getParser(repoFieldInfo); } /** * Returns the index position of this field relative to other field. E.g. 0 is the 1st field. */ public int getArrayIndex() { return _arrayIndex; } /** * Returns the field meta data */ public RepositoryFieldConfigBO getRepoFieldInfo() { return _repoFieldInfo; } /** * Returns the field value parser */ public FieldParser getParser() { return _parser; } } }