简体   繁体   中英

How to sniff which Java class (library) is writing to System.out?

The problem is either tricky or simple (not sure yet):

The project that I'm currently involved with has a bit too many logging libraries. We have log4j, sl4j, logback and who knows what else...

One of these is logging something to System.out and I've run out of ideas on how to find out which one and when...

I'm thinking about something like "putting a breakpoint" on sysout but I don't know if that's even something possible.

Any ideas?

You can redirect System.out to a custom PrintStream that throws an error or logs it in a file. You'll have to manually go through the stacktrace and look for the offending method.

To create it:

PrintWriter pw = ...;
PrintStream ps = new PrintStream(System.out) {
  public void write(int b) {
    super.write(b);
    /*try { throw new Error(); } 
    catch (Error e) { e.printStackTrace(pw); }*/

    //Edit: Jeff Wang's answer is a better approach since it doesn't
    // throw an exception and just prints the stacktrace
    new Exception().printStackTrace(pw);

    //You could also write to stderr
    Thread.dumpStack();
  }
};

To change System.out :

System.setOut(ps);

If you set this at the start of your program, this'll throw an error whenever a library prints to System.out , catch it, and write to a file (or somewhere else). You can always format it better if you want.

This isn't a great solution beyond testing, because it involves throwing an exception every time you write a single byte (you could override the other write method if you wish, though) and because you need to manually go through the stacktraces. In production, you'd want something else.

Edit: Throwing an exception is unnecessary. You can do Thread.dumpStack or new Exception().printStackTrace , as the other answer by Jeff Wang suggested.

I've used this before on err, to see the actual root cause (instead of the...and more)

    PrintStream o = new PrintStream(new File("A.txt")) { 
        public void write(byte[] b) throws IOException {
              super.write(b);
              IOException ie = new IOException();
              ie.printStackTrace(); //don't throw this!
        }
    };

and set it like user mentioned above. It's a different method then the one he used, I'm not too sure what the difference is, I just remembered that it worked.

There are a few options:

  1. Step through your code with a debugger, as @hev1 suggested. You should be able to set a break-point right on System.out.println() (though remember there are other methods you may need to add breakpoints to as well). Especially for a test this is likely the easiest and least-invasive approach.

  2. Instrument System.out by pointing it to a custom PrintStream implementation via System.setOut() that's implemented however you see fit, as @user and @Jeff Wang suggested. You can throw an exception or log a stack trace to manually inspect the call stack, or do something more clever like inspecting the call stack at runtime.

    Note that, unlike the other answers, you'll want to capture a reference to the original value of System.out before replacing it. I think the "real" out/err instances will be lost forever if you don't:)

  3. You may be able to configure a SecurityManager to control stdout/stderr . I'm not yet sure whether this is possible out of the box, but presumably you could use System.setOut() as above to register a PrintStream that queries a SecurityManager . Basically this is just a more enterprise-scale version of #2. This is probably not necessary unless you intend to enforce who can write to stdout/stderr, but it's worth mentioning an option:)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM