/* * Copyright 2013 Eediom Inc. * * 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.araqne.logdb.query.command; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.araqne.log.api.FieldDefinition; import org.araqne.log.api.LogParser; import org.araqne.log.api.LogParserInput; import org.araqne.log.api.LogParserOutput; import org.araqne.logdb.FieldOrdering; import org.araqne.logdb.QueryCommand; import org.araqne.logdb.Row; import org.araqne.logdb.RowBatch; import org.araqne.logdb.ThreadSafe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @since 1.6.6 * @author xeraph * */ public class Parse extends QueryCommand implements ThreadSafe, FieldOrdering { private final Logger logger = LoggerFactory.getLogger(Parse.class); private final int parserVersion; private final String parserName; private final LogParser parser; private final boolean overlay; public Parse(String parserName, LogParser parser, boolean overlay) { this.parserName = parserName; this.parser = parser; this.parserVersion = parser.getVersion(); this.overlay = overlay; } @Override public String getName() { return "parse"; } @Override public List<String> getFieldOrder() { if (parser instanceof FieldOrdering) return ((FieldOrdering) parser).getFieldOrder(); List<FieldDefinition> fieldDefinitions = parser.getFieldDefinitions(); if (fieldDefinitions != null) { LinkedList<String> l = new LinkedList<String>(); for (FieldDefinition def : fieldDefinitions) l.add(def.getName()); reorderSystemFields(l); return l; } return null; } private void reorderSystemFields(LinkedList<String> l) { // remove potentially duplicated field name first l.remove("_time"); l.remove("_table"); l.remove("_id"); l.addFirst("_id"); l.addFirst("_time"); l.addFirst("_table"); } @Override public void onPush(RowBatch rowBatch) { // TODO: boost v2 performance if (parserVersion == 2) { if (rowBatch.selectedInUse) { for (int i = 0; i < rowBatch.size; i++) { Row row = rowBatch.rows[rowBatch.selected[i]]; onPush(row); } } else { for (int i = 0; i < rowBatch.size; i++) { Row row = rowBatch.rows[i]; onPush(row); } } return; } int n = 0; if (rowBatch.selectedInUse) { for (int i = 0; i < rowBatch.size; i++) { int p = rowBatch.selected[i]; Row row = rowBatch.rows[p]; try { Row parsed = parseV1(row); if (parsed != null) { rowBatch.selected[n] = p; rowBatch.rows[p] = parsed; n++; } } catch (Throwable t) { if (logger.isDebugEnabled()) logger.debug("araqne logdb: cannot parse " + row.map() + ", query - " + toString(), t); // set as original rowBatch.selected[n] = p; rowBatch.rows[p] = row; n++; } } } else { rowBatch.selected = new int[rowBatch.size]; for (int i = 0; i < rowBatch.size; i++) { Row row = rowBatch.rows[i]; try { Row parsed = parseV1(row); if (parsed != null) { rowBatch.selected[n] = i; rowBatch.rows[i] = parsed; n++; } } catch (Throwable t) { if (logger.isDebugEnabled()) logger.debug("araqne logdb: cannot parse " + row.map() + ", query - " + toString(), t); // set as original rowBatch.selected[n] = i; rowBatch.rows[i] = row; n++; } } } if (!rowBatch.selectedInUse && rowBatch.size != n) rowBatch.selectedInUse = true; rowBatch.size = n; pushPipe(rowBatch); } @Override public void onPush(Row row) { try { LogParserInput input = new LogParserInput(); if (parserVersion == 2) { Object table = row.get("_table"); Object time = row.get("_time"); Object id = row.get("_id"); if (time != null && time instanceof Date) input.setDate((Date) time); else input.setDate(null); if (table != null && table instanceof String) input.setSource((String) table); else input.setSource(null); input.setData(row.map()); LogParserOutput output = parser.parse(input); if (output != null) { for (Map<String, Object> out : output.getRows()) { if (id != null && !out.containsKey("_id")) out.put("_id", id); if (time != null && !out.containsKey("_time")) out.put("_time", row.get("_time")); if (table != null && !out.containsKey("_table")) out.put("_table", row.get("_table")); if (overlay) { Map<String, Object> source = new HashMap<String, Object>(row.map()); source.putAll(out); pushPipe(new Row(source)); } else { pushPipe(new Row(out)); } } } } else { Row parsed = parseV1(row); if (parsed != null) pushPipe(parsed); } } catch (Throwable t) { if (logger.isDebugEnabled()) logger.debug("araqne logdb: cannot parse " + row.map() + ", query - " + toString(), t); } } private Row parseV1(Row row) { Map<String, Object> parsed = parser.parse(row.map()); if (parsed == null) return null; Object id = row.get("_id"); Object time = row.get("_time"); Object table = row.get("_table"); if (id != null && !parsed.containsKey("_id")) parsed.put("_id", id); if (time != null && !parsed.containsKey("_time")) parsed.put("_time", time); if (table != null && !parsed.containsKey("_table")) parsed.put("_table", table); if (overlay) { Map<String, Object> source = new HashMap<String, Object>(row.map()); source.putAll(parsed); return new Row(source); } else return new Row(parsed); } @Override public String toString() { if (parser instanceof ParseWithAnchor) { return ((ParseWithAnchor) parser).toQueryCommandString(); } else { return "parse " + parserName; } } }