HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Log file processor - Programming Contest

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
filelogprocessorprogrammingcontest

Problem

Problem Description


A profiler is a tool which provides information about run-time
performance of an application. Lets say. you are given output file
format of a profiler called Jensor. Jensor captures response times of
methods executed by capturing method entry and exit events. The entry
and exit events are written to a log file. The log file is then
processed to form a Call Trace. A Call Trace is a who called whom and
when relationship. For simplicity, let us assume that the application
which is profiled using Jensor is single threaded.


Your task is to create a Call Trace given a Jensor log file.

Sample

Pseudo Code

main()
{
  call A();
  call B();
  call C();
  loop(0 to 3, iterate by 1){
      call D();
  }
  sleep(20);
}

A(){
  call B();
  sleep(10);
}

B(){
  sleep(20);
}

C(){
  call A();
}

D(){
  call B();
}


JensorProfile.txt

Enter,main(),1345482572920,0,2 MB
Enter,A(),1345482572920,0,2 MB
Enter,B(),1345482572920,0,2 MB
Exit,B(),1345482572951,0,2 MB
Exit,A(),1345482572967,0,2 MB
Enter,B(),1345482572967,0,2 MB
Exit,B(),1345482572998,0,2 MB
Enter,C(),1345482572998,0,2 MB
Enter,A(),1345482572998,0,2 MB
Enter,B(),1345482572998,0,2 MB
Exit,B(),1345482573029,0,2 MB
Exit,A(),1345482573045,0,2 MB
Exit,C(),1345482573045,0,2 MB
Enter,D(),1345482573045,0,2 MB
Enter,B(),1345482573045,0,2 MB
Exit,B(),1345482573076,0,2 MB
Exit,D(),1345482573076,0,2 MB
Enter,D(),1345482573076,0,2 MB
Enter,B(),1345482573076,0,2 MB
Exit,B(),1345482573096,0,2 MB
Exit,D(),1345482573096,0,2 MB
Enter,D(),1345482573096,0,2 MB
Enter,B(),1345482573096,0,2 MB
Exit,B(),1345482573116,0,2 MB
Exit,D(),1345482573116,0,2 MB
Enter,D(),1345482573116,0,2 MB
Enter,B(),1345482573116,0,2 MB
Exit,B(),1345482573136,0,2 MB
Exit,D(),1345482573136,0,2 MB     
Exit,main(),1345482573156,1,2 MB




where,


Column 1 is name of the event. Possible events {Enter, Exit}


Column 2 is name of the method which is entered into or exited out of


Column 3 is time in

Solution

Unit testing

It's good to convert that main method to make your implementation testable:

public static String perform(Scanner sc) {
    try {
        String logFileName = sc.nextLine();
        int functionNumber = sc.nextInt();

        return new JensorLogProcessor().getDetailsOfFunctionFromFile(logFileName, functionNumber);
    } catch (NoSuchElementException | InvalidInputException e){
        return "Invalid Input";
    }
}

public static void main(String[] args) {
    System.out.println(perform(new Scanner(System.in)));
}


Now you can add unit tests:

public class JensorLogProcessorTest {
    @Test
    public void testSample1() {
        assertEquals("D()\n20\n4", JensorLogProcessor.process(new Scanner("/tmp/JensorProfile.txt\n10")));
    }

    @Test
    public void testSample2() {
        assertEquals("C()\n47\n2", JensorLogProcessor.process(new Scanner("/tmp/JensorProfile.txt\n5")));
    }

    @Test
    public void testInvalidInput() throws IOException {
        assertEquals("Invalid Input", JensorLogProcessor.process(new Scanner("/tmp/JensorProfile.txt\na")));
    }
}


Input validation

On one hand it's "nice" that you validate input. But if it's not part of the specification, I think it's safe to assume that the program will receive correct inputs.

Does the contest environment expect the text "Invalid Input"? If yes, then it you could move this string to a constant, especially because you repeated it twice in the code.

If the problem description doesn't specify error handling, then I think you can omit it, and let all the exceptions just bubble up all the way to main.

Similarly, in here:

if(null != functionDesc[0]) switch (enterOrExit) {


The null check is unnecessary. And if it was, then since you already assigned functionDesc[0] to enterOrExit, it would have been better this way:

if(null != enterOrExit) switch (enterOrExit) {


Naming

numberOfFunctionCalled is not a great name for a mapping of function names to invocation counts. Perhaps functionInvocationCounts would be better.

JensorObject is not a great name for function invocation details. Perhaps FunctionInvocationInfo would be better.

Minor things

Instead of this:

String line = reader.readLine();
while (line != null) {
    parseFunctionAndProcess(line);
    line = reader.readLine();
}


It's better to eliminate the duplicated .readLine call:

String line;
while ((line = reader.readLine()) != null) {
    parseFunctionAndProcess(line);
}


The empty constructor of JensorLogProcessor is pointless, you can delete it.

I don't really understand why you suppress this warning:

@SuppressWarnings("FieldMayBeFinal")
private static Deque stack = new ArrayDeque<>();
private static List listOfProcesses = new ArrayList<>();
private static Map numberOfFunctionCalled = new HashMap<>();


Why not just make those static fields final?

You forgot to close the BufferedReader in parseLogFile.

Code Snippets

public static String perform(Scanner sc) {
    try {
        String logFileName = sc.nextLine();
        int functionNumber = sc.nextInt();

        return new JensorLogProcessor().getDetailsOfFunctionFromFile(logFileName, functionNumber);
    } catch (NoSuchElementException | InvalidInputException e){
        return "Invalid Input";
    }
}

public static void main(String[] args) {
    System.out.println(perform(new Scanner(System.in)));
}
public class JensorLogProcessorTest {
    @Test
    public void testSample1() {
        assertEquals("D()\n20\n4", JensorLogProcessor.process(new Scanner("/tmp/JensorProfile.txt\n10")));
    }

    @Test
    public void testSample2() {
        assertEquals("C()\n47\n2", JensorLogProcessor.process(new Scanner("/tmp/JensorProfile.txt\n5")));
    }

    @Test
    public void testInvalidInput() throws IOException {
        assertEquals("Invalid Input", JensorLogProcessor.process(new Scanner("/tmp/JensorProfile.txt\na")));
    }
}
if(null != functionDesc[0]) switch (enterOrExit) {
if(null != enterOrExit) switch (enterOrExit) {
String line = reader.readLine();
while (line != null) {
    parseFunctionAndProcess(line);
    line = reader.readLine();
}

Context

StackExchange Code Review Q#58923, answer score: 2

Revisions (0)

No revisions yet.