Find hidden System.out.println Statements

Find hidden System.out.println Statements

Sometimes System.out.println Statements are used instead of logging information with common logging frameworks. These Statements are sometimes complicated if the application grows and a greater amount of custom libraries and dependencies are used. Locating the System.out.println is difficult, because in most cases no class, library or package information is printed out.

In an application server environment this may looks like this:

2017-02-09 11:28:53,971 INFO  [stdout] (default task-39) constraint
2017-02-09 11:28:54,123 INFO  [stdout] (default task-38) constraint
2017-02-09 11:28:54,952 INFO  [stdout] (default task-47) constraint
2017-02-09 11:28:55,539 INFO  [stdout] (default task-46) constraint

In this case one single statement was executed by multiple threads and was located in a library jar dependency.

To locate a System.out.println statement a custom PrintStream implementation replaces the default stout by setting System.setOut:

public class SoutPrintStream extends PrintStream {


    public SoutPrintStream(OutputStream out) {
        super(out);
    }

    @Override
    public void println(String x) {
        throw new RuntimeException("found System.out.println");
    }
}

An instance is passed to System.setOut

import java.io.ByteArrayOutputStream;

public class SystemOutPrintlnLocator2 {

    public static void main(String[] args) {

        System.setOut(new SoutPrintStream(new ByteArrayOutputStream()));

        System.out.println("locate me");
    }
}

If a System.out.println passes it’s content to the custom PrintStream implementation a RuntimeException is raised, and the Statement is located:

Exception in thread "main" java.lang.RuntimeException: found System.out.println
	at com.financial.sout.SoutPrintStream.println(SoutPrintStream.java:18)
	at com.financial.sout.SystemOutPrintlnLocator.main(SystemOutPrintlnLocator.java:19)

Using durian’s https://github.com/diffplug/durian StackDumper implementation is an alternative of using a custom  PrintStream implementation:

import com.diffplug.common.base.StackDumper;

public class SystemOutPrintlnLocator {

    public static void main(String[] args) {

        StackDumper.dumpWhenSysOutContains("locate me");

        System.out.println("locate me");
    }
}

The result is similar:

+----------\
| Triggered by locate me
| at com.diffplug.common.base.StringPrinter.lambda$stringsToLines$40(StringPrinter.java:256)
| at com.diffplug.common.base.StringPrinter$1.flushOutput(StringPrinter.java:138)
| at com.diffplug.common.base.StringPrinter$1.write(StringPrinter.java:113)
| at java.io.PrintStream.write(PrintStream.java:480)
| at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
| at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
| at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
| at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
| at java.io.PrintStream.newLine(PrintStream.java:546)
| at java.io.PrintStream.println(PrintStream.java:807)
| at com.financial.sout.SystemOutPrintlnLocator.main(SystemOutPrintlnLocator.java:11)
+----------/

In both cases the caller class of the System.out.println statement is found. To avoid this problem use a common logger implementation, using System.out.println for more than small “home-written” code is bad practice.