Reputation: 702
I don't normally do Java in my daily work, although I wish I did since there is a class for everything (sometimes too many). Yesterday I spent the bulk of my day writing the program below. Tiny rant: java.util.scanner is less than intuitive, IMO. What I want to do with it is to scan a log file for two certain patterns and do some date arithmetic on it and print the results. This program works if I take my log file and delete non-matching lines then run it. I can do this with vi, sed, whatever, but I'm more interested in taking this utility and making it more usable for someone who isn't as comfortable with shell scripting or using vi. I'll be hammering on this a little more today but I wonder if there is some expertise here that can make me move forward more quickly.
import java.util.*;
import java.util.concurrent.*;
import java.text.SimpleDateFormat;
import java.util.regex.Pattern;
import java.util.regex.MatchResult;
import java.io.*;
import java.time.*;
import java.time.format.*;
public class TimeDiff {
private static SimpleDateFormat m_formatter = new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss");
private static Pattern m_startRunPattern = Pattern.compile("start of run=([^,]+)");
private static Pattern m_currentTimePattern = Pattern.compile("current time=(.+)");
private String m_fileArg;
private File m_file;
private Scanner m_scanner;
public TimeDiff(String[] args)
{
if (args.length == 0) {
System.err.println("nope.");
System.exit(1);
}
m_fileArg = args[0];
m_file = new File(m_fileArg);
}
public String findPattern(Scanner fileScan, Pattern pattern)
{
String ret_val = null;
try {
ret_val = fileScan.findInLine(pattern);
MatchResult result = fileScan.match();
if (result.groupCount() > 0) {
ret_val = result.group(1);
}
}
catch (java.util.InputMismatchException e) {
System.out.println("failed at second");
}
catch (java.lang.IllegalStateException e) {
System.out.println("failed at second match " + e);
}
return ret_val;
}
public void run(String[] args) throws Exception
{
try (Scanner fileScan = new Scanner(m_file)) {
while (fileScan.hasNext()) {
String beginTimeStr = findPattern(fileScan, m_startRunPattern);
String endTimeStr = findPattern(fileScan, m_currentTimePattern);
if (beginTimeStr == null && endTimeStr == null) {
if (fileScan.hasNext()) {
fileScan.next();
}
}
else {
Date startDate = m_formatter.parse(beginTimeStr);
Date endDate = m_formatter.parse(endTimeStr);
long duration = endDate.getTime() - startDate.getTime();
long diffInSeconds = TimeUnit.MILLISECONDS.toSeconds(duration);
long diffInMinutes = TimeUnit.MILLISECONDS.toMinutes(duration);
long remainderSeconds = 0;
if (diffInMinutes > 0) {
remainderSeconds = diffInSeconds % diffInMinutes;
}
else {
remainderSeconds = diffInSeconds;
}
System.out.println("elapsed seconds: " + diffInSeconds + ", (" + diffInMinutes + " minutes, " + remainderSeconds + " seconds).");
if (fileScan.hasNext()) {
fileScan.next();
}
}
}
}
catch (IOException exception) {
System.out.println(exception);
}
}
public static void main(java.lang.String args[])
{
try {
TimeDiff app = new TimeDiff(args);
app.run(args);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
The massaged log file entries look like:
DealWithResponse.cpp, DealWithResponse(XMLSocketApp &, DOMDocument *), 247 2020-07-29 17:54:13 start of run=2020-07-29-17.53.31.216800, current time=2020-07-29-17.54.13.530384
DealWithResponse.cpp, DealWithResponse(XMLSocketApp &, DOMDocument *), 247 2020-07-29 17:54:13 start of run=2020-07-29-17.53.29.903984, current time=2020-07-29-17.54.13.805200
DealWithResponse.cpp, DealWithResponse(XMLSocketApp &, DOMDocument *), 247 2020-07-29 17:54:13 start of run=2020-07-29-17.53.14.356440, current time=2020-07-29-17.54.13.907528
DealWithResponse.cpp, DealWithResponse(XMLSocketApp &, DOMDocument *), 247 2020-07-29 23:16:01 start of run=2020-07-29-23.15.27.722784, current time=2020-07-29-23.16.01.016640
DealWithResponse.cpp, DealWithResponse(XMLSocketApp &, DOMDocument *), 247 2020-07-29 23:16:04 start of run=2020-07-29-23.15.39.955272, current time=2020-07-29-23.16.04.418160
DealWithResponse.cpp, DealWithResponse(XMLSocketApp &, DOMDocument *), 247 2020-07-29 23:16:05 start of run=2020-07-29-23.15.52.154920, current time=2020-07-29-23.16.05.480384
Of course, what the rest of the log file looks like contains business logic stuff (SQL, etc).
Upvotes: 0
Views: 119
Reputation: 103254
From the docs of Scanner
's findInLine
:
Attempts to find the next occurrence of the specified pattern ignoring delimiters. If the pattern is found before the next line separator, the scanner advances past the input that matched and returns the string that matched the pattern. If no such pattern is detected in the input up to the next line separator, then null is returned and the scanner's position is unchanged. This method may block waiting for input that matches the pattern.
What you're observing is findInLine not finding anything matching the pattern specified before hitting a newline, and thus returning null
and not changing the position whatsoever.
Perhaps findWithinHorizon(pattern, 0)
is more to your liking? This will keep looking, forever (until end of input) if need be, until it finds a match on your regexp.
It then returns the match. If you need the entire line, just expand on your regexp: "^.*current time = (.*)$"
would always match an entire line.
A second tip: your exception handling is atrocious. if you catch an exception, handle it. 'print some text and carry right on as if nothing is wrong' is not handling it. Trivial solution: add throws Exception
onto your main method (which is almost always a good idea in any case). Then just.. get rid of every try{
and catch{}
block in your code. Makes it way shorter and easier to read, and better to boot!
Upvotes: 1