1

I have an integration test (ClientIT) which uses the logging output from a test helper Class (ClientBasic) to determine whether the test passes or fails. I have re-directed the System.out/System.err inside the ClientBasic class to provide a link back to ClientIT using an OutputStream as follows,

System.setOut(new PrintStream(ClientBasic.out));
System.setErr(new PrintStream(ClientBasic.err));

where,

static OutputStream out;
static OutputStream err;

In ClientIT I call Client basic as follows,

ClientBasic.process(clientArgs.getArguments(), out, err);

This works fine, exactly how I wanted except when I run it using the Maven Failsafe plugins as part of the Package/Verify goal I get the message,

[WARNING] Corrupted STDOUT by directly writing to native stream in forked JVM 1. See FAQ web page and the dump file /path-to-project/target/failsafe-reports/2019-07-17T13-33-44_769-jvmRun1.dumpstream

which has the effect of really corrupting the display output of any logging info when the ClientBasic runs as part of my integration test - run locally from the command line or in Jenkins (using mvn ...) - strangely it still works fine when I run it from inside the IDE - maybe its not calling the failsafe plug-in directly ?

Anyway the above effect is documented on the Maven site as Corrupted STDOUT

So to try and get around this problem what I would like to do is to simply hook onto the System.out/err stream and create a copy - i.e. a bit like a splitter, rather than re-directing the System.out stream.

Does anyone now if this is possible and if so how to do this ?

robbie70
  • 1,515
  • 4
  • 21
  • 30
  • 1
    So you're using `System.out/err` for logging? How about using proper logging? – daniu Jul 17 '19 at 12:55
  • Instead of messing with the system standard output, your process should write directly into the `out` and `err` streams passed as arguments. This way, you can create new, independent print streams before each test, ensuring that they won't be altered unexpectedly. `System.out` and `System.err` should be avoided at all cost within your code. Regardless, are the `out` and `err` arguments a core part of the process, or just for logging purpose? If it's the latter, get rid of them and use a logging framework like SLF4J, and test the process checking its actual result instead of the logs. – Luis Iñesta Jul 17 '19 at 14:16
  • @daniu, Luis Inesta thank you for your suggestions. There is already quite a bit of System.out in the code which I could replace with a Logger as you both suggest... but if I am not mistaken the logger sends the output to a file rather than the console / std out or err.... do you have any examples or a link that could help ? PS In the past I have struggled to get Log4j working as documented so a little hesitant to go down that route if there is any easier alternative. – robbie70 Jul 17 '19 at 21:58
  • You can configure logging to go to a file, the console, or both. The easiest to adopt is probably `java.util.logging`, but also the one with most downsides. It's still better than printing to `System.out/err`. – daniu Jul 18 '19 at 06:44
  • I have tried to implement the functionality as you suggested using the SimpleLogger (because that is what is being used in the System) but I am stuck now how to retrieve the values from the logger. I have raised a separate SO question for this incase you have some idea about it, https://stackoverflow.com/questions/57099974/simplelogger-sl4fj-how-to-retrieve-the-log-content – robbie70 Jul 18 '19 at 18:25

1 Answers1

0

As the error does not immediately blame setOut/setErr, it should be possible to make ones own splitter extending PrintStream.

public class Splitter extends PrintStream {
    public Splitter(PrintStream sysPS, PrintWriter myOut) { ... }
    ... override methods by code generation in IDE.
}

PrintStream myOut = ...;
Splitter outSplitter = new Splitter(System.out, myOut);
Splitter errSplitter = new Splitter(System.err, myOut);
System.setOut(outSplitter);
System.setErr(errSplitter);
...
// At end:
System.setOut(outSplitter.getSysPS());
System.setErr(errSplitter.getSysPS());

IDE code generation and a couple of smart regex replaces will give you a correct class.


Alternatively there probably exists such a splitter as a Logger.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138