/*
*
* Copyright (c) void.fm
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* Neither the name void.fm nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package etm.contrib.rrd.core;
import etm.core.util.Log;
import etm.core.util.LogAdapter;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Parses arbitrary files written by {@link etm.contrib.aggregation.log.AbstractLogAggregator}. Assumes
* {@link etm.contrib.aggregation.log.DefaultOutputFormatter} as default format.
*
* @author void.fm
* @version $Revision$
* @since 1.2.0
*/
public class OfflineLogParser {
private static final LogAdapter LOG = Log.getLog(OfflineLogParser.class);
private static final String DEFAULT_SCAN_PATTERN = "^(.*)measurementPoint=<([\\w\\s\\d\\.-_():]*)>, parent=<([\\w\\s\\d\\.-_():]*)>, transactionTime=<(\\d*[,.]\\d*)>, recordingTime=<(\\d*)>";
private String pattern = DEFAULT_SCAN_PATTERN;
private List destinations;
private DecimalFormat numberFormat;
public OfflineLogParser() {
destinations = new ArrayList();
// todo?? pattern
numberFormat = new DecimalFormat();
numberFormat.setMinimumFractionDigits(3);
numberFormat.setMaximumFractionDigits(3);
numberFormat.setGroupingUsed(false);
}
public void setPattern(String aPattern) {
pattern = aPattern;
}
public void register(RrdDestination aDestination) {
destinations.add(aDestination);
}
public void parse(File aFile) throws IOException {
LOG.info("Parsing " + aFile.getAbsolutePath());
boolean checkDecimalDigit = true;
int totalLines = 0;
int processedLines = 0;
Pattern regex = Pattern.compile(pattern);
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(aFile), "UTF-8"));
try {
for (int i = 0; i < destinations.size(); i++) {
RrdDestination destination = (RrdDestination) destinations.get(i);
destination.start();
}
String line;
while ((line = in.readLine()) != null) {
totalLines++;
try {
Matcher matcher = regex.matcher(line);
if (matcher.matches()) {
// validate whether we use the matching
if (checkDecimalDigit) {
DecimalFormatSymbols symbols = numberFormat.getDecimalFormatSymbols();
if (matcher.group(4).indexOf(symbols.getDecimalSeparator()) < 0) {
LOG.warn("Possibly precision loss detected. Expected decimal separator '" +
symbols.getDecimalSeparator() +
"', but found " +
matcher.group(4) +
". Use -Duser.language and -Duser.region to adjust your locale to the logfile locale.");
}
checkDecimalDigit = false;
}
processedLines++;
OfflineExecution result = new OfflineExecution(
matcher.group(2),
matcher.group(3),
Long.parseLong(matcher.group(5)),
numberFormat.parse(matcher.group(4)).doubleValue()
);
for (int i = 0; i < destinations.size(); i++) {
RrdDestination destination = (RrdDestination) destinations.get(i);
if (destination.matches(result)) {
destination.write(result);
}
}
}
} catch (ParseException e) {
LOG.warn("Error reading line " + line, e);
}
}
for (int i = 0; i < destinations.size(); i++) {
RrdDestination destination = (RrdDestination) destinations.get(i);
destination.stop();
}
} finally {
in.close();
}
LOG.info("Finished parsing " + aFile.getAbsolutePath() +
". Processed " + processedLines + " out of " + totalLines + " lines.");
}
}