Removing access to System.out in java

2019-06-22 01:33发布

I maintain an application which acts as a container for multiple individual programs. These programs have their own dedicated logging facility, i.e. everything they log does to a special log file.

Nevertheless, application developers seem to love to throw System.out.println and e.printStackTrace calls all over, making it impossible to maintain a clean console when running the container.

How can I prevent these applications from polluting System.out and System.err?


Implementation notes:

  • the applications use Log4j for logging;
  • the container also uses the console for logging, but it is strictly reserved for lifecycle events and problems, so I still need the console;
  • the applications are loaded using a custom classloader, but no security checks are applied.

Update:

Simply redirecting System.out would not work since it redirects all output, so something like this fails:

    System.setOut(new PrintStream(new OutputStream() {

        @Override
        public void write(int b) {

            throw new Error("Not on my watch you don't");

        }
    }));

    Logger logger = Logger.getLogger(Runner.class);
    logger.info("My log message");

This should succeed.

Update 2:

The applications are loaded and configured using code similar to

App app = new UrlClassLoader(...).loadClass(className)).newInstance();
app.setLogger(loggerForClass(app));

Log4j is loaded from the system class loader.

12条回答
Juvenile、少年°
2楼-- · 2019-06-22 01:57

What I have done is redirect the PrintStream for System.out and System.err to commons-logging as INFO and ERROR level logging respectively.

This gets trickier if you want some threads to be able to write to the console or you want logs to go to the console as well but it can be done.

查看更多
趁早两清
3楼-- · 2019-06-22 01:59

We use the log4j trick but log to separate files (stdout.log, stderr.log). It's not useful to have their output mixed in with the parts that actually understand logging...

查看更多
小情绪 Triste *
4楼-- · 2019-06-22 02:00

You can actually get and store System.out/err before replacing them.

OutputStream out=System.getOut();  // I think the names are right
System.setOut(some predefined output stream, null won't work);
out.println("Hey, this still goes to the output");
System.out.println("Oh noes, this does not");

I've used this to intercept all the System.out.println's in the codebase and prefix each line of output with the method name/line number it came from.

查看更多
聊天终结者
5楼-- · 2019-06-22 02:01

Convert the System.out and System.err streams to special implementations that throw a RuntimeException("Use logging instead of System.out") every time a character is written.

If your container is important, they will get the idea pretty quickly :)

(For extra bonus throw OutOfMemoryException instead ;-))

查看更多
beautiful°
6楼-- · 2019-06-22 02:02

You can use System.setOut() and System.setErr() to redirect stdout and stderr to instances of PrintStream.

查看更多
▲ chillily
7楼-- · 2019-06-22 02:02

Use aversion therapy. A visit from "The Inspectors" is scheduled whenever any code is checked in containing unpleasant constructs.

Nice cubicle you got ere, be shame if anyfing appened to it.
查看更多
登录 后发表回答