/* * Copyright 2011 Future Systems * * 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.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.nio.charset.Charset; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; import java.util.regex.Pattern; import org.araqne.log.api.DummyLogger; import org.araqne.log.api.Log; import org.araqne.log.api.LogParser; import org.araqne.log.api.LogPipe; import org.araqne.log.api.Logger; import org.araqne.log.api.LoggerStatus; import org.araqne.log.api.MultilineLogExtractor; import org.araqne.logdb.DriverQueryCommand; import org.araqne.logdb.QueryResultClosedException; import org.araqne.logdb.QueryStopReason; import org.araqne.logdb.Row; public class TextFile extends DriverQueryCommand { private List<String> filePaths; private String filePath; private LogParser parser; private long offset; private long limit; private String beginRegex; private String endRegex; private String dateFormat; private String datePattern; private String charset; private long currentOffset; private long pushCount; private DummyLogger dummyLogger = new DummyLogger(); public TextFile(List<String> filePaths, String filePath, LogParser parser, long offset, long limit, String beginRegex, String endRegex, String dateFormat, String datePattern, String charset) { this.filePaths = filePaths; this.filePath = filePath; this.parser = parser; this.offset = offset; this.limit = limit; this.beginRegex = beginRegex; this.endRegex = endRegex; this.dateFormat = dateFormat; this.datePattern = datePattern; this.charset = charset; this.currentOffset = 0; this.pushCount = 0; } @Override public void onClose(QueryStopReason reason) { dummyLogger.setStatus(LoggerStatus.Stopped); } @Override public String getName() { return "textfile"; } private static class LimitReachedException extends RuntimeException { private static final long serialVersionUID = 1L; } private class RowPipe implements LogPipe { private String filePath; public RowPipe(String filePath) { this.filePath = filePath; } @Override public void onLog(Logger logger, Log log) { Row row = buildRow(log); pushRow(row); } private void pushRow(Row row) { if (limit > 0 && pushCount >= limit) { throw new LimitReachedException(); } Map<String, Object> parsed = null; if (parser != null) { parsed = parser.parse(row.map()); if (parsed == null) return; } if (currentOffset >= offset) { Row r = new Row(parsed != null ? parsed : row.map()); r.put("_file", filePath); pushPipe(r); pushCount++; } currentOffset++; } private void pushRows(List<Row> rows) { for (Row row : rows) { if (limit > 0 && pushCount >= limit) { throw new LimitReachedException(); } Map<String, Object> parsed = null; if (parser != null) { parsed = parser.parse(row.map()); if (parsed == null) return; } if (currentOffset >= offset) { Row r = new Row(parsed != null ? parsed : row.map()); r.put("_file", filePath); pushPipe(r); pushCount++; } currentOffset++; } } private Row buildRow(Log log) { Row row = new Row(); row.put("_time", log.getDate()); String line = (String) log.getParams().get("line"); row.put("line", line); return row; } @Override public void onLogBatch(Logger logger, Log[] logs) { if (logs.length <= 0) return; List<Row> rows = new ArrayList<Row>(logs.length); for (Log log : logs) { if (log == null) continue; rows.add(buildRow(log)); } pushRows(rows); } } @Override public void run() { status = Status.Running; for (String filePath : filePaths) { FileInputStream is = null; BufferedReader br = null; try { File f = new File(filePath); RowPipe pipe = new RowPipe(f.getName()); is = new FileInputStream(f); MultilineLogExtractor extractor = new MultilineLogExtractor(dummyLogger, pipe); if (beginRegex != null) extractor.setBeginMatcher(Pattern.compile(beginRegex).matcher("")); if (endRegex != null) extractor.setEndMatcher(Pattern.compile(endRegex).matcher("")); if (datePattern != null) extractor.setDateMatcher(Pattern.compile(datePattern).matcher("")); if (dateFormat != null) extractor.setDateFormat(new SimpleDateFormat(dateFormat)); extractor.setCharset(Charset.forName(charset).name()); extractor.setEofFlush(true); extractor.extract(is, new AtomicLong()); } catch (LimitReachedException e) { // ignore } catch (QueryResultClosedException e) { // ignore } catch (Throwable t) { throw new IllegalStateException(t); } finally { IoHelper.close(br); IoHelper.close(is); } } } @Override public String toString() { String offsetOpt = ""; if (offset > 0) offsetOpt = " offset=" + offset; String limitOpt = ""; if (limit > 0) limitOpt = " limit=" + limit; String brexOpt = ""; if (beginRegex != null) brexOpt = " brex=" + quote(brexOpt); String erexOpt = ""; if (endRegex != null) erexOpt = " erex=" + quote(erexOpt); String dfOpt = ""; if (dateFormat != null) dfOpt = " df=" + quote(dateFormat); String dpOpt = ""; if (datePattern != null) dpOpt = " dp=" + quote(datePattern); String csOpt = ""; if (charset != null) csOpt = " cs=" + charset; return "textfile" + offsetOpt + limitOpt + brexOpt + erexOpt + dfOpt + dpOpt + csOpt + " " + filePath; } private String quote(String s) { return "\"" + s.replaceAll("\"", "\\\"") + "\""; } }